Возврат 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;
}
Ответы
Ответ 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;
}