我的代码在长文本时崩溃?从文件中逐个字符地读取到 C 中的动态字符数组

My code crashes at long texts? Reading from file character by character into a dynamic char array in C

我想从txt文件中读取整篇文章,然后打印出来。 它应该具有动态内存管理和逐个字符。 我的代码适用于短文本(最多 40 个字符),但当我阅读更多字符时崩溃。

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

int main()
{
   char *s;
   int n, i;
   s = (char*) malloc(sizeof(char));
   n=0;
   FILE *f=fopen("input.txt","r");
   while (fscanf(f, "%c", &s[n]) != EOF)
        n++;
   fclose(f);
   free(s);
   for (i=0;i<n;i++)
   printf("%c",s[i]);
   return 0;
}

您只为一个字符 (sizeof(char)) 分配 space:

s = (char*) malloc(sizeof(char));

如果要存储更多字符,则必须分配更多 space,例如:

s = (char*) malloc(sizeof(char) * 100);

要读取整个文件,您最好先找出文件有多大,这样您就知道需要为 s.

分配多少 space

don't cast malloc.

你分配了错误的字节数,sizeof(char) return你的大小是 一个 char,所以你只分配了一个字节。这还不够hold 一个字符串。

你应该像这样使用 malloc:

int *a = malloc(100 * sizeof *a);
if(a == NULL)
{
    // error handling
    // do not continue
}

使用sizeof *a优于sizeof(int),因为它总是return 正确的字节数。 sizeof(int) 也会这样做,但问题是 这里是人为因素,很容易写错sizeof(*int) 反而。关于这个问题,这里有成千上万的问题。

请注意,char 被定义为具有 1 的大小,这就是为什么当您 为字符串或 char 数组分配内存,人们通常不会写 * sizeof *a:

char *s = malloc(100);
// instead of
char *s = malloc(100 * sizeof *s);

就好了。但同样,这仅适用于 char。对于其他类型 您需要使用 sizeof 运算符。

您应该始终检查 malloc 的 return 值,因为如果它 returns NULL,您无法访问该内存。

while (fscanf(f, "%c", &s[n]) != EOF)
    n++;

例如,如果您分配了 100 个空间,则必须检查您是否没有 达到了极限。否则你会溢出 s:

char *s = malloc(100);
if(s == NULL)
{
    fprintf(stderr, "not enough memory\n");
    return 1;
}

int n = 0;

while ((fscanf(f, "%c", &s[n]) != EOF) && n < 100)
    n++;

在这种情况下,您没有使用分配的内存来存储字符串,所以它是 很好,它没有 '[=34=]' 终止字节。但是,如果你想 有一个字符串,你需要写一个:

while ((fscanf(f, "%c", &s[n]) != EOF) && n < 99)
    n++;

s[n] = '[=14=]';

你也在做这个

free(s);
for (i=0;i<n;i++)
    printf("%c",s[i]);

您正在释放内存,然后尝试访问它。你必须做 反过来,访问然后免费。

正确方法:

for (i=0;i<n;i++)
    printf("%c",s[i]);
free(s);

编辑

如果你想将整个文件的内容放在一个字符串中,那么你有 2 选项:

  1. 预先计算文件的长度,然后使用分配正确的 数据量
  2. 一次读取一个固定大小的字节块,每次都调整内存大小 你读了一个新的块。

第一个很简单,第二个有点复杂,因为 你必须阅读内容,看看你读了多少,调整内存大小 realloc,检查调整大小是否成功。这是你可以 当你掌握了简单内存管理的知识时再做。

我会告诉你第一个,因为它更容易。函数 fseek 允许您将文件指针前进到文件末尾,使用 函数 ftell you can get the size of the file and with rewind 倒回文件指针并将其设置为开头:

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

int main(int argc, char **argv)
{
    if(argc != 2)
    {
        fprintf(stderr, "usage: %s file\n", argv[0]);
        return 0;
    }

    FILE *fp = fopen(argv[1], "r");

    if(fp == NULL)
    {
        fprintf(stderr, "Could not open %s for reading.\n", argv[1]);
        return 1;
    }

    // calculating the size

    // setting file pointer to the end of the file
    if(fseek(fp, 0L, SEEK_END) < 0)
    {
        fprintf(stderr, "Could not set the file pointer to the end\n");
        fclose(fp);
        return 1;
    }

    // getting the size
    long size = ftell(fp);

    if(size < 0)
    {
        fprintf(stderr, "Could not calculate the size\n");
        fclose(fp);
        return 1;
    }

    printf("file size of %s: %ld\n", argv[1], size);

    // rewinding the file pointer to the beginning of the file
    rewind(fp);

    char *s = malloc(size + 1); // +1 for the 0-terminating byte

    if(s == NULL)
    {
        fprintf(stderr, "not enough memory\n");
        fclose(fp);
        return 1;
    }

    int n = 0;

    // here the check && n < size is not needed
    // you allocated enough memory already
    while(fscanf(fp, "%c", &s[n]) != EOF)
        n++;

    s[n] = '[=17=]'; // writing the 0-terminating byte

    fclose(fp);

    printf("Contents of file %s\n\n", argv[1]);

    for(int i=0; i<n; i++)
        printf("%c",s[i]);

    free(s);
    return 0;
}

在 fseek 的帮助下计算文件的大小。

fseek(fp, 0L, SEEK_END); sz = ftell(fp);

然后您可以返回到文件的开头

fseek(fp, 0L, SEEK_SET); 通过 malloc 分配那么多内存。 S= (char*)malloc((sizeof(char)×sz)+1) 现在你可以使用这个内存来复制字节 while lopp