5 回答
我知道我可以使用
gets()
,除非它显然很糟糕,我不应该使用它。
确切地说,确切地说,它很容易出现缓冲区溢出错误。并且scanf()
同样邪恶(部分原因是相同的 - 指定缓冲区长度并非易事,而且无论如何,它比必要的复杂得多,很难做到正确,而且对于简单的原始 I/O 来说过于昂贵),不要也不要使用它。用于fgets()
获取用户输入,它通过让您将要写入的缓冲区的长度传递给它,从而避免您被击中脚:
char buf[0x40];
fgets(buf, sizeof(buf), stdin);
既然您知道“如何”,我将向您解释“为什么”。
数组,当传递给函数时,据说会衰减为指针。如果将 a 传递char []
给函数,它会将 a 视为char *
指向数组的第一个元素。这就是为什么您不必&
为 (char) 数组(在概念上是 C 中的字符串)显式使用“addressof”()运算符。
如果你使用它,你得到的不是指向数组第一个元素的指针,而是指向数组本身的指针,这不是你想要的。
(一般来说,它可以工作,就像它显然对你所做的那样,但理论上它会调用未定义的行为,因为传入的表达式的实际类型和%s
转换说明符所期望的类型不匹配。)
本文档是有关数组和指针的好读物,请务必阅读并理解它。
您正在使用数组。不要使用&
whilescanf
输入到数组
例如:scanf("%s",first);
数组已经通过引用传递。您不需要将&
数组作为指向 C 中第一个元素的指针传递
尝试更改scanf("%s",&first);
为scanf("%s",first);
(以及 的相似性last
)。
在正常情况下(包括这些),数组的名称计算为数组中第一个元素的地址。在这种情况下,这是一个指向 char 的指针,这是转换所scanf
期望的类型%s
。
以&
on 开头,您将获得相同的指针值(即相同的地址),但作为指向数组的指针而不是指向数组元素的指针。由于这与 预期的类型不匹配%s
,因此结果是未定义的行为(尽管由于它是正确的地址,这通常适用于大多数典型的编译器/CPU)。
从scanf
语句中删除 &。
scanf("%s", first); // first is pointer to start of first
scanf("%s", last); // last is pointer to start of last
在 C 中,数组的名称是指向数组开头的指针。
格式参数后scanf
需要指针参数或参数。
scanf( "%s", first );
scanf format-arg input-args
例如,如果将整数参数用于scanf
,则需要 &(获取地址)运算符。
int n;
scanf("%d", &n); // &n is pointer to n
scanf 需要一个地址,但是 char 数组 [] 已经是一个地址,而 scanf 不需要参考符号 & 因为名称本身就是一个地址