【问题标题】:Segmentation Fault with sprintfsprintf 的分段错误
【发布时间】:2012-03-25 06:02:45
【问题描述】:

我正在创建一个 makefile 创建器,但我在 sprintf 上遇到了这个错误,最奇怪的是我在出现错误的一个之前有多个 sprintf,它们工作正常。

代码如下:

if ( WIFEXITED(stat)  ){

    if ( WEXITSTATUS(stat) ) {

        if ( cFiles == 0 && cFolders == 0 ) {
            Crear(path);
        }

        cFolders = 1;
        TEMP = malloc( sizeof(char)*( strlen(direntp->d_name) + 25 ) );

        if ( TEMP == NULL ) {
            perror("Malloc Error: ");
            exit(1);
        }

        if ( sprintf(TEMP, "\n%s/%s.a: force\n\t$(MAKE) -C %s\n",direntp->d_name, direntp->d_name, direntp->d_name) < 0 ) {
        perror("Sprintf Error: ");
        exit(1);
        }

        write(STDOUT_FILENO,TEMP,strlen(TEMP));
        f.name = malloc( sizeof(char)*( strlen(direntp->d_name)*2 + 3 ) );

        if ( f.name = NULL ) {
            perror("Malloc Error: ");
            exit(1);
        } 
            //This is the one with the problem!!!       
            if ( sprintf(f.name, "%s/%s.a", direntp->d_name, direntp->d_name) < 0 ) {
            perror("Sprintf Error: ");
            exit(1);
        }

        l = AddToList(l,&f);
    }
}

【问题讨论】:

  • 我最好的猜测是其中一个字符串不是以空值结尾的。当我第一次学习 C 时,我遇到过几次这个问题。

标签: c segmentation-fault printf


【解决方案1】:

您似乎分配的 TEMP 不够大

TEMP = malloc( sizeof(char)*( strlen(direntp->d_name) + 25 ) );

应该是:

TEMP = malloc( sizeof(char)*( strlen(direntp->d_name)*3 + 25 + 1 ) );

您正在打印 d_name 三次,并且您还需要一个额外的字节作为空终止符。

同样,在这一行:

   f.name = malloc( sizeof(char)*( strlen(direntp->d_name)*2 + 3 ) );

应该是

   f.name = malloc( sizeof(char)*( strlen(direntp->d_name)*2 + 3 + 1) );

考虑空终止符。

使用这样的断言有助于确保您的计算是正确的:

    int TEMP_size = strlen(direntp->d_name)*3 + 25 + 1; 
    TEMP = malloc(sizeof(char)*TEMP_size);

    if ( TEMP == NULL ) {
        perror("Malloc Error: ");
        exit(1);
    }

    if ( sprintf(TEMP, "\n%s/%s.a: force\n\t$(MAKE) -C %s\n",direntp->d_name, direntp->d_name, direntp->d_name) < 0 ) {
      perror("Sprintf Error: ");
      exit(1);
    }
    assert(strlen(TEMP)+1==TEMP_size);

【讨论】:

  • 对不起,我发布的代码是旧代码并且 TEMP 分配已修复,但分段错误不是来自 TEMP,而是来自 sprintf(f.name.....)。这就是我发现的奇怪之处,即使 f.name = malloc( sizeof(char)*( strlen(direntp->d_name)*2 + 3 + 1) ) 仍然会启动相同的错误。
【解决方案2】:

“%s/%s.a”,所以我认为如果“%s”的长度为 n,那么整个字符串将采用 n*2+1+1+1+1=2n+4 而不是 2n+3 ...不要忘记终止的 '\0',,, 但是至于这是否会导致分段错误...我不知道...

//是的,这段代码中有很多关于分配字节数的错误......

【讨论】:

    【解决方案3】:

    您没有为此 sprintf 分配足够的内存:

    sprintf(TEMP, "\n%s/%s.a: force\n\t$(MAKE) -C %s\n",direntp->d_name, direntp->d_name, direntp->d_name
    

    你分配 sizeof(direntp->d_name) +25 但我看到 25 char + 3* sizeof(direntp->d_name) +1 extra char(你的 \0 表示你的字符串的结尾)

    问候

    【讨论】:

    • 谢谢,但就像我在其他 cmets 中所说的那样,这不是错误,尽管 TEMP 现在已经更正了来自 sprintf(f.name.....) 的 seg 错误跨度>
    • sprintf(f.name, "%s/%s.a", direntp->d_name, direntp->d_name, 我看到 2* strlen(direntp->d_name) + 3 char + 1 extra char (\0 表示字符串结尾)。您只分配了 2*strlen(direntp->d_name) + 3 个字符。您错过了字符串的 \0 空间。编辑 arf 之前没有看到您尝试过。
    【解决方案4】:

    除了以前的答案之外的一些注释:

    1. 大多数现代类 Unix 系统在标准库中都有 asprintf() 和 vasprintf(),它们自己分配缓冲区。使用它们比计算所需大小、分配和调用 sprintf() 更简单,即使它们过度分配了一点。

    2. 填充缓冲区然后使用 write() 将其打印到 stdout 看起来比简单的 printf() 复杂得多。除非您使用 stdio 无法稳定处理的东西(如非阻塞 I/O),否则将 stdio 用于此类任务要好得多。

    3. 您正在执行的任务更适合某些脚本语言(Perl、Python、Tcl、Ruby 等),除非某些外部奇怪的情况迫使您使用 C; C 应该以 Unix 的方式实现更接近内核和低级的区域。参见例如"The Art of Unix Programming"推理。

    【讨论】:

    • 这是我大学的一个项目,这就是我必须使用 C 的原因,我知道 asprintf() 更好,但我可以使用的命令有一些限制。
    猜你喜欢
    • 2011-11-03
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 2012-03-25
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    • 1970-01-01
    相关资源
    最近更新 更多