随机字符奇怪的定义行为

时间:2017-12-29 11:45:48

标签: c arrays string c-strings srand

我在这段代码中使用了一个数组,因为我需要一个应该总是被修改的字符串,这就是为什么我没有使用指针,每次运行代码我都会得到一个在第31次迭代中的奇怪行为。

代码

int i = 0;
char name[100];
srand(getpid());


while(i<100) {

    name[i] += (char)'A'+(rand()%26);
    printf("%d strlen\n", i+1);
    printf("%s\n", name);
    printf("/////\n");
    i++;    
}

输出

/////
30 strlen
IKXVKZOLKHLTKBFFTUZCYXHYVEBZOY
/////
31 strlen
IKXVKZOLKHLTKBFFTUZCYXHYVEBZOYJ
/////
32 strlen
IKXVKZOLKHLTKBFFTUZCYXHYVEBZOYJWttime
/////
33 strlen
IKXVKZOLKHLTKBFFTUZCYXHYVEBZOYJW�time
/////
34 strlen
IKXVKZOLKHLTKBFFTUZCYXHYVEBZOYJW��ime
/////
35 strlen
IKXVKZOLKHLTKBFFTUZCYXHYVEBZOYJW���me
/////
36 strlen
IKXVKZOLKHLTKBFFTUZCYXHYVEBZOYJW����e
/////
37 strlen
IKXVKZOLKHLTKBFFTUZCYXHYVEBZOYJW�����

换句话说,它总是打印ttime作为第31个字符,然后代码覆盖该单词的每个字符,结果我得到问号。

继续观察最终输出的情况会更糟糕

100 strlen
IKXVKZOLKHLTKBFFTUZCYXHYVEBZOYJW�����K��ȶ������MKRLHALEV�SNNRVWNOEXUVQNJUHAEWN�W�YPMCW�N�PXHNT��0�
/////

为什么会这样?

3 个答案:

答案 0 :(得分:1)

嗯,你正在打印垃圾值。行为将是未知的。(未定义的行为)我的意思是,可能是这些垃圾值(随随机数添加)可能是某些字符的ascii值或者可能是某些非printables的情况。你应该初始化char数组(使用\0' - 这将有两个目的,为正在运行的字符串提供\0,你也可以添加并确保它是可打印的)或只需分配

name[i] = 'A'+(rand()%26);

还在字符串的末尾添加\0。否则它将尝试访问数组索引超出绑定,直到找到\0并且它将调用未定义的行为。

31不是特别的东西 - 下次你运行时它可以是任何东西。

代码:

#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
int main(void) {
    size_t i = 0;
    char name[100]={0}; // = "";
    srand(getpid());

    while(i<99) { // till 99 making sure you won't overwrite the last NUL

        name[i] ='A'+(rand()%26);
        printf("%d strlen\n", i+1);
        printf("%s\n", name);
        printf("/////\n");
        i++;    
    }
    return 0;
}

请注意,我们已经循环到98索引,因为99索引中存在NUL终止字符。

答案 1 :(得分:1)

默认情况下,

char name[100];不是字符串。它只是另一个100元素char数组。

在C中,字符串是 始终 ,其中包含(至少)一个'\0'字符以标记字符串的结尾。 printf(),大多数str*()个函数和许多其他函数都依赖于此终止'\0'

添加数组元素背后的想法是什么?

  name[i] += ... 

他们的价值没有设定,他们是垃圾。甚至值得,添加它们意味着读取未初始化的内存1,这反过来引发未定义的行为。

因此,要修复代码,请手动添加终结符:

while (i < 99) {
  name[i] = (char) 'A' + (rand() % 26);
  name[i + 1] = '\0';

或者在开始之前对所有name初始化'\0'进行懒惰处理:

char name[100] = ""; /* or ... = {0}; */

(这可以让你坚持做name[i] += ...。但是,由于所有元素都是0,添加是没有用的。)

任何 的情况下,不要循环直到数组的最后一个元素(此处为100),但总是少一个作为最后一个元素保留用于终止{{1} }。

答案 2 :(得分:0)

如果char name[100]数组是函数内的局部变量,则其初始值未定义。所以它将包含之前在那块内存中的随机垃圾。

因此当你做

name[i] += (char)'A'+(rand()%26);

你实际上在做什么

name[i] = RANDOM JUNK + (char)'A'+(rand()%26);