Nano Hash - криптовалюты, майнинг, программирование

Segfault при доступе к памяти malloc'd в функции

Я пытаюсь написать функцию, которая принимает путь (char *) и разбивает его на массив строк, основанный на разделителе '/'. Упрощенный код ниже:

int split_path(char * path, char ** out) {
    out = NULL;
    char * token = strtok(path, "/");
    int count = 0;

    while(token) {
        out = realloc(out, sizeof(char*) * (++count));
        out[count-1] = malloc(sizeof(char) * strlen(token)+1);
        strcpy(out[count-1], token);
        fprintf(stderr, "%s\n", out[count-1]);

        token = strtok(NULL, "/");
    }   

    out = realloc(out, sizeof(char*) * (count+1));
    out[count] = NULL;

    return count;
}

int main(int argc, char * argv[]) {
    char path[] = "/home/pirates/are/cool/yeah";

    char ** out;

    int count = split_path(path, out);

    fprintf(stdout, "count: %d\n", count);
    fprintf(stderr, "1st: %s\n", out[0]); // segfaults here
    return 0;
}

Все операторы печати в функции split_path печатаются отлично, вывод выглядит следующим образом:

count: 1, string: home
count: 2, string: pirates
count: 3, string: are
count: 4, string: cool
count: 5, string: yeah
count: 5
1st: ./a.out
[1]    5676 segmentation fault (core dumped)  ./a.out

Но по какой-то причине, когда я возвращаюсь к основной функции, массив двойных символов больше не действует. Я подумал, что это может быть потому, что он указывал на память, объявленную в этой функции split_path, но я делаю strcpy, чтобы получить в нее строки, поэтому он не должен указывать обратно на память, которая является локальной для этой функции. Любая помощь приветствуется.


  • Я попробую, но я не уверен, почему это будет иметь большое значение. 30.05.2016
  • что сказал @BLUEPIXY ... или используйте char ***, чтобы out действительно менялся и возвращался. 30.05.2016
  • хорошо, что сработало, но почему? out - это указатель, так почему бы его не изменить? Нужен ли мне еще один уровень указателя, например char**? 30.05.2016
  • Вы не используете доступ к памяти, выделенной в функции. 30.05.2016
  • при вызове malloc() или realloc() всегда проверяйте (!=NULL) возвращаемое значение, чтобы убедиться, что операция прошла успешно. При вызове realloc() не присваивайте возвращаемое значение целевому указателю напрямую, поскольку в случае сбоя realloc() исходный указатель теряется, что приводит к утечке памяти. Вместо этого назначьте переменную «temp», проверьте эту переменную на NULL, и если не NULL, то назначьте целевую переменную из переменной «temp». 30.05.2016
  • относительно такого типа строки: out = realloc(out, sizeof(char*) * (++count)); это только изменение значения параметра, а не переменной обратно в main(), строка должна быть похожа на: *out = realloc(*out, sizeof(char*) * (++count));. Подобные соображения существуют для каждой ссылки на out в функции split_path(). 30.05.2016

Ответы:


1

Вы неправильно управляете параметром out. Переменной out в main() никогда не назначается допустимый адрес памяти, поэтому возникает ошибка сегментации. Параметр out в split_path() никогда не обновляет переменную out в main(). Вам нужно передать адрес переменной в split_path(), чтобы он мог обновить переменную и получить доступ к памяти, на которую указывает переменная.

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

Вместо этого попробуйте что-то вроде этого:

int split_path(char * path, char *** out) {
    *out = NULL;
    char * tmp = strdup(path);
    if (!tmp) { ... }
    char * token = strtok(tmp, "/"');
    int count = 0;
    char ** newout;

    while (token) {
        newout = realloc(*out, sizeof(char**) * (++count));
        if (!newout) { ... }
        *out = newout;
        (*out)[count-1] = malloc(sizeof(char) * (strlen(token)+1));
        if (!(*out)[count-1]) { ... }
        strcpy((*out)[count-1], token);
        fprintf(stderr, "%s\n", token);

        token = strtok(NULL, "/");
    }   

    newout = realloc(*out, sizeof(char**) * (count+1));
    if (!newout) { ... }
    *out = newout;
    (*out)[count] = NULL;

    free (tmp);
    return count;
}

int main(int argc, char * argv[]) {
    char path[] = "/home/pirates/are/cool/yeah";

    char ** out;

    int count = split_path(path, &out);

    fprintf(stdout, "count: %d\n", count);
    fprintf(stderr, "1st: %s\n", out[0]); // segfaults here

    free (out);
    return 0;
}

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

29.05.2016
  • оно работает! спасибо, теперь я понимаю, что если я хочу сохранить ссылку на двумерный массив памяти, мне нужен тройной указатель, точно так же, как если бы я хотел ссылку на один int, мне нужен указатель int. Имеет смысл. 30.05.2016
  • Новые материалы

    Кластеризация: более глубокий взгляд
    Кластеризация — это метод обучения без учителя, в котором мы пытаемся найти группы в наборе данных на основе некоторых известных или неизвестных свойств, которые могут существовать. Независимо от..

    Как написать эффективное резюме
    Предложения по дизайну и макету, чтобы представить себя профессионально Вам не позвонили на собеседование после того, как вы несколько раз подали заявку на работу своей мечты? У вас может..

    Частный метод Python: улучшение инкапсуляции и безопасности
    Введение Python — универсальный и мощный язык программирования, известный своей простотой и удобством использования. Одной из ключевых особенностей, отличающих Python от других языков, является..

    Как я автоматизирую тестирование с помощью Jest
    Шутка для победы, когда дело касается автоматизации тестирования Одной очень важной частью разработки программного обеспечения является автоматизация тестирования, поскольку она создает..

    Работа с векторными символическими архитектурами, часть 4 (искусственный интеллект)
    Hyperseed: неконтролируемое обучение с векторными символическими архитектурами (arXiv) Автор: Евгений Осипов , Сачин Кахавала , Диланта Хапутантри , Тимал Кемпития , Дасвин Де Сильва ,..

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

    Обеспечение масштабируемости LLM: облачный анализ с помощью AWS Fargate и Copilot
    В динамичной области искусственного интеллекта все большее распространение получают модели больших языков (LLM). Они жизненно важны для различных приложений, таких как интеллектуальные..