C: strcat() 终止程序没有错误

C: strcat() terminates program without error

我正在 windows 机器上编写 C 代码。这是我第一个正式的 C 程序,所以我可能不知道很多词汇。

我正在尝试编写一个程序,从文本文件中读取字符并将它们放入字符串中。

# include <stdio.h>
# include <string.h>
# define MAXCHAR 10

char* load_html(char* filename) {
  FILE *file;

  file = fopen(filename, "r");
  if (file == NULL) {
    printf("File not found %s", filename);
    return NULL;
  }

  char str[MAXCHAR];
  char* html= "";

  while (fgets(str, MAXCHAR, file) != NULL) {
    printf(str);
    //strcat(html, str);
  }

  return html;
}

int main() {
  char* filename = "load_html.c";
  load_html(filename);

  return 0;
}

当我编译 (gcc -o load_html.exe .\load_html.c) 和 运行 这段代码时,它 运行 非常好,并将该程序的源代码打印到控制台。但是,如果我取消注释 strcat

  while (fgets(str, MAXCHAR, file) != NULL) {
    printf(str);
    strcat(html, str);
  }

程序会读取文件的第一行,暂停1到2秒然后无错退出。

这里到底发生了什么?我觉得我错过了一些非常重要的东西。

html 是一个指向字符串文字的指针,这些不能更改(并且通常存储在内存的 read-only 部分),这就是 strcat 尝试的做,在此过程中调用 undefined behavior

即使情况并非如此,html 显然也太小了,无法容纳任何其他内容,因为它只有 space 表示 1 个字符。

应该是:

char html[SIZE] = "";

其中 SIZE 必须足够大以容纳所有连接的字符串。

在这种情况下,您在返回 html 时遇到问题,如果它不是指针,它将是一个局部变量,其生命周期将作为函数 returns 到期。您可以通过以下方式解决这个问题:


  1. html 保存为指针并为其分配内存:
#include <stdlib.h>
//...
char *html = malloc(SIZE);

完成后您需要free(html)


  1. 或者传递一个指向 char 的指针作为函数的参数:
void load_html(char* filename, char* html){ //void return type

    //remove declaration of html
    //do not return anything
}

主要是:

int main(){

    char* filename = "load_html.c";
    char html[size]; //buffer to store the concatenated string
    load_html(filename, html); //the string will be stored in the buffer you pass as an argument

}

我更喜欢第二个选项,因为您不需要分配内存,这是一种更昂贵的方法并迫使您手动管理内存。


printf(str)也是ill-formed,这个函数需要格式说明符来打印格式化输出:

printf("%s" str);

或者简单地使用 puts(str).

html 是指向 1 字节内存的指针。该内存是 read-only 因为它是静态分配的字符串。 strcat 覆盖它,未定义的行为也是如此,原因有两个:越界写入内存,以及写入 read-only.

的内存

您看到的任何奇怪行为(例如:您的程序提前退出)都可能是由此引起的。

在此声明中

char* html= "";

您声明了一个指向字符串文字的指针 ""

那么在这个语句中

strcat(html, str);

您正在尝试更改指向的字符串文字。

但是您不能更改字符串文字。根据 C 标准(6.4.5 字符串文字)

7 It is unspecified whether these arrays are distinct provided their elements have the appropriate values. If the program attempts to modify such an array, the behavior is undefined.

所以如果你想累积从文件中读取的字符串,你需要定义一个足够大的字符数组。

例如

char html[MAXCHAR * MAXCHAR];
html[0] = '[=12=]';

但在这种情况下会出现另一个问题,因为您可能不会 return 来自函数的局部数组,该数组在退出该函数后将不再存在。

所以更灵活和正确的做法是在while循环中为从文件中读取的每个新字符串动态地重新分配一个字符数组。

类似

char *htmp = calloc( 1, sizeof( char ) );
size_t n = 1;

while (fgets(str, MAXCHAR, file) != NULL) {
    printf(str);

    n += strlen( str );

    char *tmp = realloc( html, n );

    if ( tmp == NULL ) break;

    html = tmp;

    strcat(html, str);
}

// ...

return html;

并且在 main 中,您应该在不再需要数组时释放分配的内存。

free( html );