C - 我不想分配我不会使用的内存! (新问题)

时间:2011-05-19 20:11:38

标签: c string comments malloc

我已经制作了我的第一个C程序。它删除C注释('//')。我将一个字符串传递给函数strip_comments,创建一个与参数字符串大小相同的新字符串,然后我做一个副本,char by char,忽略注释。

这是代码:

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

#define IN 1
#define OUT 0

int file_size(FILE *file);
char * strip_comments(char *content);

int main(int argc, char *argv[])
{
    FILE *file;
    char *buffer, *content;
    int size;

    if (argc == 1)
    {
        printf("USAGE: stripccomments filename\n");
        return 1;
    }

    if ((file = fopen(argv[1], "rw")) == NULL)
    {
        printf("Could not open file '%s'.\n", argv[1]);
        return 1;
    }

    size = file_size(file);
    buffer = malloc(sizeof(char) * size);

    if (buffer == NULL)
    {
        printf("Could not allocate memory\n");
        return 1;
    }

    fread(buffer, sizeof(char), size, file);

    content = strip_comments(buffer);
    printf("%s", content);

    free(buffer);
    fclose(file);

    return 0;
}

int file_size(FILE *file)
{
    int size;

    fseek(file, 0, SEEK_END);
    size = ftell(file);
    rewind(file);

    return size;
}

char * strip_comments(char *content)
{
    int state, length, i, j;
    char *new_content;

    state = OUT;
    length = strlen(content);
    new_content = malloc(sizeof(char) * length);
    j = 0;

    for (i = 0; i < length; i++)
    {
        if (content[i] == '/' && content[i + 1] == '/')
        {
            state = IN;
            i++;
            continue;
        }

        if (state && content[i] == '\n')
        {
            state = OUT;
        }

        if (!state)
        {
            new_content[j] = content[i];
            j++;
        }
    }
    new_content[j + 1] = '\0';

    return new_content;
}

如果有一些注释,我将只使用分配字符串的一些字节。我不想分配超过我将使用的。这样做的最佳方法是什么,并返回一个新的字符串?或者我应该修改作为参数传递的字符串吗?

更新:这个未使用的空间会发生什么?它是否仍处于“边缘”状态?当执行到达终点时,这个空间会发生什么?

谢谢。

3 个答案:

答案 0 :(得分:2)

这并没有解决你所说的问题,但我的方法是把它写成一个与输入文件句柄和输出文件句柄一起工作的函数,即void strip_comments(FILE *infile, FILE *outfile);。你真的只是做一次一次的解析,那么失去从content[i++]getc()的转变是什么?如果你用文件句柄而不是字符串来做,你a)不必将大量的整个文件存储在内存中,并且b)不必担心为缓冲区分配内存。

也就是说,如果你想用char *代替它,你总是可以解析字符串两次:一次计算要分配的字节数,然后一次复制所述字节。或者您可以在结尾处拨打realloc以将缓冲区缩短到适当的大小。

答案 1 :(得分:1)

由于您的程序不知道需要多少内存来包含源代码,因此您可以从初始缓冲区大小开始,并根据需要增加它。另一种方法是首先扫描文件并计算大小差异。这两种方法都会影响性能,具体取决于传入的注释量。多个malloc / realloc会降低性能,并且会读取整个文件两次,另一方面你担心浪费内存,你可以选择决定或者你可以使用全部3,设置默认值然后实现命令行标志,让用户决定选择哪个选项。

还要记住在你的strlen中添加+1以说明空字符。如果文件中没有注释,您当前的实现将进入非malloc区域。

您的更新:

是的,浪费的空间将在你的字符串的末尾不做任何事情,但在调用free后将被正确回收。例如,在分配给15的内存块中,strlen为10的字符串可能如下所示:

size of 10\0#%^@&
          ^^^garbage
          ^^null char

答案 2 :(得分:0)

我只能想到一种可能使你的分配更有效的方法(不是我认为它需要,老实说,你现在正在做的事情看起来很合理,特别是对于新的C程序员而言)。

我能想到的是两次通过你的档案。在第一遍中,您可以计算需要分配的内存量。在此之后,您可以准确分配所需的内存量,然后在第二遍中进行实际复制。

此外,您可能会看到使用文件句柄而不是完全在内存中执行此操作,这样您就不需要一次分配大量内存。