我正在为即将到来的课程消除我的C技能,在使用printf
构建字符串后,我使用getchar
遇到了这个奇怪的输出。具体来说,我尝试输出的任何字符串都会获得与每个字母相同的字符序列。 foo
变为"f?8@{?o?8@{?o?8@{?"
与cc
进行编译,f¿:¿o¿:¿0¿:¿
与Apple LLVM 5.0
进行编译(Xcode)。以下是说明问题的示例代码:
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 );
我到处搜索,但我在其他任何地方都没有看到这个,但这看起来有点像边缘情况。这是一种我没有考虑的编码问题吗?
答案 0 :(得分:3)
您无法拨打strcat(input_buffer, &c);
。
传递给strcat
的每个参数必须是有效的以空字符结尾的字符串。
&c
为0后的下一个字节的可能性非常小。
input_buffer
指向的第一个字节为0的可能性也不是很高。
换句话说,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;
}
答案 1 :(得分:2)
input_buffer
分配空间char
。 strcat(input_buffer, &c);
错了。您使用字符串连接字符(它不是以空值终止)。 getchar
会返回int
类型,但您宣布c
的类型为char
。答案 2 :(得分: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
的第一个参数必须已经包含一个有效的以空字符结尾的字符串,并且它必须有足够的空间来容纳该字符串以及您要附加的字符串。
c
是一个char
对象,包含您刚刚阅读的任何字符getchar(). The second argument to
strcat is a
char * , so you've got the right type -- but that
char *`必须指向有效的以null结尾的字符串。
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()
可以更轻松地完成这里所做的事情 - 但是了解事情如何在稍低的水平上运作是很好的。