使用 sizeof 将字符追加到用户字符串的末尾

Using sizeof to append a character to the end of a string form user

我正在尝试使用以下代码将右括号附加到从用户那里获取的字符串的末尾

int main( void )
{
    char charArray[ 20 ];

    fgets( charArray, 20, stdin );

    charArray[ sizeof( charArray ) / sizeof( charArray[ 0 ] ) ] = ')';

    printf( "%s", charArray );
}

但是如果我输入:4+5 输出只是:4+5 而不是:4 +5)

我什至尝试了以下变体,以防万一

int main( void )
{
    char charArray[ 20 ];
    int n;

    fgets( charArray, 20, stdin );

    n = sizeof( charArray ) / sizeof( charArray[ 0 ] );

    charArray[ n ] = ')';

    printf( "%s", charArray );
}

但它不起作用。所以我通过

避免了对 sizeof 的需要
int main( void )
{
    char charArray[ 20 ];
    int i = 0;

    do{
        scanf( "%c", &charArray[ i ] );
        ++i;
    } while( charArray[ i - 1 ] != '\n' );

    charArray[ i - 1 ] = ')';

    printf( "%s", charArray );
}

但是我以后可能需要 sizeof 所以我想知道我做错了什么。此外,使用 fgets 和 sizeof 似乎比使用神秘的 [ i - 1 ] 下标的 scanf 和 do while 更直接和简洁。 请告诉我有关 sizeof 方法的信息:我的代码有什么问题?

表达式 sizeof(charArray) 是二十,并且与您存储在其中的字符串没有任何关系(除非该字符串大于二十个字节,当然)。

如果要获取字符串末尾[=12=]的索引,需要使用strlen而不是sizeof

例如,这里有一种安全的方法:

#include <stdio.h>
#include <string.h>

int main( void ) {
    // Allow extra space for ')' and use actual size for input.

    char charArray[21];
    if (fgets(charArray, sizeof(charArray) - 1, stdin) == NULL) {
        fprintf(stderr, "Some problem occurred on input\n");
        return 1;
    }

    // Ensure terminated with newline.

    size_t len = strlen(charArray);
    if (len < 1 || charArray[len - 1] != '\n') {
        fprintf(stderr, "Input is not terminated with newline\n");
        return 1;
    }

    // Just replace newline with ')' character.

    charArray[len - 1] = ')';
    printf("%s\n", charArray);
}

顺便说一句,如果您正在寻找标准 C 中的 bullet-proof 用户输入函数,建议您查看 this one。我已经使用它 很多 年了,没有任何问题。

你在这里做错的是不知道数组和字符串之间的区别。您已经声明了一个大小为 20 的数组。该大小永远不会改变。

你要找的是字符串的长度,用strlen(charArray)就可以得到。

字符串是以 [=17=] 字符结尾的可打印字符序列。字符串的长度是终止符之前的字符数。

此代码将打印 5, 20:

char arr[20] = "Hello";
printf("%zu, %zu\n", strlen(arr), sizeof(arr));

请注意,这将打印 3:

char arr[20] = "Hello";
printf("%zu\n", strlen(&arr[2]));

另请注意,您可以这样做:

char arr[20] = "Hello[=12=]World!\n";
printf("%zu, %zu\n", 
       strlen(&arr[0]), // Hello
       strlen(arr[strlen(&arr[0]) + 1]) // World!\n
);

这将打印 5, 7。第二个长度为七,因为换行符也很重要。另请注意,当您初始化数组时,总是附加 '[=21=]' ,除非数组的大小太小。这将声明一个没有终止符的字符串:

char no_terminator[5] = "Hello";

避免这种情况。它可能会给你带来很多问题。

所以在你的情况下,你可以这样做:

fgets( charArray, 20, stdin );

// Standard way of removing newline from a string. It's a very useful
// trick since fgets saves the newline in the string.
charArray[strcspn(charArray, "\n")] = '[=14=]';

size_t len = strlen(charArray);
charArray[len] = ')';
charArray[len+1] = '[=14=]';

但要小心,不要让 len+1 超过 20。如果超过,则您正在调用未定义的行为,调试起来会很麻烦。此外,检查 fgets 是否返回 NULL 是明智的。如果是这样,你应该处理这个错误。

如果你经常处理这种输入,我可以推荐这个包装器:

void my_readline(char *str, int n)
{
    if(fgets(str, n, stdin) == NULL) {
        perror("Error reading string");
        exit(EXIT_FAILURE);
    }
    str[strcspn(charArray, "\n")] = '[=15=]';
}

当然,您可以按照您想要的任何方式自定义错误处理。

首先,char的大小总是1,在规范中定义。

其次,数组的大小是数组本身的大小,以“字节”为单位。

也就是说

sizeof( charArray ) / sizeof( charArray[ 0 ] )

等于

20 / 1

等于20.

也就是说,您将总是写入数组的twenty-first元素,这超出了范围并导致未定义的行为。

如果您想将字符附加到字符串,请使用 strcat 将字符作为字符串附加(确保您没有写出越界):

// Check to make sure there's space in the array, the -1 is for the terminator
if (strlen(charArray) < (sizeof charArray - 1))
{
    strcat(charArray, ")");
}

或者使用 strlen 获取字符串 null-terminator 的位置并用你的字符覆盖它(但记得添加一个新的 null-terminator,并检查你不不要出界):

// Get the index of the current null-terminator in the string
size_t terminator_index = strlen(charArray);

// Check to make sure there's space in the array, the -1 is for the terminator
if (terminator_index < (sizeof charArray - 1))
{
    // Can append new character
    charArray[terminator_index] = ')';

    // Add terminator
    charArray[terminator_index + 1] = '[=13=]';
}

sizeof( char ) 始终等于 1。所以这个表达式

sizeof( charArray ) / sizeof( charArray[ 0 ] )

等同于表达式

sizeof( charArray )

因为 sizeof( charArray[ 0 ] )sizeof( char ) 因此它产生整个数组大小的值,在这个声明的情况下

char charArray[ 20 ];

等于20.

表示例如这个语句

charArray[ sizeof( charArray ) / sizeof( charArray[ 0 ] ) ] = ')';

尝试写入数组外的内存。

如果用户输入的字符串小于指定的字符数组大小,函数 fgets 将附加换行符 '\n'

所以你需要用换行符代替字符 ')'.

您可以通过以下方式使用标准 C 函数 strcspn 轻松完成此操作

size_t n = strcspn( charArray, "\n" );
if ( n + 1 < sizeof( charArray ) ) charArray[n] = ')';

在 if 语句的条件中使用表达式 n + 1 来考虑数组不包含换行符 '\n' 的情况(用户输入的字符多于指定尺寸)。在这种情况下,n 将产生小于数组大小的终止零字符 '\0' 的位置。

但我们不能用它代替字符 ')',否则数组将不包含字符串。所以这个条件 n + 1 < sizeof( charArray ) 保证字符串包含换行符 '\n'.