【问题标题】:Random character strange defined behavior随机字符奇怪的定义行为
【发布时间】:2017-12-29 11:45:48
【问题描述】:

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

为什么会这样?

【问题讨论】:

  • name 不是0-在游戏开始前被输出,然后被视为 C 字符串:臭名昭著的未定义行为再次发生。
  • 我打赌你之前有其他语言的经验。 C 字符串很奇怪——但可以预测。 string += 'x' 不会像你想的那样做。
  • @alk 比赛开始前不是0-out是什么意思?
  • @usr2564301 你是对的,这种方式效果更好,但仍然会打印一些未定义的字符
  • 因为它并没有像你想象的那样做......在你最喜欢的 C 手册中查找“字符串”。

标签: c arrays string c-strings srand


【解决方案1】:

您正在打印垃圾值。行为将是什么是未知的。(未定义的行为)我的意思是,这些垃圾值(与您的随机数一起添加)可能是某些字符的 ascii 值,或者可能是一些不可打印的.您应该初始化 char 数组(使用\0's - 这将有两个目的,为正在运行的字符串提供\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 终止字符。

【讨论】:

    【解决方案2】:

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

    在 C 中,字符串是 always 携带(至少)一个 '\0' 字符来标记字符串的结尾。 printf(),大部分 str*() 函数和许多其他函数都依赖于这个终止 '\0'

    另外,添加到数组元素背后的想法是什么?

      name[i] += ... 
    

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

    所以要修复您的代码,请手动添加终止符:

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

    或者在开始之前采用惰性方法将name 初始化为所有'\0'

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

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

    any 的情况下,不要循环直到数组最后一个元素(此处为 100),但总是少一个,因为最后一个元素是为终止 '\0' 保留的。

    【讨论】:

    • 谢谢你的解决方案确实是对的,我投票给另一个只是因为他之前回答过
    【解决方案3】:

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

    所以当你在做的时候

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

    你确实在做

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

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 1970-01-01
      • 2012-05-28
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 2017-03-29
      • 2018-05-27
      • 1970-01-01
      相关资源
      最近更新 更多