在下面的代码中,我将一个字符串复制到一个char*str,它是10个字符长,使用strncpy().
现在根据strncpy()手册,"警告:如果src的前n个字节中没有空字节,则放置在dest中的字符串将不会以空值终止."这正是这里发生的事情.
源字符串是26个字符长,我复制了10个字符,因此在str的末尾没有放置空字符.
但是当我打印str的内容时,从0开始直到我得到'\ 0',它表现正常.
为什么?当末尾没有'\ 0'时,为什么循环停在正确的位置?
我的理解是它应该给出"分段错误",或者至少它不应该停在那里并继续打印一些垃圾值.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define SIZE 10
int main()
{
char *str ;
str = malloc( sizeof( char ) * SIZE );
if( str == NULL )
exit( 1 );
memset( str, 0, sizeof( char ) * SIZE );
strncpy( str, "abcdefghijklmnopqrstuvwxyz", sizeof( char ) * SIZE );
unsigned int index;
for( index = 0; str[ index ] != '\0' ; index++ ) {
printf( "str[ %u ] has got : %c \n ", index, str[ index ] );
}
return 0;
}
Run Code Online (Sandbox Code Playgroud)
这是输出:
str[ 0 ] has got : a str[ 1 ] has got : b str[ 2 ] has got : c str[ 3 ] has got : d str[ 4 ] has got : e str[ 5 ] has got : f str[ 6 ] has got : g str[ 7 ] has got : h str[ 8 ] has got : i str[ 9 ] has got : j
任何帮助将不胜感激.
编辑
有没有正确的方法来检查字符串是否以'\ 0'结尾?我一直认为上面的循环是最终的测试,但现在看来它不是.
让我们说我们从其他程序员开发的函数中得到一个字符串.现在我们怎么知道它以'\ 0'结束在正确的位置.可能它没有,那么它将超出实际大小,直到我们得到一些'\ 0'.我们永远无法知道字符串的实际大小.
那么我们如何解决这种情况呢?
有什么建议吗?
sha*_*oth 15
只是在分配块的末尾之外有一个空字节.
很可能malloc()分配更多内存并将所谓的保护值恰好包含空字节,或者放置一些元数据以供free()稍后使用,并且此元数据恰好在该位置包含空字节.
无论如何,你不应该依赖这种行为.您必须malloc()为空字符请求()一个字节,以便合法地为您分配空字符位置.
没有可移植的方法来测试字符串是否正确地终止.可能会发生这样的情况:一旦你超过分配块的结束,你的程序就会崩溃.或者可能发生在块的末尾之外的某处存在空字符,并且在操作错误解释的字符串时,您将在块之后覆盖内存.
理想情况下,您需要一些函数来检查给定地址是否分配给您并且属于与另一个给定地址相同的分配(可能是块的开始).这将是缓慢的,不值得,并没有标准的方法来做到这一点.
换句话说,如果你遇到一个字符串,这个字符串意味着空终止,但实际上并不是你搞砸了很多时间 - 你的程序将遇到未定义的行为.
至于你的编辑,我认为迂腐将有助于阐明一些问题.
在C中没有字符串这样的东西.有一个"C字符串"的概念是C标准库的工作原理,它被定义为NUL终止的字符序列,所以实际上没有"非空终止字符串"这样的东西"在C.所以你的问题更好地表达为"如何确定任意字符缓冲区是否是有效的C字符串?" 或"我如何确定我找到的字符串是否是预期的字符串"
不幸的是,第一个问题的答案是只是线性扫描缓冲区,直到你遇到NUL字节为止.这将为您提供C字符串的长度.
第二个问题没有简单的答案.由于C没有具有长度元数据的实际字符串类型(或者能够跨函数调用来携带数组的大小),因此没有真正的方法来确定我们在上面确定的字符串长度是否为预期的字符串.很明显,如果我们开始在程序中看到段错误或者在输出中看到"垃圾",但一般来说我们通过扫描直到第一个NUL字节(通常在字符串长度上有一个上限以避免混乱)来执行字符串操作缓冲区溢出错误)