这个c函数有什么问题?

use*_*931 0 c

以下函数必须将一条线分成2行或更多行,每行比s短.

char **splitline(FILE *fp, int s)
{
    char **l;
    char c;
    int ccounter;
    int lcounter;

    c = fgetc(fp);
    if (c == EOF)
    {
        return NULL;
    }

    lcounter=0;
    l = malloc(sizeof(char **));
    l[lcounter] = malloc((SIZE+2)*sizeof(char));

    ccounter = 0;
    while (c != EOF && c != '\n')
    {
        l[lcounter][ccounter] = c;
        ccounter++;
        c = fgetc(fp);

        if (ccounter == SIZE)
        {
            l[lcounter][ccounter] = '\n';
            ccounter++;
            l[lcounter][ccounter] = '\0';

            realloc(l, (lcounter+2) * sizeof(char **));

            lcounter++;

            l[lcounter] = malloc((SIZE+2) * sizeof(char));
            ccounter = 0;
        }
    }

    if (ccounter == 0)
    {
        l[lcounter][ccounter] = '\0'; 
    }
    else
    {
        l[lcounter][ccounter] = '\n';
        ccounter++;
        l[lcounter][ccounter] = '\0';

        realloc(l, (lcounter+2) * sizeof(char **));

        lcounter++;

        ccounter = 0;
        l[lcounter] = malloc((SIZE+2) * sizeof(char));
        l[lcounter][ccounter] = '\0';
    }

    return l;
}
Run Code Online (Sandbox Code Playgroud)

Jon*_*ler 5

  • 您正在使用未定义的常量SIZE而不是s函数的参数来控制线的最大长度.既然s是有符号整数,你应该检查它是否合理(它应该是正(非零)数字,可能不大于1 MiB;也许你想设置一个比1更大的下限;也许你默认为80如果来电者搞砸了,或者你回来时有错误).

  • 您正char c;用于保存读取的值fgetc(); 遗憾的是,这意味着您的EOF测试不可靠.当有人提供'ÿ'(y-umlaut,ISO 8859-1中的十六进制0xFF,ISO 8646中的U + 00FF - Unicode)或者根本不会停止时,你要么提前停止类型char是签名还是未签名.永远记住:getchar()亲戚回来了int!

  • 变量l引起与常量的混淆1; 一般避免它.

  • 如果fgetc()直接测试结果,主循环条件会更好.

    int c;
    while ((c = fgetc(fp)) != EOF && c != '\n')
    {
        ...
    }
    
    Run Code Online (Sandbox Code Playgroud)

    实际上,你在循环中读取了一个字符并且没​​有正确检查它.然后,您可以使用ungetc()将字符首先读回到输入流中; 它使输入处理更加均匀.或者,如果第一次调用fgetc()是在循环控件中返回EOF ,则可以进行设置以使一切正常.

  • 正如汤米指出的那样,你必须捕捉到的输出realloc(); 无法保证它会返回其输入指针作为结果.您现在还应该了解到,您没有将结果保存realloc()到指定为其第一个参数的变量中.如果你这样做,你会立即泄漏内存并且重新分配失败(因为你丢失了指向旧内存的指针 - 它只是归零).所以,为了安全起见,你使用:

    char **new_array = realloc(l, (lcounter+1) * sizeof(*new_array));
    if (new_array == 0)
        ...handle out of memory...
    else
        l = new_array;
    
    Run Code Online (Sandbox Code Playgroud)

    这里有几点.你分配了(lcounter+2)值,但我认为你只使用其中一个(除非有一个终端空指针来标记数组的结尾).你指定sizeof(char **)但实际上你想要一个char *值数组.幸运的是,所有(对象)指针的大小都相同--C标准保证; 只有POSIX保证函数指针与对象指针的大小相同(C标准没有).所以,sizeof(char **) == sizeof(char *)你是安全的,但你不是在问你想要什么.

  • 关于realloc()可能失败的讨论的必然结果也malloc()可能失败.您应该错误检查内存分配 - 或者使用标准库的一组封面函数,只有在返回的指针不为空时才返回.如果你不检查它,你的程序最终会因内存分配失败而崩溃 - 即使在具有24 GiB主内存的机器上(尽管可能需要一段时间才能达到这一点).

  • 代码中有很多重复.你应该避免这样做.这意味着可能使用子功能来管理内存分配.

如果你解决这些问题,那么你就有机会获得一个有效的功能.您还应编写代码以释放您返回的已分配内存,以便用户无需为您设计方法.总是担心谁会释放分配的内存以及它将如何发布.


Chris Lutz问道:

标准在哪里保证所有对象指针类型都相同?

我相信(C99 - ISO/IEC 9899:1999)标准的相关部分是:

§6.3.2.3指针

1指向void的指针可以转换为指向任何不完整或对象类型的指针.指向任何不完整或对象类型的指针可能会转换为指向void的指针并再次返回; 结果应该等于原始指针.

这基本上说所有对象指针类型都可以转换为void指针,然后再返回而不会丢失信息,这意味着它们必须都是相同的大小.请注意,类别"对象指针"不包括"函数指针".

POSIX标准的相关部分(关于函数指针)是§2.12.3(在链接部分的底部).