我正在尝试理解关于字符串'的基本内容。在c中定义。
char s[2];
scanf("%s", s);
printf("%s", s);
printf("sizeof s %d", sizeof(s));
我不是c程序员。我知道使用scanf来获取用户输入存在问题,而且我甚至没有检查其返回值等。这只是为了解一些关于声明字符串的基本知识。
鉴于以上代码,如果我输入“helloworld'印刷' helloworld'。好。但是我想通过说char [2]我说的是类似于长度为2的数组,其中每个元素都是char'。
因此我期待看到他'打印。不是' helloworld'。因为我的阵列只有2个字符的空间。
sizeof仍然返回2.但看起来我的数组已经增长到用户输入的大小。
发生了什么事?
答案 0 :(得分:4)
这显示了为什么scanf
如此危险的完美原因。您已经覆盖了其他不适用于此的内存。读取常量长度字符串的更安全的方法是执行类似这样的操作
char a[2];
fgets(a, sizeof(a), stdin);
printf("%s\n", a);
如果你这样做并且输入了helloworld
,那么你只能得到h
到stdout(因为字符串由于空终止符而有sizeof(a) - 1
个字符。这意味着数组{{1}实际上是a
)。 {'h', '\0'}
对于阅读常量大小的字符串比fgets
更安全。
答案 1 :(得分:3)
两个问题:
%s
转换规范告诉printf
打印从指定地址开始的字符的序列,直到它在字符串末尾看到0终结符。类似地,它告诉scanf
存储从指定地址开始的字符序列,直到它看到空白字符或EOF。
当您将表达式 s
作为参数传递给scanf
或printf
时,表达式将从类型" 2元素数组转换char
" to"指向char
"的指针,表达式的值是数组的第一个元素的地址(它相当于传递表达式&s[0]
) 。
所有scanf
接收都是指针值 - 它不知道从该地址开始的数组有多大。所以它不知道s
只有大到足以包含两个字符。相反,它愉快地将那些额外的字符写在数组的末尾。同样地,printf
不知道数组只有2个字符宽 - 它只是保持打印直到它看到0终止符。
您可以指定字段宽度作为转换的一部分:
scanf( "%1s", s );
这将从标准输入读取最多 1个字符并将其存储到s
。请记住,字符串是一个字符序列后跟一个0终结符,因此要存储一个N字符字符串,您需要预留一个N + 1元素数组来存储它。
答案 2 :(得分:0)
我认为还没有人真正回答过这个问题。这里有两个问题......
首先,阵列" s"只有2个字节长,因此超过1个字符的任何字符串的 scanf 将产生不希望的结果。
fgets(s, sizeof(s), stdin); // was scanf("%s", s);
另外,如前所述, scanf 是一种输入字符串的可怕方式。请改用 fgets 。
printf("strlen s %d", strlen(s)); // was printf("sizeof s %d", sizeof(s));
其次,您不能使用 sizeof 来获取字符串的长度。它会返回包含字符串的数组的长度(不是你想要的,相信我)。相反,请使用 strlen 。
protocol MyProtocol {}
struct MyAssociatedValue: MyProtocol {}
enum MyEnum {
case myCase(MyAssociatedValue)
}
func myEnumClosureMapping() -> (MyAssociatedValue) -> MyEnum {
return MyEnum.myCase
}