如果错误的话,我定义了一个没有'\ 0'作为最后一个字符的char数组,那么会发生什么? 我问这个是因为我注意到如果我尝试迭代数组而(cnt!='\ 0'),其中cnt是一个int变量,用作数组的索引,同时打印cnt值来监视迭代停止在最后一个字符+ 2处发生了什么。额外的字符当然是随机的但我无法理解为什么它必须在2之后停止。编译器是否自动插入'\ 0'字符?相关文档的链接将不胜感激。
为了说清楚我给出了一个例子。让我们说数组“str”包含单词doh(没有'\ 0')。在每个循环打印cnt变量会给我这个 卫生署+ 或者doh ^ 等等。
答案 0 :(得分:5)
编辑(未定义的行为)
访问数组边界之外的数组元素是未定义的行为 使用除C字符串之外的任何内容调用字符串函数是未定义的行为 不要这样做!
C字符串是由终止的字节序列,包括 a '\0'
(NUL终结符)。所有字节必须属于同一个对象。
无论如何,你看到的是巧合!
但它可能会像这样发生
,------------------ garbage | ,---------------- str[cnt] (when cnt == 4, no bounds-checking) memory ----> [...|d|o|h|*|0|0|0|4|...] | | \_____/ -------- cnt (big-endian, properly 4-byte aligned) \___/ ------------------ str
答案 1 :(得分:4)
如果你定义一个没有终止\0
的char数组(称为“null终止符”),那么你的字符串就不会有那个终止符。你会这样做:
char strings[] = {'h', 'e', 'l', 'l', 'o'};
在这种情况下,编译器永远不会自动插入空终止符。你的代码在“+2”之后停止的事实是巧合;它可以很容易地停在+50或其他任何地方,这取决于你的字符串后面的内存中是否有\ 0字符。
如果您将字符串定义为:
char strings[] = "hello";
然后那将确实是空终止的。当你在C中使用这样的引号时,即使你在文本编辑器中无法实际看到它,在字符串的末尾也有一个空终止符。
有一些C字符串相关的函数会自动附加一个空终止符。这不是编译器所做的事情,而是函数规范本身的一部分。例如,strncat()将一个字符串连接到另一个字符串,将在末尾添加空终止符。
但是,如果您使用的其中一个字符串还没有该终结符,那么该函数将不知道该字符串的结束位置,并且您将最终得到垃圾值(或分段错误。)
答案 2 :(得分:3)
如果巧合的是,*(str + 5)
处的字节为0
(作为数字,而不是ASCII)
答案 3 :(得分:3)
就大多数字符串处理函数而言,字符串总是停在'\0'
个字符处。如果你错过了这个null终结符,通常会发生以下三种情况之一:
您的程序将继续读取字符串的结尾,直到找到恰好在那里的'\0'
。有这样一个字符的方法有几种,但它们通常都不能预先预测:它可能是另一个变量的一部分,可执行代码的一部分,甚至是之前存储在同一缓冲区中的较大字符串的一部分。当然,到了发生的时候,程序可能已经处理了大量的垃圾。如果您看到printf()
产生大量垃圾,则未终止的字符串是常见原因。
您的程序将继续读取字符串的结尾,直到它尝试读取其地址空间之外的地址,从而导致内存错误(例如Linux系统中可怕的“分段错误”)。
复制字符串时,程序将耗尽空间,并再次导致内存错误。
而且,不,除了你在程序中指定的内容之外,C编译器通常不会执行任何操作 - 例如,它不会自行终止字符串。这就是使C如此强大而且难以编码的原因。
答案 4 :(得分:3)
在C语言中,术语 string 是指零终止字符数组。所以,迂腐地说,没有“没有'\ 0'字符的字符串”这样的东西。如果它不是以零结尾,则它不是字符串。
现在,只要你知道它不是一个字符串,拥有一个没有任何零的字符数组是没有错的。如果您尝试使用此类字符数组,就好像它是一个字符串一样,程序的行为是 undefined 。任何事情都可能发生。由于一些神奇的原因,它似乎“起作用”。或者它可能会一直崩溃。这样的程序实际上会做什么并不重要,因为如果行为未定义,程序就没用了。
答案 5 :(得分:0)
我敢打赌,在你的字符串之后定义了一个int,并且这个int只取小值,这样至少有一个字节是0。