如何在 C 方法(字符数组)中使用指针
How to use pointers in C methods (char arrays)
我是 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]='[=10=]';
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];
.
这会导致第二个问题,即您要返回一个指向局部变量的指针。该指针在函数 returns 时失效,因此尝试使用它会触发 undefined behavior.
您应该改为动态分配内存:
char *text = malloc(1000);
所以函数returns时仍然有效。请记住,当您使用完内存后,您将需要 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;
}
问题的症结在于:存储这些字符的内存 space 在哪里?并且 - 谁可以在你的函数 returns 之后使用?具体来说,当你的函数再次被调用时会发生什么?
现在(忽略你有一个指针数组的事实),你正在 return 获取局部变量的地址,正如@dbush 指出的那样。这意味着:
- 只有您的函数可以使用内存中的 space。
- 离开该功能后将停止使用...
- ...并且相同的地址可能会被编译器分配给程序中的其他用途。
@dbush 的建议是解决该问题的一种方法:您的函数可以在每次调用时分配内存,并返回指向该分配内存的指针。
另一种方法是更改函数的签名,以便由调用者提供内存 space,例如:
int read_entire_file(char* destination_buffer, const char *filename);
在这两种情况下,还有另一个问题,即 1000 个字符的限制(或者更确切地说,999 个字符和尾随的 '\0',它标志着字符串的结尾)。如果文件中有更多数据怎么办?也许您实际上也应该采用缓冲区的大小?:
int read_entire_file(char* destination_buffer, size_t buffer_size, const char *filename);
除了我建议的方法和@dbush 的建议之外,还有其他替代方法,但我的观点是,完成此任务的方法不止一种。
其他comments/issues:
- 不要将文件名作为非成本指针(
char*
);让它 const char* filename
澄清你不能更改文件名。
fgetc()
是一种从文件中读取数据的相当慢的方法。考虑 fread()
:
size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
- 您必须确保您的
fopen()
文件成功;如果没有,return NULL
(或终止程序)。您的 fgetc()
电话也是如此。
- 您没有检查是否已到达缓冲区的边缘,因此可能会溢出缓冲区。
- 将大量数据放在 stack 上不是一个好主意。
read()
是一个过于通用的名称;更加详细一些。此外,该名称可能与 Linux、MacOS 和其他类 Unix 操作系统上的 typical system call of the same name 冲突。
我是 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]='[=10=]';
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];
.
这会导致第二个问题,即您要返回一个指向局部变量的指针。该指针在函数 returns 时失效,因此尝试使用它会触发 undefined behavior.
您应该改为动态分配内存:
char *text = malloc(1000);
所以函数returns时仍然有效。请记住,当您使用完内存后,您将需要 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;
}
问题的症结在于:存储这些字符的内存 space 在哪里?并且 - 谁可以在你的函数 returns 之后使用?具体来说,当你的函数再次被调用时会发生什么?
现在(忽略你有一个指针数组的事实),你正在 return 获取局部变量的地址,正如@dbush 指出的那样。这意味着:
- 只有您的函数可以使用内存中的 space。
- 离开该功能后将停止使用...
- ...并且相同的地址可能会被编译器分配给程序中的其他用途。
@dbush 的建议是解决该问题的一种方法:您的函数可以在每次调用时分配内存,并返回指向该分配内存的指针。
另一种方法是更改函数的签名,以便由调用者提供内存 space,例如:
int read_entire_file(char* destination_buffer, const char *filename);
在这两种情况下,还有另一个问题,即 1000 个字符的限制(或者更确切地说,999 个字符和尾随的 '\0',它标志着字符串的结尾)。如果文件中有更多数据怎么办?也许您实际上也应该采用缓冲区的大小?:
int read_entire_file(char* destination_buffer, size_t buffer_size, const char *filename);
除了我建议的方法和@dbush 的建议之外,还有其他替代方法,但我的观点是,完成此任务的方法不止一种。
其他comments/issues:
- 不要将文件名作为非成本指针(
char*
);让它const char* filename
澄清你不能更改文件名。 fgetc()
是一种从文件中读取数据的相当慢的方法。考虑fread()
:size_t fread(void *ptr, size_t size, size_t nmemb, FILE *stream);
- 您必须确保您的
fopen()
文件成功;如果没有,returnNULL
(或终止程序)。您的fgetc()
电话也是如此。 - 您没有检查是否已到达缓冲区的边缘,因此可能会溢出缓冲区。
- 将大量数据放在 stack 上不是一个好主意。
read()
是一个过于通用的名称;更加详细一些。此外,该名称可能与 Linux、MacOS 和其他类 Unix 操作系统上的 typical system call of the same name 冲突。