简体   繁体   English

如何将 const char* 从函数转移到函数?

[英]How do I transfer const char* from function to function?

Here is an example of what I am trying to do:这是我正在尝试做的一个例子:

#include <stdio.h>

FILE* f;
const char* getstring()
{
    f = fopen ("hello.txt", "r");
    char x[200];
    for (int i = 0; i < 200; i++) x[i] = 0;
    for (int c = getc(f), i = 0; (c != EOF) && (i < 200); c = getc(f), i++)
        x[i] = c;
    fclose(f);
    printf ("getstring(): x = %s", x);
    const char* y = x;
    printf ("getstring(): y = %s", y);
    return y;
}

void printstring (const char* string)
{
    printf ("%s", string);
}

int main()
{
    printstring(getstring());
    printf ("\nprintf: %s", getstring());
    return 0;
}

and the output is:输出是:

getstring(): x = Hello World
getstring(): y = Hello World
���getstring(): x = Hello World
getstring(): y = Hello World

printf: ��������

I don't know why the printstring() function is outputting nothing and printf is outputting random data or why there is a bit of random data at the end of the string when I use the printstring() function.我不知道为什么printstring()函数不输出任何内容而printf输出随机数据,或者为什么当我使用printstring()函数时string末尾有一些随机数据。

Is there any way to fix this and what am I doing wrong?有什么办法可以解决这个问题,我做错了什么?

The problem问题

The problem is that getstring() returns a pointer to a local array.问题是getstring()返回一个指向本地数组的指针。 This array gets destructed when the function returns, so you have an dangling pointer.这个数组在函数返回时被破坏,所以你有一个悬空指针。 Using this pointer is then undefined behavior.使用这个指针是未定义的行为。 Anything can happen: for example you can get garbage random value, you can get the old unchanged value, or the system could crash.任何事情都可能发生:例如,您可以获得垃圾随机值,您可以获得旧的未更改值,或者系统可能崩溃。

The solution解决方案

Since this question is labelled c++, just use std::string instead of char* , and this kind of nightmare will vanish for good.由于这个问题被标记为 c++,只需使用std::string而不是char* ,这种噩梦就会消失。

Note that Using std::string in prinf() would require you get a pointer with .c_str() .请注意,使用std::stringprinf()会要求你得到一个指向与.c_str()

If for an obscure reason, you are required to use char* you'd have to to use strdup() or llocate some memory for the c string and return a pointner to that memory.如果出于某种晦涩的原因,您需要使用char* ,则必须使用strdup()或为 c 字符串分配一些内存并返回指向该内存的指针。 But the caller must then delete this pointer if you don't want memory to leak.但是如果你不想内存泄漏,调用者必须删除这个指针。

The C string is stored in a function local char array. C 字符串存储在函数本地字符数组中。 This array is destroyed when the function is left.当函数离开时,这个数组被销毁。 Since the question is tagged as C++ use std::string由于问题被标记为 C++ 使用 std::string

#include <iostream>
#include <string>
#include <fstream>

std::string getstring()
{
    std::ifstream f("hello.txt");
    std::string x;
    x.resize(200);
    for (int i = 0; i < 200; i++) x[i] = 0;
    for (int c = f.get(), i = 0; (c != EOF) && (i < 200); c = f.get(), i++)
        x[i] = c;
    std::cout << "getstring(): x = " << x;
    const std::string& y = x;
    std::cout << "getstring(): y = " << y;
    return x;
}

void printstring (const std::string& string)
{
    std::cout << string;
}

int main()
{
    printstring(getstring());
    std::cout << "\nprintf: " << getstring();
    return 0;
}

Since others have explained how to go about resolving the issue, I'll expand the other answers a bit and explain why you had an issue in the first place.由于其他人已经解释了如何解决问题,因此我将扩展其他答案并首先解释您为什么遇到问题。

To put it simply, whenever a function is called, it is given a stack frame (also called activation record ) of its own.简单地说,每当一个函数被调用时,它都会被赋予一个自己的堆栈帧(也称为活动记录)。 That is to say: it is given an area of memory where it can place its local variables.也就是说:它被赋予了一块内存区域,它可以在其中放置它的局部变量。 When the function returns, the stack frame is destroyed.当函数返回时,栈帧被销毁。 If you then call another function, the stack frame of that function overwrites the stack frame of the previous function.如果随后调用另一个函数,该函数的堆栈帧将覆盖前一个函数的堆栈帧。

In this specific case, when getstring returns and printstring and subsequently printf are called, the stack frames of the latter two along with that of main overwrite the data that was previously located within the stack frame of getstring .在该特定情况下,当getstring回报和printstring和随后printf是所谓的,后两者与该沿着堆栈帧main重写先前位于的堆栈帧中的数据getstring The most likely result is that printf will output complete junk.最可能的结果是printf将输出完整的垃圾。 In the worst case, it can make the entire program crash if the null terminator of the string was overwritten.在最坏的情况下,如果字符串的空终止符被覆盖,它会导致整个程序崩溃。

It is also interesting to note that in your case it seems that a binary value corresponding with that of the null terminator \\0 was inserted somewhere, because only a bit of junk is printed before printf returns.还有趣的是,在您的情况下,似乎在某处插入了与空终止符\\0对应的二进制值,因为在printf返回之前只打印了一点垃圾。 This would indicate that it did not stop at the original null terminator of the character array x but rather encountered a value it interpreted as the null terminator and returned.这表明它没有在字符数组x的原始空终止符处停止,而是遇到了一个被它解释为空终止符并返回的值。

If you wish, you can read more about the call stack on Wikipedia .如果您愿意,可以在 Wikipedia 上阅读有关调用堆栈的更多信息。

This is the answer for C code (not C++).这是 C 代码(不是 C++)的答案。 In the code in NPE 's answer on the similar question that I found at this link , which I didn't find before I posted this question, I found the malloc(bytes) function does the trick but if you compile with gcc , you have to have to convert the malloc function as a char* manually by using (char*) malloc (bytes) .在我在此链接上找到的类似问题的NPE回答中的代码中,我在发布此问题之前没有找到,我发现malloc(bytes)函数可以解决问题,但是如果您使用gcc编译,您必须使用(char*) malloc (bytes)手动将 malloc 函数转换为 char* 。 I also found that because it's using pointers you will have to treat the allocated string as a global variable when you free() it.我还发现,因为它使用指针,所以当您free()时,您必须将分配的字符串视为全局变量。 Here is an example of the working code based on the code in my question:这是基于我的问题中的代码的工作代码示例:

#include <stdio.h>
#include <stdlib.h>

FILE* f;
char* getstring()
    {
    f = fopen ("hello.txt", "r");
    char* x = (char*) malloc (200);
    int length = 0;
    for (int i = 0; i < 200; i++) x[i] = 0;
    for (int c = getc(f), i = 0; (c != EOF) && (i < 200); c = getc(f), i++)
        { x[i] = c; length++; }
    fclose(f);
    return x;
    }

void printstring (char* string)
    {
    printf ("%s", string);
    free (string);
    }

int main()
    {
    printstring(getstring());
    return 0;
    }

And this outputs the exact first 200 bytes of "hello.txt".这将输出“hello.txt”的前 200 个字节。

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

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