Подтвердить что ты не робот

Возврат char * из функции

Ниже приведены 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;
}
4b9b3361

Ответ 1

В С++ обработка строк отличается от, например, pascal.

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

Это означает следующее:

  • char* ch = new char; создает память для ОДНОГО символа и присваивает ее переменной ch
  • ch = "Hello Heap"; присваивает переменной ch указатель на память только для чтения, которая содержит байты "Hello Heap\0". Кроме того, исходное содержимое переменной ch теряется, что приводит к утечке памяти.
  • 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, другой общий и более разумный подход выделяет в вызывающем абоненте, переходя к вызываемому, который "заполняет" память с результатом и снова освобождается от вызывающего.

Что приведет к следующему поведению undefined:

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", а затем попытается вернуть указатель на первый байт этого массива (который может в функции вызова указать на что-либо)

Ответ 2

в mycharstack() строка хранится в стеке, я думаю, так как "ch" выходит за пределы области видимости, она не должна возвращать строку. Как это работает правильно?

Строковый литерал относится к массиву, который находится в статической памяти. Надеюсь, вы знаете о трех областях памяти: автоматической памяти (aka stack), бесплатном хранилище (aka heap) и статической памяти. Эта вещь в стеке - это просто переменная указателя, и вы возвращаете значение указателя (адрес, который он хранит) по значению. Итак, все в порядке, за исключением того факта, что вы должны использовать const char* как тип указателя, потому что вам не разрешено изменять массив, на который ссылается строковый литерал.

Я думаю, что строка, хранящаяся в mychar(), также находится в стеке.

Строка (массив символов) хранится в статической памяти. char* - это просто тип указателя, который вы можете использовать для передачи адресов. const также отсутствует.

Я думаю, что есть другие ошибки в утечке кода и памяти, пожалуйста, дайте мне знать, если они есть.

Утечка в третьей функции. Вы выделяете память только для одного символа в куче и сохраняете ее адрес в переменной с именем ch. При следующем назначении вы переписываете этот адрес по адресу строкового литерала. Итак, вы теряете память.

Кажется, вы думаете о char* как type для строковых переменных. Но это не так. Это тип для указателя на символ или последовательность символов. Указатель и строка, на которые он указывает, являются двумя отдельными вещами. Вместо этого вы, вероятно, должны использовать std::string.

Ответ 3

В вашем коде нет ошибок только утечка 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.
}

Для части "Что вы хотите:" Йоссариан был быстрее меня.

Ответ 4

Во-первых, если вы используете С++, используйте 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;
}

Тем не менее, для повторного итерации не используйте char* для строк в С++. Используйте std::string.

Ответ 5

Функция mycharheap() протекает: вы указываете точку указателя на область памяти длиной 1 char, выделенную в куче, а затем вы изменяете этот указатель, чтобы указать на строковый литерал, который хранится в read- только память. Выделенная память не будет освобождена.

Ответ 6

Пример ниже был вопросом, который возник, когда я пытался извлечь информацию из вызова функции.

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