这是释放 C 语言内存的可接受方式吗?

huangapple go评论62阅读模式
英文:

Is this an acceptable way to deallocate memory in c?

问题

下面是您提供的代码的翻译部分:

// 我有一个函数,它读取一个文件并为文件内容分配内存,然后将文件内容分配给指针,然后返回指针。然后,我使用循环来遍历字符串,并使用指针算术打印每个字符。

// 我相当肯定我可以/应该在每次迭代时使用realloc来重新分配更少的内存,而不是使用计数器来跟踪迭代,但我不确定如何实现它。

// 因此,代替在代码末尾调用`free()`时,我从指针变量中减去计数器以释放最初指向的`contents`指针的地址。

// 以下是我用于读取文件的代码以及我的循环所在的主函数:

char *read_file(const char *filename) {
    FILE *fp = fopen(filename, "r");
    if (fp == NULL) {
        perror("无法打开文件");
        exit(EXIT_FAILURE);
    }

    // 获取文件的信息
    struct stat st;
    if (fstat(fileno(fp), &st) != 0) {
        perror("无法获取文件信息");
        exit(EXIT_FAILURE);
    }
    size_t file_size = st.st_size;

    // 分配一个缓冲区来保存文件的内容
    char *buffer = (char *) malloc(file_size + 1);
    if (buffer == NULL) {
        perror("内存分配失败");
        exit(EXIT_FAILURE);
    }

    // 将文件内容读取到缓冲区
    size_t bytes_read = fread(buffer, 1, file_size, fp);
    buffer[bytes_read] = '
// 我有一个函数,它读取一个文件并为文件内容分配内存,然后将文件内容分配给指针,然后返回指针。然后,我使用循环来遍历字符串,并使用指针算术打印每个字符。

// 我相当肯定我可以/应该在每次迭代时使用realloc来重新分配更少的内存,而不是使用计数器来跟踪迭代,但我不确定如何实现它。

// 因此,代替在代码末尾调用`free()`时,我从指针变量中减去计数器以释放最初指向的`contents`指针的地址。

// 以下是我用于读取文件的代码以及我的循环所在的主函数:

char *read_file(const char *filename) {
    FILE *fp = fopen(filename, "r");
    if (fp == NULL) {
        perror("无法打开文件");
        exit(EXIT_FAILURE);
    }

    // 获取文件的信息
    struct stat st;
    if (fstat(fileno(fp), &st) != 0) {
        perror("无法获取文件信息");
        exit(EXIT_FAILURE);
    }
    size_t file_size = st.st_size;

    // 分配一个缓冲区来保存文件的内容
    char *buffer = (char *) malloc(file_size + 1);
    if (buffer == NULL) {
        perror("内存分配失败");
        exit(EXIT_FAILURE);
    }

    // 将文件内容读取到缓冲区
    size_t bytes_read = fread(buffer, 1, file_size, fp);
    buffer[bytes_read] = '\0';

    // 关闭文件并返回缓冲区
    fclose(fp);
    return buffer;
}

int main() {
    char *contents = read_file("testNote.txt");
    int counter = 0;

    while (*contents != '\0') {
        printf("%c", *contents);
        ++counter;
        ++contents;
    }

    free(contents - counter);

    return 0;
}
'
;
// 关闭文件并返回缓冲区 fclose(fp); return buffer; } int main() { char *contents = read_file("testNote.txt"); int counter = 0; while (*contents != '
// 我有一个函数,它读取一个文件并为文件内容分配内存,然后将文件内容分配给指针,然后返回指针。然后,我使用循环来遍历字符串,并使用指针算术打印每个字符。

// 我相当肯定我可以/应该在每次迭代时使用realloc来重新分配更少的内存,而不是使用计数器来跟踪迭代,但我不确定如何实现它。

// 因此,代替在代码末尾调用`free()`时,我从指针变量中减去计数器以释放最初指向的`contents`指针的地址。

// 以下是我用于读取文件的代码以及我的循环所在的主函数:

char *read_file(const char *filename) {
    FILE *fp = fopen(filename, "r");
    if (fp == NULL) {
        perror("无法打开文件");
        exit(EXIT_FAILURE);
    }

    // 获取文件的信息
    struct stat st;
    if (fstat(fileno(fp), &st) != 0) {
        perror("无法获取文件信息");
        exit(EXIT_FAILURE);
    }
    size_t file_size = st.st_size;

    // 分配一个缓冲区来保存文件的内容
    char *buffer = (char *) malloc(file_size + 1);
    if (buffer == NULL) {
        perror("内存分配失败");
        exit(EXIT_FAILURE);
    }

    // 将文件内容读取到缓冲区
    size_t bytes_read = fread(buffer, 1, file_size, fp);
    buffer[bytes_read] = '\0';

    // 关闭文件并返回缓冲区
    fclose(fp);
    return buffer;
}

int main() {
    char *contents = read_file("testNote.txt");
    int counter = 0;

    while (*contents != '\0') {
        printf("%c", *contents);
        ++counter;
        ++contents;
    }

    free(contents - counter);

    return 0;
}
'
) {
printf("%c", *contents); ++counter; ++contents; } free(contents - counter); return 0; }

希望这有助于您理解代码的工作原理。如果您有任何疑虑,请随时提出。

英文:

I have a function that reads a file and allocates memory for the files contents and assigns the files contents to a pointer and then returns the pointer. I then use a loop to loop over the string and print each character using pointer arithmetic.

I'm pretty sure I could/should use realloc to reallocate less memory each iteration as opposed to tracking the iterations with a counter but I'm not sure exactly how to implement it.

So instead at the end of the code when I call free() I subtracted the counter from the pointer variable to deallocate the address that the contents pointer originally pointed to.

Below is the code I used to read the file as well as the main function where my loop is at:

char *read_file(const char *filename) {
    FILE *fp = fopen(filename, "r");
    if (fp == NULL) {
        perror("Failed to open file");
        exit(EXIT_FAILURE);
    }

    // Obtain information about the file
    struct stat st;
    if (fstat(fileno(fp), &st) != 0) {
        perror("Failed to get file information");
        exit(EXIT_FAILURE);
    }
    size_t file_size = st.st_size;

    // Allocate a buffer to hold the contents of the file
    char *buffer = (char *) malloc(file_size + 1);
    if (buffer == NULL) {
        perror("Failed to allocate memory");
        exit(EXIT_FAILURE);
    }

    // Read the contents of the file into the buffer
    size_t bytes_read = fread(buffer, 1, file_size, fp);
    buffer[bytes_read] = '\0';

    // Close the file and return the buffer
    fclose(fp);
    return buffer;
}




int main() {
    char *contents = read_file("testNote.txt");
    int counter = 0;

    while (*contents != '\0') {

        printf("%c", *contents);

        ++counter;
        ++contents;
    }

    free(contents - counter);

    return 0;
}

As far as I can tell after experimenting this is working the way I'm thinking it is, but I just want to make sure I'm not doing anything harmful here

答案1

得分: 6

你正在做的方式有效。每次增加contents时,也会增加counter,因此contents - counter给出了原始指针,可以进行释放。

当然,更好的方式是使用临时指针来遍历分配的内存,以便可以使用原始指针来进行free

int main() {
    char *contents = read_file("testNote.txt");
    char *tmp = contents;

    while (*tmp != '
int main() {
    char *contents = read_file("testNote.txt");
    char *tmp = contents;

    while (*tmp != '\0') {

        printf("%c", *tmp);

        ++tmp;
    }

    free(contents);

    return 0;
}
'
) {
printf("%c", *tmp); ++tmp; } free(contents); return 0; }
英文:

What you're doing will work. Each time you increment contents, you also increment counter, so contents - counter gives you the original pointer that you can free.

Of course, a better way of doing this would be to use a temporary pointer to increment through the allocated memory so you can use the original to free.

int main() {
    char *contents = read_file("testNote.txt");
    char *tmp = contents;

    while (*tmp != '
int main() {
char *contents = read_file("testNote.txt");
char *tmp = contents;
while (*tmp != '\0') {
printf("%c", *tmp);
++tmp;
}
free(contents);
return 0;
}
') { printf("%c", *tmp); ++tmp; } free(contents); return 0; }

答案2

得分: 1

不,这不安全。

假设您读取一个大于2147483647字节,约2GB的文件。然后,当您到达文件末尾时,counter的值会溢出并变为负数。当您执行contents - counter时,得到的地址与您从malloc()获得的地址不同。最好的情况是程序崩溃,最糟糕的情况是它会损坏堆并继续运行。

我建议使用@dbush的建议。即使您可以保证不会遇到2GB的文件,他们的代码仍然更容易理解。

英文:

No, this isn't safe.

Suppose you read a file which is bigger than 2147483647 bytes, or about 2 GB. Then the value of counter overflows by the time you get to the end of the file, and is negative. When you subtract contents - counter, you get an address different from the one you got from malloc(). The best case scenario is that it crashes. The worst case scenario is that it corrupts the heap and keeps running.

I would suggest using @dbush's suggestion. Even if you can guarantee you won't get 2GB files, their code is still easier to reason about.

huangapple
  • 本文由 发表于 2023年2月27日 08:20:20
  • 转载请务必保留本文链接:https://go.coder-hub.com/75575851.html
匿名

发表评论

匿名网友

:?: :razz: :sad: :evil: :!: :smile: :oops: :grin: :eek: :shock: :???: :cool: :lol: :mad: :twisted: :roll: :wink: :idea: :arrow: :neutral: :cry: :mrgreen:

确定