【问题标题】:Bizarre behavior with 2D Char array in CC中2D Char数组的奇怪行为
【发布时间】:2019-10-04 02:57:15
【问题描述】:

我在这段代码中遇到了一些我无法理解的奇怪行为:

char strings[5][4];

for (int i = 0; i < 5; ++i) {
    scanf("%s", strings[i]);
}
for (int i = 0; i < 5; ++i) {
    printf("%s\n", strings[i]);
}

如果我输入 5 个字符串,例如:

this
is
a
test
help

我在第二个 for 循环中得到了这样的结果:

thisis
is
a
testhelp
help

知道发生了什么吗?快把我逼疯了

【问题讨论】:

  • 对不起,我没提:数组的结构是这样的:char strings[5][4];
  • 字符串太短,无法正确写入空字符。
  • 我不明白你在说什么?如果我完全填写每个字符串,它们的行为会更加奇怪,例如,如果我给它 ["test", "fake", "core", "bird", "town"] 它会给我 ["testfakecorebirdtown", " fakecorebirdtown”, “corebirdtown” “corebird”, “城镇”]
  • 需要是字符串[5][5],因为您还需要保存空字符。 C 在遇到空字符时终止字符串。
  • scanf 允许限制字符串中的最大字符数 %4s 将适合 char[5]

标签: c


【解决方案1】:

所以 char 数组的工作方式是分配指定数组中的每个字符;但是,最后一个字符是分隔“字符串”的空字符:

char str[4] = {'n','o','t','\0'};
char str[4] = {'t','h','i','s'};

因此,如果您添加的大小比它的大小多一个,因为它实际上节省了空间,并且您的 scanf 工作正常。因此解决方案是,如果缓冲区是设定的大小,则将缓冲区增大一号,或者读取字符串,然后手动添加空字符

【讨论】:

    【解决方案2】:

    问题实际上在于您定义的字符数组。

    char strings[5][4]
    

    程序分配“字符串”20 个“字符”大小的内存块。

    假设起始地址是 0x00 所以从 0x00 到 0x20 的内存块(为了便于理解用十进制提到)分配给“字符串”

    这意味着字符串[0]指向0x00

    这意味着字符串[1]指向0x04

    这意味着字符串[2]指向0x08

    这意味着字符串[3] 指向 0x12

    这意味着字符串[4] 指向 0x16

    现在在“scanf”中基本上是读取每个字符直到 endline 并将其存储在相应的内存块中

    for (int i = 0; i < 5; ++i) {
        scanf("%s", strings[i]);
    }
    

    所以从您的问题来看,“this”存储在 4 个字符串块 [0] 中,并且没有用于结束行字符的空间 "is" 占用字符串[1] 中的 3 个字符,第三个是结束符。

    现在来到数组的 printf 函数。它将数组视为指针并迭代直到找到 endline 语句。

    for (int i = 0; i < 5; ++i) {
        printf("%s\n", strings[i]);
    }
    

    对于字符串[0],printf 函数获取指针 0x00 和 iteartes,直到找到结束行字符(即在 0x06)

    所以“thisis”被打印出来 对于 string[1] ,指针位于 0x04 处,因此打印“is”。

    现在,如果您输入的 sizw 字符串大于 4,您可以观察到该字符串溢出到下一个字符串

    for (int i = 0; i < 1; ++i) {
                    scanf("%s", strings[i]);
                }
        
    for (int i = 0; i < 2; ++i) {
                    printf("%s\n", strings[i]);
                }
    
    
    **INPUT:**
            thisab
    
        
    

    在上面的代码中,只有 strings[0] 被赋值为“thisab” 但它 printf 产生

    **OUTPUT:**
                    thisab
                    ab
    

    为避免此类问题,请使用字符串或将每行的大小定义为等于 (max_input_size+1)

    【讨论】:

      【解决方案3】:

      您的字符串的输入大小错误。

      C 中的字符串是以零结尾的,这意味着它们将包含所需的内容加上一个结尾的零字符(以便大多数函数能够理解您的字符串在哪里结束)。

      您的数组将连续分配到堆栈上,这意味着在您的第一次循环之前,您的内存将如下所示:

      000011112222333344445555
      

      内容是任意的,但为了便于理解,您的数组应如下所示

      1. [[0,0,0,0],[1,1,1,1],[2,2,2,2],[3,3,3,3],[4,4,4,4],[5,5,5,5]]
      2. [['t','h','i','s'],['\0',1,1,1],[2,2,2,2],[3,3,3,3],[4,4,4,4],[5,5,5,5]]
      3. [['t','h','i','s'],['i','s','\0',1][2,2,2,2],[3,3,3,3],[4,4,4,4],[5,5,5,5]]

      在连续视图中

      't','h','i','s','i','s','\0',12222333344445555
      

      导致观察到的行为

      您可以通过两种方式解决此问题

      • 在输出格式中使用%4s限制字符串输出。
      • 将输入限制为 3 个字符 %3s,以便在写入终止零字符时输入不会重叠。
      • 增加字符串的大小以容纳终止零字符。

      【讨论】:

        猜你喜欢
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        • 2017-12-13
        • 1970-01-01
        • 1970-01-01
        • 1970-01-01
        相关资源
        最近更新 更多