【问题标题】:Why null chars added in array?为什么在数组中添加空字符?
【发布时间】:2021-12-28 13:54:04
【问题描述】:

我有一个数组,它保存 stringchars,并希望找到它的 suffixes。如果我在数组中添加 7 个字符,则字符总数应该是 7*8/2 = 28。所以 suffix_array 限制应该是 28。当我尝试创建后缀数组时,我注意到数组也有空字符。所以我的输出是错误的。 这是什么原因?

#include <stdio.h>
#include <stdlib.h>

static char *suffix;

int main()
{
    char s[7] = {'c','o','n','n','e','c','t'};
    suffix = (char*) malloc(sizeof (char)*28);
    int j;
    static int k=0;
    j=k;
    for(int i=0; i<28; i++) {
        suffix[i] = s[j];
        printf("%c ", suffix[i]);
        if(j<7) {
            j++;
        }
        else {
            k++;
            j=k;
        }
            
    }
    
    return 0;
}
Output:

c o n n e c t  o n n e c t  n n e c t  n e c t  e c

【问题讨论】:

  • 你在哪里输出任何东西?
  • 循环的每 7 次迭代,您就有 j == 7,而 s[7] 越界(零索引数组,记得吗?)
  • 请注意,AddressSanitizer 和 UBSan 都会立即捕获此溢出:godbolt.org/z/fzPMfqx4a
  • @Ahmeett_ Re "我不知道在这种情况下如何调试我的程序",学习时,有时最好拿出一张纸,然后创建一个每个变量的列。自己走一遍程序。但是,您可以使用 IDE 来做同样的事情。您试图回答的问题是:实际行为在哪里偏离了预期行为?你可以倒过来工作。当我收到错误时,我的变量有什么值? (suffix[i] 是垃圾)。为什么? s[j] 是垃圾。为什么? j==7,超出了数组的末尾。为什么? if (j&lt;7) { j++; } 错了。
  • 请注意,-fsanitize=address 会缩短该过程,将您直接带到“j 超出数组末尾”。

标签: arrays c for-loop undefined-behavior


【解决方案1】:

即使在第一次迭代中,for 循环也会调用未定义的行为

for(int i=0; i<28; i++) {
    suffix[i] = s[j];
    printf("%c ", suffix[i]);
    if(j<7) {
        j++;
    }
    //...

j等于6时增加

    if(j<7) {
        j++;
    }

所以j 等于7,并且这个值将用于赋值语句中循环的下一次迭代

    suffix[i] = s[j];

因此,可以访问数组 s 的最后一个元素之后的内存,因为该数组的有效索引范围是 [0, 7 )

注意,在文件范围内声明变量后缀,将局部变量设为静态,没有太大意义。

您的程序至少可以通过以下方式简化

#include <stdio.h>
#include <stdlib.h>

int main( void ) 
{
    enum { N = 7, M = ( N * ( N + 1 ) ) / 2 };

    const char s[N] = { 'c','o','n','n','e','c','t' };
    char *suffix = malloc( sizeof( char ) * M );

    for ( size_t i = 0, k = 0, j = k; i < M; i++ ) 
    {
        suffix[i] = s[j++];
        printf("%c ", suffix[i]);

        if ( j == N ) j = ++k;
    }

    free( suffix );

    return 0;
}

程序输出是

c o n n e c t o n n e c t n n e c t n e c t e c t c t t

请注意,当不再需要动态分配的数组时,您应该始终释放它们。

实际上在这个程序中不需要动态分配结果数组。你可以写

char suffix[M];

【讨论】:

    【解决方案2】:

    您最终得到 j==7 (if (j&lt;7) { j++; }),它超出了 s 的结尾。

    替换

    if(j<7) {
        j++;
    }
    else {
        k++;
        j=k;
    }
    

    j++;
    if(j==7) {
        k++;
        j=k;
    }
    

    提示:

    • 硬编码 7 和 28 是个坏主意(包括 Vlad 的做法)。最好使用
      char s[] = {...}; size_t n = sizeof(s)/sizeof(s[0]);(如果是数组)
      const char *s = "connect"; size_t n = strlen(s);(如果是字符串)

    • 你并没有真正使用suffix。但是,如果您想在suffix 中构建一个字符串,请确保为尾随 NUL 再分配一个字符并添加尾随 NUL!

    【讨论】:

      猜你喜欢
      • 1970-01-01
      • 2016-11-23
      • 2020-04-30
      • 2012-09-21
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      • 1970-01-01
      相关资源
      最近更新 更多