问题描述
我正在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,file) != NULL) {
printf(str);
strcat(html,str);
}
这到底是怎么回事?我觉得我缺少一些非常重要的东西。
解决方法
html
是指向字符串文字的指针,它们不能更改(通常存储在内存的只读部分中),这是strcat
试图执行的操作,调用undefined behavior。
即使不是这种情况,html
显然也太小了,无法容纳其他任何东西,因为它只能容纳1个字符。
应该是:
char html[SIZE] = "";
SIZE
必须足够大以容纳所有串联的字符串。
在这种情况下,您在返回html
时遇到问题,如果它不是指针,它将是一个局部变量,该函数的生命周期将终止。您可以通过以下方式解决此问题:
- 保留
html
作为指针并为其分配内存:
#include <stdlib.h>
//...
char *html = malloc(SIZE);
完成后,您需要free(html)
。
- 或将指向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)
也是格式错误的,此功能需要格式说明符来打印格式化的输出:
printf("%s" str);
或仅使用puts(str)
。
在此声明中
char* html= "";
您声明了指向字符串文字""
的指针。
然后在此声明中
strcat(html,str);
您正在尝试更改指向的字符串文字。
但是,您不能更改字符串文字。根据C标准(6.4.5字符串文字)
7不确定这些数组是否有区别,只要它们的 元素具有适当的值。 如果程序尝试执行以下操作 修改这样的数组,行为是不确定的。
因此,如果要累积从文件中读取的字符串,则需要定义足够大的字符数组。
例如
char html[MAXCHAR * MAXCHAR];
html[0] = '\0';
但是在这种情况下,还会出现另一个问题,因为您可能无法从函数中返回一个本地数组,而该函数在退出该函数后将不处于活动状态。
因此,一种更灵活,正确的方法是在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;
在主要情况下,当不再需要该数组时,应该释放分配的内存。
free( html );
,
html
是指向1字节内存的指针。该内存是只读的,因为它是静态分配的字符串。 strcat
会覆盖它,未定义的行为也会被覆盖,原因有两个:写内存超出范围,写到只读内存。
您看到的任何怪异行为(例如:程序提前退出)都可能是这种情况造成的。