从函数返回char *

时间:2013-01-17 12:39:06

标签: c++

以下是3个功能。 main()按预期打印出来。 现在,在mycharstack()中,字符串存储在堆栈中我猜,因为“ch”超出范围,它应该不能返回字符串。它是如何正常工作的? 我想存储在mychar()中的字符串也在堆栈上。它应该正常工作吗? 我猜在代码和内存泄漏中还有其他错误,如果有的话请告诉我。我可以做这些清洁&使用std :: string更容易。但我想了解char *会发生什么。

#include <iostream>
using namespace std;

char* mychar()
{
    return "Hello";
}

char* mycharstack()
{
    char* ch = "Hello Stack";
    return ch;
}

char* mycharheap()
{
    char* ch = new char;
    ch = "Hello Heap";
    return ch;
}

int main()
{
    cout << "mychar() = " << mychar() << endl;
    cout << "mycharstack() = " << mycharstack() << endl;
    cout << "mycharheap() = " << mycharheap() << endl;

    system("PAUSE");
    return 0;
}

7 个答案:

答案 0 :(得分:17)

在C ++中,字符串处理不同于例如pascal。

char* mycharheap()
{
    char* ch = new char;
    ch = "Hello Heap";
    return ch;
}

以下是:

  1. char* ch = new char;为一个字符创建内存,并将其分配给变量ch
  2. ch = "Hello Heap";分配给只读内存的变量ch指针,其中包含字节"Hello Heap\0"。此外,变量ch的原始内容将丢失,从而导致内存泄漏。
  3. return ch;返回存储到变量ch的指针。
  4. 你可能想要的是

    char* mycharheap()
    {
        char* ch = new char[11] /* 11 = len of Hello Heap + 1 char for \0*/;
        strcpy(ch, "Hello Heap");
        return ch;
    }
    

    请注意strcpy - &gt;你有ch的内存,它有11个字符的空间,而你是从内存的只读部分用字符串填充它。

    在这种情况下会有泄漏。您需要在写完后删除内存,例如:

    char* tempFromHeap = mycharheap();
    cout << "mycharheap() = " << tempFromHeap << endl;
    delete[] tempFromHeap;
    

    但是,我高度不建议这样做(在被叫方中分配内存并在调用方中删除)。对于这种情况,例如,有STL std::string,另一个常见且更合理的方法是在调用者中分配,传递给被调用者,用结果“填充”内存,并再次在调用者中释放。

    将导致未定义行为的原因如下:

    char* mycharstack()
    {
        char[] ch = "Hello Heap"; /* this is a shortcut for char[11] ch; ch[0] = 'H', ch[1] = 'e', ...... */
        return ch;
    }
    

    这将在堆栈上创建带有字节"Hello Heap\0"的数组,然后尝试返回指向该数组的第一个字节的指针(可以在调用函数中指向任何内容)

答案 1 :(得分:2)

  

在mycharstack()中,字符串存储在堆栈中我猜,因为“ch”超出范围,它应该不能返回字符串。它是如何正常工作的?

字符串文字是指存在于静态内存中的数组。我希望你知道三个内存区域:自动内存(也称为堆栈),免费存储(又名堆)和静态内存。堆栈上的东西只是一个指针变量,你可以按值返回指针的值(它存储的地址)。所以一切都很好,除非你应该使用const char*作为指针类型,因为你不允许修改字符串文字引用的数组。

  

我猜存储在mychar()中的字符串也在堆栈上。

字符串(字符数组)存储在静态存储器中。 char*只是一种可用于传递地址的指针类型。 const也不见了。

  

我猜在代码和内存泄漏中还有其他错误,如果有的话请告诉我。

泄漏是你的第三个功能。您只为堆上的一个字符分配内存,并将其地址存储到名为ch的变量中。使用以下分配,您可以使用字符串文字的地址覆盖此地址。所以,你正在泄露记忆。

您似乎将char*视为字符串变量的类型。但事实并非如此。它是指向字符或字符序列的指针的类型。它可能指向的指针和字符串是两个单独的东西。你应该在这里使用的是std :: string。

答案 2 :(得分:1)

您的代码中只有泄漏的char没有错误。但这很奇怪。

char* mycharheap()
{
    char* ch = new char; //creates a pointer that points to a new char in the heap
    ch = "Hello Heap";   //overwrites the pointer with const char - but this cast is legal.
                         //note: pointer to the previous char is lost
    return ch;           //return the pointer to the constant area where "Hello heap" is stored.
                         //no, "Hello heap" is not on the heap.
}

对于“你想要什么:”部分,约塞连比我快。

答案 3 :(得分:1)

首先,如果您使用的是C ++,请使用std::string来表示字符串。

现在回答你的问题。 char*是指向char(或char s的数组)的指针。字符串文字(引号中的东西)是char数组类型的只读对象,存储在某种只读内存中(既不在堆栈上也不在堆上)。

由于char*是指针,因此分配指针会更改指针。所以mychar()mycharstack()都返回一个指向存储在只读内存中的字符串文字的指针。

mycharheap()只是泄密。您使用char在堆上分配一个new char,然后忘记其地址并返回指向字符串文字的指针。我想你的意思是:

char* mycharheap() {
  char* ch = new char[strlen("Hello Heap") + 1];
  strcpy(ch, "Hello Heap");
  return ch;
}

然而,要重新迭代,不要在C ++中使用char*作为字符串。使用std::string

答案 4 :(得分:0)

函数mycharheap()正在泄漏:您使指针指向堆上分配的一个char长度的内存区域,然后修改该指针以指向字符串文字,即存储在只读存储器中。分配的内存不会被释放。

答案 5 :(得分:0)

以下示例是我在尝试从函数调用中输入和输出信息时出现的问题。

#include <iostream>
#include <cstring>
using namespace std;

char* Xout(char* message);

int main()
{
const int LEN = 64;
char message[LEN], *x;

cin>>message;

x=Xout(message);
cout<<x;
return 0;
}

char* Xout(char* message)
{
int length=strlen(message);
for(int i = 0; i < length; i++)
{
    message[i] = 'X';
}
return message;
}

答案 6 :(得分:0)

const char* mychar_readonly() {
    // each time it returns the same pointer to char array in Read-Only memory
    return "Hello Read-Only";
}

int main() {
    const char* s1 = mychar_readonly();
    const char* s2 = mychar_readonly();
    // it will print the same addresses
    // e.g s1: 0x100000f87, s2: 0x100000f87
    printf("s1: %p, s2: %p\n", s1, s2);
    return 0;
}