WedX - журнал о программировании и компьютерных науках

нужна помощь, чтобы выяснить, почему strtok вызывает segfault, может ли он не использовать параметр const char *?

Мне трудно понять, почему я продолжаю получать ошибку сегментации при попытке запустить небольшой тест. Идея состоит в том, что я отправляю дробь в виде строки, такой как «1/4» в этом случае, а string_to_fraction должен токенизировать строку, избавляясь от «/» и устанавливая значение числителя равным 1, а значение знаменателя до 4, а затем вернуть его.

typedef struct {
    int numer;
    int denom;
}Fraction;

Fraction string_to_fraction(const char *S);

main(){
    const char* strn = "1/4";
    Fraction myFrac;
    myFrac = string_to_fraction(strn);
    return 0;
}

Fraction string_to_fraction(const char *S)
{
    Fraction result = {0,1};
    char *p;
    char n[100] = {}, d[100] = {};
    p = strtok(S,"/");
    if(p == NULL){
        printf("String of improper format");
        return result;
    }
    strcpy(n,p);
    p = strtok(NULL,"/");
    strcpy(d,p);
    result.numer = n;
    result.denom = d;
    return result;
}

segfault возникает в первом экземпляре strtok, например. p = strtok(S,"/");, но я понятия не имею, почему это происходит, я пробовал передать много разных вещей в функцию string_to_fraction, но она всегда дает сбои. Любое понимание очень ценно, так как все другие проблемы, которые люди имели с strtok, вызывающим segfault, на самом деле не относятся к моей ситуации, насколько я могу судить.

изменить: забыл включить мое объявление в функцию Fraction_to_string здесь, которая теперь исправлена. Я сделал это в своем коде, но этот код разделен большим количеством мусора, поэтому я просто переписал его здесь.


  • возможный дубликат strtok не принимает: char *str 12.04.2015
  • Вызов strtok изменяет строку, которую вы ему передали, однако S передается из символьного литерала, который размещен в сегменте данных и является неизменяемым (поскольку это литерал). Вам нужно сделать копию С. 12.04.2015
  • так что-то вроде char* newS; strcpy(newS,S);, затем вызовите strtok как p = strtok(newS,"/");? 12.04.2015
  • Подождите, нет, согласно другой вещи здесь, у которой будет та же проблема, поскольку она, по-видимому, не может изменить char * или что-то в этом роде, так что тогда мне вместо этого нужно что-то вроде: char newS[100] = {}; strcpy(newS,S);? 12.04.2015
  • Нет, так как вы не выделили места для newS. Вы можете использовать strdup или выделить пространство, в которое вы пытаетесь его скопировать. 12.04.2015
  • так что это так же просто, как выполнить char *newS; newS = strdup(S); перед strtok, а затем вызвать strtok для newS, а не для S? 12.04.2015
  • поскольку размещенный код возвращает экземпляр структуры, а не указатель на структуру, компилятор выделит некоторую «скрытую» память, а затем использует два вызова memcpy(). первый вызов для копирования возвращенной структуры в скрытую память и второй вызов для копирования скрытой памяти в экземпляр структуры вызывающего объекта. это много лишнего/скрытого кода, потерянная память и т. д. Гораздо лучше передать второй параметр и заставить вызываемую функцию копировать данные в определение структуры вызывающей стороны. 12.04.2015

Ответы:


1

Да, как сказал Бенджамин, строковые литералы размещаются в постоянной памяти, а strtok изменяет саму строку, например сохраняет '\0' символ вместо delim.

Предупреждение компилятора

warning: passing argument 1 of ‘strtok’ discards ‘const’ qualifier from pointer target type

намек здесь, что что-то не так.

Вот как сделать копию:

заменять

const char* strn = "1/4";

с участием

char buf[8192];
snprintf(buf, 8192, "1/4");
const char* strn = buf;

...или с:

char *strn = strdup("1/4");
...
free(strn);//<<-- but then your would need to free memory in the end of program

Есть еще одна проблема с вашим кодом — вы используете строки как целые числа. C не будет конвертировать их автоматически:

result.numer = n;
result.denom = d;

заменить:

result.numer = atoi(n);
result.denom = atoi(d);
11.04.2015
  • Ах, спасибо, я попытаюсь внести несколько изменений, используя это, и посмотреть, смогу ли я это исправить. 12.04.2015
  • У меня это работает! Большое спасибо Вам (фуканчик) а так же Пенсионеру Ниндзя. я закончил тем, что использовал char *scpy = strdup(S);, затем вызвал p = strtok(scpy,"/");, затем вызвал free(scpy); непосредственно перед возвратом. Раньше я даже не задумывался о том, что строки не являются целыми числами, поэтому упоминание atoi спасло меня от многих страданий в будущем. 12.04.2015
  • Новые материалы

    Объяснение документов 02: BERT
    BERT представил двухступенчатую структуру обучения: предварительное обучение и тонкая настройка. Во время предварительного обучения модель обучается на неразмеченных данных с помощью..

    Как проанализировать работу вашего классификатора?
    Не всегда просто знать, какие показатели использовать С развитием глубокого обучения все больше и больше людей учатся обучать свой первый классификатор. Но как только вы закончите..

    Работа с цепями Маркова, часть 4 (Машинное обучение)
    Нелинейные цепи Маркова с агрегатором и их приложения (arXiv) Автор : Бар Лайт Аннотация: Изучаются свойства подкласса случайных процессов, называемых дискретными нелинейными цепями Маркова..

    Crazy Laravel Livewire упростил мне создание электронной коммерции (панель администратора и API) [Часть 3]
    Как вы сегодня, ребята? В этой части мы создадим CRUD для данных о продукте. Думаю, в этой части я не буду слишком много делиться теорией, но чаще буду делиться своим кодом. Потому что..

    Использование машинного обучения и Python для классификации 1000 сезонов новичков MLB Hitter
    Чему может научиться машина, глядя на сезоны новичков 1000 игроков MLB? Это то, что исследует это приложение. В этом процессе мы будем использовать неконтролируемое обучение, чтобы..

    Учебные заметки: создание моего первого пакета Node.js
    Это мои обучающие заметки, когда я научился создавать свой самый первый пакет Node.js, распространяемый через npm. Оглавление Глоссарий I. Новый пакет 1.1 советы по инициализации..

    Забудьте о Matplotlib: улучшите визуализацию данных с помощью умопомрачительных функций Seaborn!
    Примечание. Эта запись в блоге предполагает базовое знакомство с Python и концепциями анализа данных. Привет, энтузиасты данных! Добро пожаловать в мой блог, где я расскажу о невероятных..


    Для любых предложений по сайту: [email protected]