Почему я получаю segfault с atoi в c?

Я пытаюсь прочитать строку из argv. Это должно быть что-то вроде математической функции, например "-x^2-5" и т. д.

У меня есть что-то вроде этого:

void test(char *function){
  int temp = 0;
  for (int i = 0; i < strlen(function); i++){
    if ((function[i] != '+') && (function[i] != ...){
      // function[i] is a digit, but still as a char
      temp = atoi(function[i]);
    }
  }
  //... 
}
int main(int argc, char **argv){
  test(argv[1]);
  //...
}

Это работает довольно хорошо до последнего круга цикла. Если я использую printf("%c", function[i]);, он говорит, что это 5.

Но atoi(function[i]) дает segfault. Почему?

Пожалуйста, проверьте if (argc >= 2) перед использованием argv[1].

Weather Vane 10.12.2020 11:33

Включите предупреждения компилятора! function[i] — это один char, а не char*. Таким образом, он неявно приводится к типу указателя и atoi пытается читать с почти нулевого адреса памяти. Возможно, вы имели в виду &function[i] или function + i

paddy 10.12.2020 11:33
atoi(function[i]) на самом деле недействителен C, поэтому любой компилятор, пропускающий этот код, плох. Имейте в виду, что большинство основных компиляторов C по умолчанию работают в «плохом режиме». Вы должны добавить -std=c11 -pedantic-errors, чтобы превратить их в компиляторы C. Также см. Проблемы «Указатель из целого числа/целое число из указателя без приведения».
Lundin 10.12.2020 11:46
Стоит ли изучать PHP в 2023-2024 годах?
Стоит ли изучать PHP в 2023-2024 годах?
Привет всем, сегодня я хочу высказать свои соображения по поводу вопроса, который я уже много раз получал в своем сообществе: "Стоит ли изучать PHP в...
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
Поведение ключевого слова "this" в стрелочной функции в сравнении с нормальной функцией
В JavaScript одним из самых запутанных понятий является поведение ключевого слова "this" в стрелочной и обычной функциях.
Приемы CSS-макетирования - floats и Flexbox
Приемы CSS-макетирования - floats и Flexbox
Здравствуйте, друзья-студенты! Готовы совершенствовать свои навыки веб-дизайна? Сегодня в нашем путешествии мы рассмотрим приемы CSS-верстки - в...
Тестирование функциональных ngrx-эффектов в Angular 16 с помощью Jest
В системе управления состояниями ngrx, совместимой с Angular 16, появились функциональные эффекты. Это здорово и делает код определенно легче для...
Концепция локализации и ее применение в приложениях React ⚡️
Концепция локализации и ее применение в приложениях React ⚡️
Локализация - это процесс адаптации приложения к различным языкам и культурным требованиям. Это позволяет пользователям получить опыт, соответствующий...
Пользовательский скаляр GraphQL
Пользовательский скаляр GraphQL
Листовые узлы системы типов GraphQL называются скалярами. Достигнув скалярного типа, невозможно спуститься дальше по иерархии типов. Скалярный тип...
0
3
353
3
Перейти к ответу Данный вопрос помечен как решенный

Ответы 3

Ответ принят как подходящий

Верно. Давайте сначала посмотрим на подпись atoi.

int atoi(const char *str);

Теперь вы передаете ему function[i], а поскольку function имеет тип char *, function[i] является char. И ваш персонаж, скорее всего, не является правильным указателем персонажа.

Вместо этого вы хотите передать atoiconst char *, который вы можете получить, позвонив atoi(&function[i]);

@xXxKaddiexXx Хотя, если бы я пытался анализировать подобные выражения, я бы рассмотрел возможность проведения «правильного» лексического анализа выражения, а затем использовал бы что-то вроде алгоритма «сортировочной станции» для создания дерева выражений из предоставленного пользователем выражение. Облегчает распознавание того, является ли символ оператором, переменной, такой как x, или литеральным значением, таким как 2. Также упрощается оценка.

sham1 10.12.2020 13:25

Как уже сказал @sham1, atoi ожидает, что его параметр будет строкой C, это массив символов с нулевым завершением, в то время как у вас есть один символ.

Но цифры особенные, потому что они должны иметь последовательные коды. Итак, если вы знаете, что символ (скажем, c) — это цифра, его значение равно c - '0'. Итак, вы можете написать:

if ((function[i] != '+') && (function[i] != ...){
  // function[i] is a digit, but still as a char
  temp = function[i] - '0';    // get the int value of a digit character
}

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

xXxKaddiexXx 10.12.2020 12:22

Помимо ошибки, указанной в других ответах, atoi не имеет надежной обработки ошибок, поэтому это одна из функций стандартной библиотеки , которую никогда не следует использовать .

Просто забудьте, что вы когда-либо слышали о atoi, и замените его на:

char* endptr;
int result = strtol(str,&endptr,10);

if (endptr == str)
{
  // some conversion error
}

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

О нет, я этого не знал. Это сэкономило бы много времени xD. Спасибо :)

xXxKaddiexXx 10.12.2020 12:17

@xXxKaddiexXx В этом конкретном случае вы, по сути, предоставляете что-то, что не является строкой с нулевым символом в конце, поэтому strtol вряд ли смог бы найти эту проблему.

Lundin 10.12.2020 12:22

Другие вопросы по теме