Поскольку я не могу вернуть локальную переменную, каков наилучший способ вернуть строку из C или C ++?

В качестве продолжения этого вопроса :

Из того, что я видел, это должно работать так, как ожидалось:

void greet(){ char c[] = "Hello"; greetWith(c); return; } 

но это приведет к неопределенному поведению:

 char *greet(){ char c[] = "Hello"; return c; } 

Если я прав, что лучший способ исправить вторую функцию приветствия? Во встроенной среде? На рабочем столе?

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

  printf("%s\n",greet()); 

вы получите странные результаты, потому что вызов printf повторно использовал бы часть вашего массива.

Решение состоит в том, чтобы выделить память в другом месте. Для примера:

 char c[] = "Hello"; char * greet() { return c; } 

Должно сработать. Другим вариантом было бы распределить его статически по охвату:

 char * greet() { static char c[] = "Hello"; return c; } 

потому что статическая память выделяется отдельно от стека в пространстве данных.

Ваш третий выбор – выделить его в кучу через malloc:

 char * greet() { char * c = (char *) malloc(strlen("Hello")+1); /* +1 for the null */ strcpy(c, "Hello"); return c; } 

но теперь вы должны убедиться, что память каким-то образом освобождена, или же у вас есть утечка памяти.

Обновить

Одна из тех вещей, которые кажутся более запутанными, чем я ожидаю, – это именно «утечка памяти». Утечка – это когда вы распределяете память динамически, но теряете адрес, чтобы он не мог быть освобожден. Ни один из этих примеров не обязательно имеет утечку, но только третий, даже потенциально, имеет утечку, поскольку он является единственным, который динамически распределяет память. Итак, принимая третью реализацию, вы можете написать этот код:

 { /* stuff happens */ printf("%s\n", greet()); } 

У этого есть утечка; возвращается указатель на память malloc’а, printf использует его, а затем он потерян; вы больше не можете его освобождать. С другой стороны,

 { char * cp ; /* stuff happens */ cp = greet(); printf("%s\n", cp); free(cp); } 

не течет, потому что указатель сохраняется в автоматической переменной cp достаточно долго, чтобы вызвать free() на нем. Теперь, несмотря на то, что cp исчезает, как только выполнение проходит, он заканчивает скобки, так как свободен вызван, память исправлена ​​и не просачивается.

Если вы используете C ++, вам может потребоваться использовать std::string для возврата строк из вашей второй функции:

 std::string greet() { char c[] = "Hello"; return std::string(c); // note the use of the constructor call is redundant here } 

Или в однопоточной среде вы можете:

 char *greet() { static char c[] = "Hello"; return c; } 

static здесь выделяет пространство в глобальной области памяти, которое никогда не исчезает. Однако этот static метод чреват опасностью.

Зависит, если встроенная среда имеет кучу или нет, если это так, вы должны malloc следующим образом:

 char* greet() { char* ret = malloc(6 * sizeof(char)); // technically " * sizeof(char)" isn't needed since it is 1 by definition strcpy(ret,"hello"); return ret; } 

Обратите внимание, что позже вы должны вызвать free () для очистки. Если у вас нет доступа к динамическому распределению, вам нужно сделать его глобальным или переменным в стеке, но дальше вверх по стеку вызовов.

Если вам нужно сделать это на C ++, использование std::string предложенное Грегом Хьюджиллом, безусловно, является самой простой и поддерживаемой страtagsей.

Если вы используете C, вы можете подумать о возврате указателя на пространство, которое было динамически распределено с помощью malloc() как было предложено Джесси Пеппер; но другим способом, который может избежать динамического распределения, является получение greet() помощью параметра char * и запись его вывода там:

 void greet(char *buf, int size) { char c[] = "Hello"; if (strlen(c) + 1 > size) { printf("Buffer size too small!"); exit(1); } strcpy(buf, c); } 

Параметр size существует для безопасности, чтобы предотвратить переполнение буфера. Если бы вы точно знали, как долго будет эта строка, это было бы необязательно.

Вы можете использовать любой из них:

 char const* getIt() { return "hello"; } char * getIt() { static char thing[] = "hello"; return thing; } char * getIt() { char str[] = "hello"; char * thing = new char[sizeof str]; std::strcpy(thing, str); return thing; } shared_array getIt() { char str[] = "hello"; shared_array thing(new char[sizeof str]); std::strcpy(thing.get(), str); return thing; } 

Первое требует, чтобы вы не записывали в возвращаемую строку, но также и простейший, который вы можете получить. Последнее использует shared_array, который автоматически может очищать память, если ссылка на память потеряна (последний shared_array для нее выходит за frameworks). Последнее и второе последние должны использоваться, если вам требуется новая строка при каждом вызове функции.

Возврат памяти malloc’d из функции, предложенной несколькими другими ответами, просто требует утечки памяти. Вызывающий должен был бы знать, что вы malloc’d, а затем позвоните бесплатно. Если они вызвали удаление на нем, результаты не определены (хотя, вероятно, все в порядке).

Было бы лучше заставить вызывающего обеспечить память для вас, а затем скопировать в нее строку. Таким образом, вызывающий абонент уведомляется о необходимости его очистки.

Из того, что я прочитал, самый безопасный вариант – сделать вызывающего абонента ответственным за выделение памяти для хранения строки. Вы также должны проверить, достаточно ли достаточно буфера для хранения строки:

 char *greet(char *buf, int size) { char *str = "Hello!" if (strlen(str) + 1 > size) { // Remember the terminal null! return NULL; } strcpy(buf, str); return buf; } void do_greet() { char buf[SIZE]; if (greet(buf, SIZE) == NULL) { printf("Stupid C"); } else {} // Greeted! } 

Тон работы для простой задачи … но для вас есть C 🙂 Упс! Думаю, я был избит random_hacker …

Выделить массив символов в куче?

Можете ли вы использовать malloc или нет, зависит только от того, что вы подразумеваете под «встроенной средой».

  • Почему Dropbox использует так много памяти в Linux?
  • Как вы получаете общий объем оперативной памяти компьютера?
  • Инструмент для разметки больших файлов
  • Установка двух папок RAM вызывает проблемы; Используя только один из них, нет?
  • iPhone - dealloc - Релиз против нуля
  • Настройка памяти программ Java, выполняемых с Eclipse
  • Как я могу отслеживать и регистрировать использование процессора и памяти на Mac?
  • Почему dwm.exe использует столько памяти?
  • stringstream, string и char * ошибка конверсии
  • Chrome. Как восстановить текст в текстовых полях?
  • Что происходит, когда ОС Linux из ОЗУ и без обмена
  • Давайте будем гением компьютера.