如何在C方法(char数组)中使用指针



我是C的新手,对指针和字符数组感到困惑…

我写了:

char *read(char *filename) {
char *text[1000];
FILE *inputFile = fopen(filename, "r");
int i=0;
while (feof(inputFile)) {
text[i++] = fgetc(inputFile);
}
text[i]='';
fclose(inputFile);
return text;
}

我的目标是传入我想要打开的文件的名称,打开它,并将其中的所有单词分配到一个字符数组(char text[])中。我不断得到以下错误:

expression which evaluates to zero treated as a null pointer constant of type 'char *' [-Wnon-literal-null-conversion]

incompatible pointer types returning 'char *[1000]' from a function with result type 'char *' [-Wincompatible-pointer-types]

寻求建议

这里有两个问题。

首先,你的数组被声明为char *text[1000];,即指针指向char的数组,因此每个text[i]是一个指针,而不是一个字符。你想要的可能是char text[1000];

这会导致第二个问题,即返回指向局部变量的指针。当函数返回时,该指针将失效,因此尝试使用它将触发未定义行为。

你应该动态分配内存:

char *text = malloc(1000);

所以函数返回时仍将有效。请记住,当您完成使用内存时,您需要free

或者,您可以将要填充的缓冲区作为参数传递给函数:

void read(char *filename, char *text) {

您希望用从文件中读取的字符填充字符数组。如果是这样,那么至少需要声明一个像

这样的字符数组。
char text[1000];

而不是写

时指向字符的指针数组
char *text[1000];

然而,声明的数组具有自动存储持续时间,并且在退出函数后将不再存活。所以返回的指针是无效的。

应该动态分配数组,例如

char *text = malloc( 1000 );

您还需要检查文件是否已成功打开。

while循环中的条件

while (feof(inputFile)) {
text[i++] = fgetc(inputFile);
}

可以在调用fgets之后出现。因此,数组可以存储一个无效的字符。

你应该写

for ( int value; i + 1 < 1000 && ( value = fgetc( inputFile ) ) != EOF; i++ ) 
{
text[i] = value;
}

问题的关键是:存储这些字符的内存空间在哪里?和-谁可以使用后,你的函数返回?具体来说,当函数再次被调用时会发生什么?

现在(忽略你有一个指针数组的事实),你返回一个局部变量的地址,正如@dbush指出的。这意味着:

  • 只有你的函数可以使用内存空间
  • 当您离开该功能时,它将停止可用…
  • …并且编译器可能会为程序中的其他用途分配相同的地址。

@dbush的建议是解决这个问题的一种方法:你的函数可以在每次调用时分配内存,并返回一个指向分配内存的指针。

另一种方法是更改函数的签名,以便由调用者提供内存空间,例如:

int read_entire_file(char* destination_buffer, const char *filename);

在这两种情况下,都有另一个问题,那就是1000个字符的限制(或者更确切地说,999个字符和后面的'',它标志着字符串的结束)。如果文件中有更多的数据呢?也许你应该把缓冲区的大小也取下来?:

int read_entire_file(char* destination_buffer, size_t buffer_size, const char *filename);

除了我的建议和@dbush的建议,还有其他的选择,但我的观点是,有不止一种方法来完成这项任务。


其他评论/问题:

  • 不要将文件名作为非开销指针(char*);让它成为const char* filename来澄清你不允许改变文件名。
  • fgetc()是从文件中读取数据的一种相当慢的方式。考虑fread():
    size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
    
  • 你必须确保你的fopen()文件成功;如果没有,返回NULL(或者终止程序)。你的fgetc()呼叫也是如此。
  • 你没有检查你是否已经到达缓冲区的边缘,因此可能溢出缓冲区。
  • 将大量数据放在堆栈上不是一个好主意。
  • read()是一个过于通用的名称;更具体一些。此外,该名称可能与Linux, MacOS和其他类unix操作系统上的典型同名系统调用冲突。

最新更新