C基本字符串返回函数
我仍然是C的新手。我仍然不了解指针。 我正在尝试创建一个返回String的方法。 这是function,它仍然不完整。
char getS(char *fileName){ FILE *src; if((src = fopen(fileName, "r")) == NULL){ printf("%s %s %s", "Cannot open file ", fileName, ". The program is now ending."); exit(-1); } char *get = " "; //insert getting a random word here return(*get); }
而我正试着这样调用这个方法
char *article = getS("articles.txt"); char *noun = getS("nouns.txt"); char *verb = getS("verbs.txt");
编译器给我这个:
error: invalid type argument of unary '*' (have 'int')
我该怎么办?
你的函数应该返回一个char *(一个字符串),而不是一个char,它应该返回相同的。 所以function变成:
char * getS(char *fileName) { FILE *src; if((src = fopen(fileName, "r")) == NULL) { printf("%s %s %s", "Cannot open file ", fileName, ". The program is now ending."); exit(-1); } char *get = " "; //insert getting a random word here return get; }
以下可能比您正在寻找的信息要多得多。 现在不要太担心吸收它,但是你可能以后需要它。
首先,关于术语的重要说明。 C没有“字符串”类型。 引用ISO C标准:
字符串是由第一个空字符终止并包括第一个空字符的连续字符序列。 […] 指向字符串的指针是指向其初始(最低寻址)字符的指针。
特别是, char*
值是一个指针, 而不是一个字符串(尽管我们通常使用char*
指针来访问和操作字符串)。 即使数组本身也不是字符串,但它可以包含字符串。
对于(相对简单的)函数,您返回的char*
值指向字符串文字的(第一个字符),因此内存管理不是问题。 对于更复杂的情况,这种语言坦率地说并不是特别有用,你必须自己做一些工作来管理记忆。
函数可以轻松返回指向字符串的char*
值,允许调用者使用该字符串执行它喜欢的操作 – 但组成该字符串的字符存储在哪里?
有(至少)三种常见方法。
(1)函数返回一个指向char
的静态数组开头的指针:
char *func(void) { static char result[100]; // copy data into result return result; }
这有效,但它有一些缺点。 result
数组只有一个副本,对func()
连续调用将破坏该数组的内容。 并且arrays具有固定的大小; 它必须足够大才能容纳它能够返回的最大字符串。 标准的C asctime()
函数以这种方式工作。
(2)调用者可以传入指向字符串的指针,并让函数填充它:
void func(char *buffer) { // code to copy data into the array pointed to by buffer }
这给调用者带来了负担,调用者必须分配一个char
数组,特别是必须知道它需要多大。
(3)该函数可以使用malloc()
为字符串分配内存:
char *func(void) { char *result = malloc(some_number); if (result == NULL) { // allocation failed, cope with the error } // copy data into the array pointed to by result return result; }
这样做的好处是函数可以决定需要分配多少内存。 但是调用者必须知道字符串是在堆上分配的,所以它可以稍后通过调用free()
来释放它。 malloc()
和free()
函数也可能相对昂贵(但除非你确定你的程序性能不够好,否则不要担心)。
实际上,还有第四种方法,但这是错误的 :
char *bad_func(void) { char result[100]; // copy data into result return result; // equivalent to "return &result[0];" }
这里的问题是result
是函数的局部result
,并且没有定义为static
,所以一旦函数返回,数组对象就不再存在。 调用者将收到一个指向不再保留的内存的指针,并且可以在您的背后重复使用。 您可以返回指向本地static
对象的指针(因为在程序的生命周期中存在单个副本),并且您可以返回本地非static
对象的值 ,但是您无法安全地返回本地的地址非static
对象。
comp.lang.c FAQ是一个很好的资源。
这完全取决于你的字符串是否有一个恒定的大小。 通常人们会为这些函数使用缓冲区参数,因为如果你在函数内部分配字符串内存空间,并返回指向它的指针,那么你必须释放函数外的内存,如果没有这样做,你就会丢失内存引用导致内存泄漏。
因此,返回字符串的函数的最佳方法是这样的:
void getS(char *fileName, char *output, size_t len) { FILE *src; if((src = fopen(fileName, "r")) == NULL) { printf("Cannot open file '%s'. The program is now ending.", fileName); exit(-1); } fread(output, sizeof(char), len, src); // Just an example without error checking fclose(src); }
然后你会像这样使用它:
char content[512]; getS("example.txt", content, 512); // From now, you can use 'content' safely
或者使用malloc.h
进行动态分配:
char *content = (char *)malloc(512 * sizeof(char)); getS("example.txt", content, 512); // Use 'content', and after using it, free its memory: free(content);
但是,随着时间的推移,你将学会正确使用它。 但是如果你想以任何方式返回一个文字字符串(除了你的不完整的示例代码之外不是你的情况),你必须使用char *
作为函数的返回类型,并return get;
而不是*get
,因为有*get
你返回一个字符(例如第一个),而不是指向字符串的指针。
FrankieTheKneeMan的答案非常有用,可以帮助您了解您返回的内容以及您的代码无效的原因……
getS
的类型是char
但是您将它分配给char*
类型的变量。 大概你想让getS
返回一个字符串,所以它的类型应该是char*
,你应该返回get
而不是*get
(这只是get
的第一个字符)。
C中的指针是其他一些信息的地址。 C带有两个一元运算符来处理它。
*
取消引用指针 – 或者获取指向的内存空间的信息。
&
获取您正在谈论的信息的地址,因此:
int p; int* q = &p; //int* is a pointer to an it. q==p; //Error (or at least a warning) *q == p; //true q == &p; //true *q == &p; //ERROR &q == &p; //false, but also probably an error, depending on your compiler and settings
所以,当你声明你的char * get
,你会声明“指向char的指针” – 而且C知道按惯例它可以被视为一个chars数组。 但是,当你试图return * get
,C认为你正试图在get
寻址的内存中返回char。
所以相反, return get
,你将返回你正在寻找的指针。
那揭开了全能指针的神秘面纱吗?
(旁白:你可能想要malloc
那个char *
以避免指针被堆栈内存清除,但这完全是一个不同的问题)。