C字符串的行为很奇怪
第一个问题是关于字符串末尾的空字符C字符串的行为很奇怪,c,arrays,string,C,Arrays,String,第一个问题是关于字符串末尾的空字符\0,在需要/自动添加\0的时间方面有很多变化。 声明字符数组时,是否需要指定\0或否?或者在什么情况下,我应该指定\0,而在什么情况下不指定?有人能给出一个全面的总结吗?(如中所示)。如果您觉得我的问题模棱两可,那么更具体的一个问题是,在C中声明字符串时,最好的方法是什么,是char string[]=“first string”,因为例如,通过这种方法,我可以在不考虑大小问题的情况下执行strcat(string,另一个字符串) 第二个问题:我有 1 c
\0
,在需要/自动添加\0
的时间方面有很多变化。
声明字符数组时,是否需要指定\0
或否?或者在什么情况下,我应该指定\0
,而在什么情况下不指定?有人能给出一个全面的总结吗?(如中所示)。如果您觉得我的问题模棱两可,那么更具体的一个问题是,在C中声明字符串时,最好的方法是什么,是char string[]=“first string”
,因为例如,通过这种方法,我可以在不考虑大小问题的情况下执行strcat(string,另一个字符串)
第二个问题:我有
1 char a[] = "kenny";
2 char b[3];
3 strncpy(b, a, (int)(sizeof(b) - 1));
4 printf("%i\n", (int)sizeof(b)); // 3
5 printf("string length: %i\n", (int)strlen(b)); // string length: 8
6 printf("%s\n", b); // give me random stuff like kekenny or keEkenny
- 3:我只想将2个字节传递给b
- 4:
行为正常sizeof
- 5:但是为什么会变成8
- 6:为什么它会给我一些随机的东西,比如kekenny或keEkenny
我刚刚弄丢了C字符串中发生的事情。我过去经常使用C++,但仍然不理解C字符串是如何运行的。 < p>你必须以某种方式将字符串终止符0添加到B中。printf(“%s\n”,b)将在找到\0时停止
这取决于内存中的内容,有时可能会出现seg故障 如果您阅读了
strncpy
的文档,它非常清楚地指出,如果您指定的大小不包括NUL终止符,它将不会添加NUL终止符:
strncpy()函数与之类似,不同的是src的最大字节数为n
抄袭的。警告:如果src的前n个字节中没有空字节,
放置在dest中的字符串不会以null结尾
所以在下面的例子中,您只复制了2个字符,它们都不是NUL终止符,所以您需要自己添加它
strncpy(b, a, (int)(sizeof(b) - 1));
根据定义,在声明中:
char string[] = "first string"
strcat(string, anythingElse);
字符串
精确填充了它所能容纳的所有内容:
在内存中,它看起来是这样的:
|f|i|r|s|t| |s|t|r|i|n|g|\0|?|?|?|
/// end of legal memory ^
…说明为什么会有以下声明:
char string[] = "first string"
strcat(string, anythingElse);
是。(有些人称之为。)
另外,关于用法。由于不能保证在使用后包含nul
字符,建议始终将nul
显式附加到新字符串中的正确位置:
strncpy (target, source, n);
target[n] = 0;
在您的示例中,n
=(sizeof(b)-1)
注意:当将sizeof
用作strncpy(,*)
的第三个参数的类型时,上述表达式中不需要对(int)
进行强制转换:
char *strncpy (char Target_String[], const char Source_String[], size_t Max_Chars);
另一方面,的用法是将
nul
字符附加到结果目标字符串的末尾,从而消除了显式附加nul
的需要。关于C字符串的一点是,它们的级别非常低,需要记住许多额外的事情,有时还需要“手动”执行
(相比之下,C++std::字符串几乎是完全正常的高级类型。)
在回答您的具体问题时:
您几乎不需要显式地提供\0
。你唯一能做的就是完全用手构建一个字符串。例如,此代码可以工作:
char str[10];
str[0] = 'c';
str[1] = 'a';
str[2] = 't';
str[3] = '\0';
printf("%s\n", str);
但是如果您省略了对str[3]
的显式赋值,它的行为将不稳定。(但如果你不这样手工创建字符串,你就不必太担心了。)
使用strcpy
复制字符串时必须非常小心。您必须确保目标字符串(“缓冲区”)足够大。C语言中的任何东西都无法为您解决这个问题——没有任何东西可以确保目的地足够大;如果它不够大,就不会有任何警告。但如果它不够大,最奇怪的事情可能会发生——包括它似乎起作用,尽管它不应该起作用。(其正式名称为“未定义行为”。)
特别是,如果你写
char string[] = "first string";
strcat(string, another_string);
你得到的是一个bug,纯粹而简单。这不是真的“这样你就不用担心尺寸问题”。当您说char string[]=“…”
时,编译器会将字符串的大小调整到足以容纳初始值设定项(及其\0
),在本例中,“第一个字符串”
为13个字节。[]
并不意味着“让这个字符串足够大,可以容纳我要塞进的任何文本”
使用
strncpy
时必须更加小心。事实上,我的建议是根本不要使用strncpy
。它的实际功能是不寻常的、特殊的、难以解释的,而且通常不是你想要的。(首先,如果您让它复制的字符串少于一个完整字符串,它不会向目标添加一个“\0”,这有助于解释为什么会出现“kekenny”这样的情况)。第一个问题
当你这样做的时候
char string[] = "first string";
^
No size specified
编译器将保留可以精确保存文本“第一个字符串”和NUL终止的内存。如果打印字符串的大小,将得到13。换句话说-变量可以而不是保存更多的数据,因此连接另一个字符串是没有意义的
你可以做:
char string[100] = "first string";
然后可以连接另一个字符串
第二个问题
首先要知道的是C中的字符串是包含NUL终止的字符数组
当您这样做时:
char b[3];
strncpy(b, a, (int)(sizeof(b) - 1));
printf("string length: %i\n", (int)strlen(b));
printf("%s\n", b);
您将得到一个未初始化的数组,即b
可以包含任何内容,如b={?,?,?}
然后你会:
char b[3];
strncpy(b, a, (int)(sizeof(b) - 1));
printf("string length: %i\n", (int)strlen(b));
printf("%s\n", b);
这意味着您将前两个字符从a
复制到b
现在我们知道b
是b={'k','e',?}
注意b
的第三个字符仍然没有初始化
所以当你这样做的时候:
char b[3];
strncpy(b, a, (int)(sizeof(b) - 1));
printf("string length: %i\n", (int)strlen(b));
printf("%s\n", b);
您使用b
就像它是一个字符串,但它不是。没有NUL终止。因此,函数(printf
,strlen
)给出的结果不正确。使用字符数组调用这些函数,而不使用