0

我正在为即将到来的课程清理我的 C 技能,并且printf在使用getchar. 具体来说,我尝试输出的任何字符串都会在每个字母上附加相同的字符序列。foo变成"f?8@{?o?8@{?o?8@{?"cc, 和f¿:¿o¿:¿0¿:¿( Apple LLVM 5.0Xcode) 编译。以下是说明该问题的示例代码:

char * input_buffer = malloc( sizeof( char ) );

char c;
while ( ( c = getchar() ) != '\n' ) {
    strcat(input_buffer, &c);
}

// problem output
printf( "\n%s\n", input_buffer );
// foo -> f¿:¿o¿:¿0¿:¿

// weird side effect is the 4 is required to get a proper len
printf("\ncharacters: %lu\n", strlen( input_buffer ) / 4 );

我到处搜索,但在其他任何地方都没有看到这个,但这似乎有点像一个边缘案例。这是我没有考虑到的某种编码问题吗?

4

3 回答 3

3

你不能打电话strcat(input_buffer, &c);

传递给的每个参数都strcat必须是有效的以空字符结尾的字符串。

为 0之后的下一个字节的机会&c非常渺茫。

0指向的第一个字节的机会input_buffer也不是很高。

换句话说,strcat读取“垃圾”,直到在两个参数中都遇到 0 字符。

改变:

while ( ( c = getchar() ) != '\n' ) {
    strcat(input_buffer, &c);
}

至:

for (int i=0; 1; i++)
{
    c = getchar();
    if (c == '\r' || c == '\n')
    {
        input_buffer[i] = 0;
        break;
    }
    input_buffer[i] = c;
}
于 2014-01-18T20:15:10.757 回答
2
  • input_buffer只为一个分配空间char
  • strcat(input_buffer, &c);是错的。您正在用字符串连接字符(它不是以 null 结尾的)。
  • getchar返回inttype 但您声明c的是 type char
于 2014-01-18T20:13:39.797 回答
1
char * input_buffer = malloc( sizeof( char ) );

sizeof (char)根据定义为 1。这为单个字符分配空间,并input_buffer指向它。

您也没有检查分配是否成功。malloc失败时返回空指针;你应该经常检查。

并且指向的分配char对象包含垃圾。input_buffer

char c;
while ( ( c = getchar() ) != '\n' ) {
    strcat(input_buffer, &c);
}

getchar()返回一个int,而不是一个char。您可以将结果分配给char对象,但这样做会失去检测文件结尾或错误条件的能力。当没有更多字符要读取时getchar()返回;EOF您应该始终检查这一点,这样做需要将结果存储在int. (EOF是一个不等于任何有效字符的整数值。)

    strcat(input_buffer, &c);

input_buffer指向一个未初始化的char. 您可以将其视为由单个char元素组成的数组。的第一个参数strcat必须已经包含一个有效的以 null 结尾的字符串,并且它必须有足够的空间来容纳该字符串以及您要附加到它的任何内容。

c是单个对象,包含您刚刚使用strcat char* char*`char读取的任何字符,必须指向一个有效的以空字符结尾的字符串。getchar(). The second argument tois a, so you've got the right type -- but that

strcat将首先扫描指向的数组input_buffer以找到终止'\0'字符,以便它知道从哪里开始追加 - 它可能会扫描到不属于您声明或分配的任何对象的内存中,这可能会使您的程序崩溃。如果这没有爆炸,它将复制从 开始的字符c,并将其传递到您不拥有的内存中。您有多种形式的未定义行为。

您不需要使用strcat将单个字符附加到字符串;你可以分配它。

这是一个简单的例子:

char input_buffer[100];
int i = 0; /* index into input_buffer */
int c;
while ((c = getchar()) != '\n' && c != EOF) {
    input_buffer[i] = c;
    i ++;
}
input_buffer[i] = '\0'; /* ensure that it's properly null-terminated */

为了简单起见,我分配了一个固定大小的缓冲区而不是使用malloc

同样为简单起见,我省略了输入没有超过输入缓冲区末尾的任何检查。如果是这样,如果幸运的话,程序可能会崩溃;如果你不走运,它可能只是在破坏不属于你的记忆时起作用。如果输入行不太长,它会正常工作。在任何现实世界的程序中,您都需要检查这一点。

顺便说一句,这里所做的事情使用起来更容易fgets()——但最好在稍低的水平上了解事物的工作方式。

于 2014-01-18T21:03:01.030 回答