24

下面是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;
}
4

7 回答 7

24

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

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

这会执行以下操作:

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

你可能想要的是

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

注意strcpy-> 你有内存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;
}

这将使用 bytes 在堆栈上创建数组"Hello Heap\0",然后尝试返回指向该数组的第一个字节的指针(在调用函数时,它可以指向任何东西)

于 2013-01-17T12:45:52.677 回答
4

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

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

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

字符串(字符数组)存储在静态内存中。char*只是一种指针类型,您可以使用它来传递地址。const也不见了。

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

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

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

于 2013-01-17T12:54:55.363 回答
1

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

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

作为char*一个指针,分配给它会改变指针。因此mychar()mycharstack()两者都返回一个指向存储在只读内存中的字符串文字的指针。

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

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

尽管如此,要重新迭代,不要char*在 C++ 中使用字符串。使用std::string.

于 2013-01-17T12:47:03.950 回答
0

您的代码中没有错误,只是泄露了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.
}

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

于 2013-01-17T12:43:28.343 回答
0

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

于 2013-01-17T12:42:57.750 回答
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;
}
于 2016-10-12T09:08:02.070 回答
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;
}
于 2020-12-22T20:43:56.897 回答