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
@Nick: не, не го правиш. 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