从函数返回char*

Return char* from function

本文关键字:char 返回 函数      更新时间:2023-10-16

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

在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"。另外,变量ch的原始内容丢失,导致内存泄漏。
  3. return ch;返回指向变量ch的指针。

你可能想要的是

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

注意strcpy ->你在ch中有内存,有11个字符的空间,并且你正在从内存的只读部分用字符串填充它。

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

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

然而,我强烈建议不这样做(在callee中分配内存,在caller中删除内存)。对于这种情况,有,例如,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"字节的数组,然后尝试返回指向该数组第一个字节的指针(在调用函数时,该指针可以指向任何值)

在mycharstack()中的字符串存储在堆栈上,我猜,所以当"ch"超出范围时,它不应该能够返回字符串。它是如何正确工作的?

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

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

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

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

泄漏在第三个函数中。您只需为堆上的一个字符分配内存,并将其地址存储到名为ch的变量中。使用下面的赋值操作,可以用字符串字面值的地址覆盖此地址。所以,你在泄漏内存。

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

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

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

由于char*是指针,对其赋值会改变指针。因此,mychar()mycharstack()都返回一个指针,指向存储在只读内存中的字符串字面值。

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

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

然而,重申一下,不要在c++中对字符串使用char*。使用std::string

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

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

在"What you want:"部分,尤塞连比我快。

下面的例子是当我试图从函数调用中提取信息时出现的一个问题。

#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;
}
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: %pn", s1, s2);
    return 0;
}