简体   繁体   English

C基本字符串返回函数

[英]C Basic String Return Function

I'm still pretty new to C. I still don't understand everything with pointers at all. 我对C还是很陌生。我仍然对指针一无所知。 I'm trying to make a method that returns a String. 我试图做一个返回String的方法。 Here's the function, it's still incomplete. 这是功能,仍然不完整。

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);
}

and I'm trying to call the method like this 我试图像这样调用方法

char *article = getS("articles.txt");
char *noun = getS("nouns.txt");
char *verb = getS("verbs.txt");

The compiler is giving me this: 编译器给我这个:

error: invalid type argument of unary ‘*’ (have ‘int’)

What should I do? 我该怎么办?

The following is probably going to be a lot more information than you're looking for. 以下信息可能会比您想要的要多得多。 Don't worry too much about absorbing it all now, but you're likely to need it later. 不必太担心现在就吸收它,但是以后可能会需要它。

First, an important note about terminology. 首先,有关术语的重要说明。 C has no "string" type. C没有“字符串”类型。 Quoting the ISO C standard: 引用ISO C标准:

A string is a contiguous sequence of characters terminated by and including the first null character. 字符串是由第一个空字符终止并包括第一个空字符的连续字符序列。 [...] A pointer to a string is a pointer to its initial (lowest addressed) character. [...] 指向字符串的指针是指向其初始(最低寻址)字符的指针。

In particular, a char* value is a pointer, not a string (though we generally use char* pointers to access and manipulate strings). 特别是, char*值是一个指针, 而不是字符串(尽管我们通常使用char*指针来访问和操作字符串)。 Even an array is not itself a string, though it can contain a string. 即使数组本身也可以不是字符串,尽管它可以包含字符串。

For your (relatively simple) function, the char* value that you're returning points to (the first character of) a string literal, so memory management is not an issue. 对于您的(相对简单的)函数,您要返回的char*值指向字符串文字(的第一个字符),因此内存管理不是问题。 For more complicated cases, the language is frankly not particularly helpful, and you'll have to do some work to manage memory yourself. 坦率地说,对于更复杂的情况,该语言并不是特别有用,您必须自己做一些工作来管理内存。

A function can easily return a char* value that points to a string, allowing the caller to do what it likes with that string -- but where are the characters that make up that string stored? 函数可以轻松地返回指向字符串的char*值,从而使调用者可以对该字符串进行操作,但是构成该字符串的字符存储在哪里?

There are (at least) three common approaches. 有(至少)三种常见方法。

(1) The function return a pointer to the beginning of a static array of char : (1)该函数返回一个指向char 静态数组开头的指针:

char *func(void) {
    static char result[100];
    // copy data into result
    return result;
}

This works, but it has some drawbacks. 这行得通,但是有一些缺点。 There's only one copy of the result array, and successive calls to func() will clobber the contents of that array. result数组只有一个副本,对func()连续调用将破坏该数组的内容。 And the array has a fixed size; 数组的大小是固定的; it has to be big enough to hold the largest string it can ever return. 它必须足够大以容纳它可以返回的最大字符串。 The standard C asctime() function works this way. 标准的C asctime()函数以这种方式工作。

(2) The caller can pass in a pointer to a string, and let the function fill it in: (2)调用者可以传递一个指向字符串的指针,然后让函数将其填充:

void func(char *buffer) {
    // code to copy data into the array pointed to by buffer
}

This places a burden on the caller, which has to allocate an array of char , and in particular has to know how big it needs to be. 这给调用方带来了负担,该调用方必须分配一个char数组,尤其是必须知道它需要多大。

(3) The function can allocate memory for the string using malloc() : (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;
}

This has the advantage that the function can decide how much memory it needs to allocate. 这样做的好处是该函数可以决定需要分配多少内存。 But the caller has to be aware that the string was allocated on the heap, so it can later release it by calling free() . 但是调用者必须知道该字符串是在堆上分配的,因此以后可以通过调用free()释放它。 The malloc() and free() functions can also be relatively expensive (but don't worry about that unless you're sure that your program's performance isn't good enough). malloc()free()函数也可能相对昂贵(但不要担心,除非您确定程序的性能不够好)。

Actually, there's a fourth method, but it's wrong : 实际上,有第四种方法,但这是错误的

char *bad_func(void) {
    char result[100];
    // copy data into result
    return result; // equivalent to "return &result[0];"
}

The problem here is that result is local to the function, and is not defined as static , so the array object ceases to exist as soon as the function returns. 这里的问题是result在函数中是局部的,并且没有定义为static ,因此一旦函数返回,数组对象就不再存在。 The caller will receive a pointer to memory that is no longer reserved, and that can be re-used behind your back. 调用方将收到一个指向不再保留的内存的指针,该指针可以在您的背后重复使用。 You can return a pointer to a local static object (because the single copy exists for the lifetime of the program), and you can return the value of a local non- static object, but you can't safely return the address of a local non- static object. 您可以返回指向本地static对象的指针(因为在程序生命周期中存在单个副本),并且可以返回本地非static对象的 ,但是您不能安全地返回本地的地址static对象。

The comp.lang.c FAQ is an excellent resource. comp.lang.c FAQ是一个很好的资源。

Your function should return a char * (a string), instead of a char, and it should return the same. 您的函数应该返回一个char *(一个字符串),而不是一个char,并且它应该返回相同的值。 So the function becomes: 因此该函数变为:

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;
}

It all depends if your string has a constant size or not. 这完全取决于您的字符串是否具有恒定大小。 Normally people use buffer parameters for such functions, because if you allocate the string memory space inside the function, and return a pointer to it, then you'd have to free the memory outside the function, and if not done so, you'd have a memory leak by losing the memory reference. 通常,人们会为此类函数使用缓冲区参数,因为如果您在函数内部分配字符串存储空间,并返回指向该函数的指针,那么您将必须在函数外部释放内存,如果不这样做,您将丢失内存引用会导致内存泄漏。

So the best approach for functions that return strings, is something like this: 因此,返回字符串的函数的最佳方法是这样的:

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);
}

Then you'd use it like this: 然后,您将像这样使用它:

char content[512];
getS("example.txt", content, 512);
// From now, you can use 'content' safely

Or using malloc.h for dynamic allocation: 或使用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);

But it's from time you'll learn to use this correctly. 但这是从时间开始您将学会正确使用它的时间。 But if in any way you want to return a literal string (that's not your case, except for your incomplete example code), you have to use char * as the return type for the function, and return get; 但是,如果要以任何方式返回文字字符串(除了不完整的示例代码,情况并非如此),则必须使用char *作为函数的返回类型,并return get; and not *get , because with *get you're returning a character (the first one for instance), and not a pointer to the string. 而不是*get ,因为使用*get可以返回一个字符(例如第一个字符),而不是指向字符串的指针。

FrankieTheKneeMan's answer is very useful for you to understand what you were returning and why your code was not working... FrankieTheKneeMan的答案对于您了解返回的内容以及代码为何不起作用非常有用。

The type of getS is char but you're assigning it to variables of type char* . getS的类型为char但您将其分配给char*类型的变量。 Presumably you want getS to return a string, so its type should be char* , and you should return get rather than *get (which is just the first character at get ). 大概您希望getS返回一个字符串,所以它的类型应该是char* ,并且应该返回get而不是*get (这只是get的第一个字符)。

A pointer in C is the address of some other piece of information. C中的指针是其他一些信息的地址。 C comes with two unary operators to deal with that. C带有两个一元运算符来处理。

*

dereferences pointers - or gets the information at the memory space that is being pointed at. 解引用指针-或在指向的内存空间中获取信息。

&

Gets the address of the information You're talking about, so: 获取您正在谈论的信息的地址,因此:

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

So, when you declare your char * get , you're declaring "a pointer to a char" - and C knows that by convention it can be treated as an array of chars. 因此,当您声明char * get ,即是在声明“指向char的指针”-C知道,按照惯例,它可以视为char数组。 However, when you attempt to return * get , C thinks you're trying to return the char at the memory addressed by get . 但是,当您尝试return * get ,C认为您正在尝试通过get寻址的内存返回char。

So instead, return get , and you'll return the pointer you're looking for. 因此, return get ,您将返回要查找的指针。

Did that demystify the almighty pointer for you? 这是否使全能指针神秘化?

(Aside: You may want to malloc that char * to avoid the pointer being cleared by the stack memory, but that's a different problem altogether). (此外:您可能希望对char *进行malloc分配,以避免指针被堆栈存储器清除,但这是另一个完全不同的问题)。

声明:本站的技术帖子网页,遵循CC BY-SA 4.0协议,如果您需要转载,请注明本站网址或者原文地址。任何问题请咨询:yoyou2525@163.com.

 
粤ICP备18138465号  © 2020-2024 STACKOOM.COM