随机字符奇怪的定义行为

问题描述 投票:0回答:3

我在这段代码中使用了一个数组,因为我需要一个应该总是被修改的字符串,这就是我不使用指针的原因,每次运行代码时我都会在第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�
/////

为什么会这样?

c arrays string c-strings srand
3个回答
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;
}

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


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),但总是少一个,因为最后一个元素是为终止'\0'保留的。


0
投票

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

所以当你这样做的时候

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

你其实在做

name[i] = RANDOM JUNK + (char)'A'+(rand()%26);
© www.soinside.com 2019 - 2024. All rights reserved.