C странная ошибка с strcpy и еще более странное решение

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

char *name(char *string) {
    int i = strlen(string);
    char *aux;
    while(string[i-1] != '/'){
        i--;
    }
    strcpy(aux, &string[i]); 
    return aux;
}

Приведенная выше функция выдает ошибку Segmentation Fault, но если я добавлю следующую строку " int j = 0;" до объявления aux ошибка ушла, новый и рабочий код

char *name(char *string) {
    int i = strlen(string);
    int j = 0;
    char *aux;
    while(string[i-1] != '/'){
        i--;
    }
    strcpy(aux, &string[i]); 
    return aux;
}

ввод: C:\test\a.txt
вывод: a.txt

Почему добавление «int j = 0;» решает проблему? Я застрял с этим и не могу продолжать, потому что я не знаю, может ли это несоответствие привести к более серьезным проблемам позже, я думаю о написании собственной функции для копирования строк, но перед этим я действительно хочу понять, что ошибка.


person user1493813    schedule 01.07.2012    source источник
comment
aux не инициализирован. Сначала используйте malloc.   -  person Steve Howard    schedule 01.07.2012
comment
другое решение, которое я нашел, - это поменять местами порядок объявлений int i = strlen(string); и char *aux;   -  person user1493813    schedule 01.07.2012
comment
@ user1493813, это не решения. Это неопределенное поведение.   -  person chris    schedule 01.07.2012
comment
Кроме того, еще одно примечание: ваш ввод указывает обратную косую черту, а ваш цикл ищет прямую косую черту. У вас нет никакого терминатора цикла, кроме поиска косой черты, поэтому вы также должны segfault на этом входе. Чтобы быть в безопасности, выставьте чек на залог i == 0.   -  person Nick    schedule 01.07.2012
comment
Реквизит для не может продолжаться, потому что я не знаю, может ли это несоответствие привести к более серьезным проблемам позже, и я приду сюда, чтобы спросить, вместо того, чтобы просто продолжить после того, как найду что-то, что работает.   -  person Daniel Fischer    schedule 01.07.2012
comment
Ник, я опечатался при вводе (просто скопировал его с панели Windows), настоящий ввод использует косую черту   -  person user1493813    schedule 01.07.2012


Ответы (3)


Вы никогда не выделяете aux. aux должен указывать на действительное место в памяти, прежде чем вы попытаетесь что-либо скопировать в него.

Вместо char *aux нужно что-то вроде char *aux = malloc(i+1);. Обратите внимание, что i+1 является излишним, потому что в вашем случае aux всегда будет как минимум на 3 символа короче, чем string (оно не будет содержать C:\), но вам, вероятно, не нужны такие маленькие строки. Не забудьте free() указатель, когда закончите с ним.

Кроме того, причина, по которой вы обнаружили, что это работает, переключая порядок объявлений и / или добавляя объявление, вероятно, заключается в том, что вам повезло, и каким-то образом местоположение, на которое указывает aux, является допустимым (если вы делаете только char *aux;, aux указывает на случайное место) . Однако это чистая удача, и это по-прежнему неверный код, хотя кажется, что он работает.

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

person houbysoft    schedule 01.07.2012
comment
strcpy копирует нулевой терминатор, вам абсолютно необходимо (i+1). - person Nick; 01.07.2012
comment
@Ник: нет. aux всегда короче, чем string. - person houbysoft; 01.07.2012
comment
@Nick: добавлено объяснение к ответу, если это не очевидно. - person houbysoft; 01.07.2012
comment
Да, я пропустил ту часть, что он всегда использовал абсолютные пути, спасибо. - person Nick; 01.07.2012
comment
Большое спасибо, я использовал счетчик в цикле для подсчета количества символов, а затем делаю char *aux = malloc(cont + 1); , теперь я понимаю, что это была такая глупая ошибка указателя, мне действительно нужно обратить внимание на основы - person user1493813; 01.07.2012
comment
@ user1493813: рад, что помогло. Вы можете пометить его как принятый ответ, используя зеленую галочку слева. И да, использование счетчика - правильное решение :) - person houbysoft; 01.07.2012

Поскольку похоже, что вы заинтересованы только в использовании части строки имени файла в качестве параметра, другой вариант — использовать часть строки, которая у вас уже есть.

Попробуйте: aux = &string[i]; вместо strcpy.

Это дает вам указатель на интересующую вас часть строки (а именно, последнюю часть после финального '/').

Во-вторых, убедитесь, что у вас есть '/' во всех ваших входных строках, иначе произойдет что-то плохое (т. е. ваш цикл будет проходить дальше начала строки, вероятно, в какой-то момент столкнется с ошибкой сегментации). Было бы лучше поставить условие на цикл, чтобы он не продолжался за пределами i = 1.

person Paradigm    schedule 01.07.2012

Вы не выделяете память для aux. Вы пытаетесь записать в память через неинициализированный указатель.

person Nick    schedule 01.07.2012