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

18
задан Community 23 May 2017 в 11:59
поделиться

8 ответов

Если Вы используете 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 метод чреват опасностью, все же.

12
ответ дан 30 November 2019 в 05:48
поделиться

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

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

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

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

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'ed память возвращается, printf использование это, и затем это потеряно; Вы не можете освободить его больше. С другой стороны,

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

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

33
ответ дан 30 November 2019 в 05:48
поделиться

Зависит, если встроенная среда имеет "кучу" или нет, если так, Вы должны 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;
}

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

9
ответ дан 30 November 2019 в 05:48
поделиться

Можно использовать любой из них:

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<char> getIt() {
    char str[] = "hello";
    shared_array<char> thing(new char[sizeof str]);
    std::strcpy(thing.get(), str);
    return thing;
}

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

5
ответ дан 30 November 2019 в 05:48
поделиться

Если необходимо сделать, это в C++, с помощью std::string, как предложил Greg Hewgill является определенно самой простой и удобной в сопровождении стратегией.

при использовании C Вы могли бы полагать, что возврат указателя расположил с интервалами, который был динамично выделен с malloc(), как предложил Jesse Pepper; но иначе который может избежать, чтобы динамическое выделение имело 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 параметр там в целях безопасности, чтобы помочь предотвратить переполнение буфера. Если бы Вы знали точно, сколько времени строка была, это не было бы необходимо.

7
ответ дан 30 November 2019 в 05:48
поделиться

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

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...

1
ответ дан 30 November 2019 в 05:48
поделиться

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

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

4
ответ дан 30 November 2019 в 05:48
поделиться

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

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

0
ответ дан 30 November 2019 в 05:48
поделиться