функция с использованием fgets возвращает 0 - PullRequest
0 голосов
/ 23 марта 2019

Я пишу небольшой калькулятор, предназначенный для Arduino, используя RPN (обратная польская запись).Поскольку я также хочу, чтобы код выполнялся на моем ноутбуке x86, с настройкой некоторых параметров конфигурации для моей программы калькулятора, я использую такие функции, как input_str, input_int и output_str, поэтому я могу реализовать их по-разному для своего ноутбука илиarduino.

Теперь в input_str

char *input_str(void) {
  #if IS_IO_STDIO
    char iobuf[IO_BUF_SIZE];
    fgets(iobuf, IO_BUF_SIZE, stdin);
    if (IS_DEBUG) { printf("1. iobuf: %s\n", iobuf); }
    if (IS_DEBUG) { printf("2. iobuf ptr: %p\n", iobuf); }
    return iobuf;
  #elif IS_IO_SERIAL
    // TODO: implement serial input str
  #endif // IS_IO_STDIO
}

, используя fgets, чтобы получить ввод пользователя (для будущих вычислений), 1. iobuf printout правильно печатает строку, набранную впользователем 2. iobuf ptr правильно распечатывает некоторые char *, не равные 0.

Когда я использую возвращаемое значение input_str в моем ipo-цикле:

int ipo_loop(int16_t *stack, int *sp) {
    // TODO: implement real ipo loop
    int is_exit = false;
    char *iobuf;
    while (!is_exit) {
        iobuf = input_str();
        if (IS_DEBUG) { printf("3. iobuf ptr: %p\n", iobuf); }
        output_str(iobuf);
    }
    return 0;
}

3. iobuf ptr внезапно показывает, что iobuf теперь указывает на 0.

Почему iobuf внезапно 0?

Это какая-то проблема с типом передачи от char[IO_BUF_SIZE] до char *?

1 Ответ

4 голосов
/ 23 марта 2019

В приведенном ниже коде

char *input_str(void) { 
  char iobuf[IO_BUF_SIZE];
  fgets(iobuf, IO_BUF_SIZE, stdin);
  /* some code */
  return iobuf; 
}

, куда вы возвращаете локальный массив iobuf, вызывает неопределенное поведение .Массив char iobuf, объявленный в input_str(), имеет локальную область видимости, и его область действия заканчивается, когда управление выходит из этой функции.

Если вы могли бы скомпилировать свой код с flags наподобие -Wall, -Wextra и т. Д., Например, компилятор

gcc -Wall -Wextra -Werror -Wpedantic test.c

мог бы предупредить вас как

предупреждение: возвращен адрес стековой памяти, связанной с локальной переменной 'iobuf' [-Wreturn-адрес стека]

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

Вместо того, чтобы возвращать локальный массив, создайте динамический массив и верните его,Например,

char *iobuf = malloc(IO_BUF_SIZE * sizeof(*iobuf));
/* @TODO if malloc was success i.e check return value of malloc */

. После этого отсканируйте данные, используя fgets(), как вы сделали ниже.

  fgets(iobuf, IO_BUF_SIZE, stdin);

, а затем верните динамический массив

  return iobuf;

Inвызывая API ipo_loop(), как только вы закончите с динамически возвращаемым массивом, не забудьте free, чтобы избежать утечки памяти.например,

iobuf = input_str();
/* processing with iobuf.. here iobuf is dynamically returned array */
free(iobuf);
...