LINUX.ORG.RU

[нубский вопрос]C и указатели...

 


0

0

Добрый день, недавно начал изучать С и столкнулся с проблемой:

При вызове функции «foo» прога вылетает с ошибкой сегментирования. Если содержимое foo перенести в main то все прекрасно работает. В чем беда?

void foo(char* name){
    
    FILE *fd=fopen(name, "a+");
    fprintf(fd,"blah-blah\n");
}

int main(int argc, char* argv[]){
    char* name;
    printf("Test filesave function, enter filename: ");
    scanf("%s",name);
    foo(name);
    
    return 0;
}

мдя, оно еще и течет, кошмарики

hizel ★★★★★
()
Ответ на: комментарий от Rapt0r

> Так неинтересно, вдруг гипотетический пользователь введет 563 символа :)

я тебе указал причину, а не решение, потому что для приведения полного решения у тебя слишком кривой код

lester ★★★★
()

Вы уж покажите как вы переносите код "foo" в main. У вас, ИМХО, сигфолт должен быть в любом случае.

mky ★★★★★
()
Ответ на: комментарий от mky

int main(int argc, char* argv[]){

    char* name;
    printf("Test filesave function, enter filename: ");
    scanf("%s",name);

    FILE *fd=fopen(name, "a+");
    fprintf(fd,"blah-blah\n");
   
    return 0;
}

Rapt0r
() автор топика
Ответ на: комментарий от Rapt0r

Если речь идет о программе под glibc (GNU libc), то вам нужно вместо scanf использовать getline(). Прочитайте man или поищите пример в Инете.

mky ★★★★★
()
Ответ на: комментарий от Rapt0r

Упс, написал вам не все :) В начале есть еще:

#include <stdlib.h>
#include <stdio.h>

Rapt0r
() автор топика
Ответ на: комментарий от Rapt0r

> Нельзя ли привести пример "не кривого" кода?

наверное лучше вам сначала почитать литературу( в которой обычно есть примеры )

lester ★★★★
()
Ответ на: комментарий от Rapt0r

Тебе уже сказали, где он происходит и почему.
Конкретно: у тебя под массив name не выделена память.
Почему не падает - видимо потому, что, какбэ случайно, место, куда указывает name никем не занято.

tzukko
()
Ответ на: комментарий от lester

>наверное лучше вам сначала почитать литературу( в которой обычно есть примеры )

Полностью согласен, только в теорию сначала въехать.
И не копипастить примеры, да еще и с ошибками.
А-то был тут недавно деятель =)

tzukko
()
Ответ на: комментарий от lester

Литературу мне, конечно, еще читать и читать, но мне непонятна причина вылета.

Вы можете её назвать?

Rapt0r
() автор топика
Ответ на: комментарий от urxvt

Интереснее выяснить причину отсутсвия сегфолта, а точнее, сколько байт может ввести пользователь без возникновения сегфолта в варианте когда scanf() вызывают из main.

mky ★★★★★
()

чтоб не казаться слишком злым:

1. void foo( const char* name ) - всегда указывай, что аргумент не должен изменятся( если он таки не должен изменятся и не является базовым типом вроде int )
2. надо проверять в foo name на NULL( и assert добавить - чтоб всегда замечать такие ситуации по ходу исполнения )
3. fopen может вернуть NULL - у тебя не проверяется, также надо выводить сообщения об ошибках, а то при выполнении программы будет не понятно чего она не работает
4. используй fgets + stdin вместо scanf, чтоб избежать проблем с длинными строками( ес-но не забудь проверить на NULL полученное значение )
5. про char* name - уже писал
6. про то что файл надо закрыть - тоже писали

lester ★★★★
()
Ответ на: комментарий от mky

Я просто упустил момент распределения (точнее его отсутствие) памяти для name.

> сколько байт может ввести пользователь без возникновения сегфолта в варианте когда scanf() вызывают из main

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

urxvt ★★★★★
()
Ответ на: комментарий от mky

>сколько байт может ввести пользователь без возникновения сегфолта

Как повезет, по-видимому.

tzukko
()
Ответ на: комментарий от mky

>а точнее, сколько байт может ввести пользователь без возникновения сегфолта в варианте когда scanf() вызывают из main.

пока стек не переполниться, ведь char *name явно на стеке выделиться
можно попробовать написать ещё одну функцию, в ней вызвать scanf, а потом попробовать выйти из неё

dimon555 ★★★★★
()
Ответ на: комментарий от dimon555

>пока стек не переполниться, ведь char *name явно на стеке выделиться

Но указывает оно не обязательно в стек. Или туплю уже?

tzukko
()
Ответ на: комментарий от dimon555

Да нет же. Указатель лежит то в стеке, но указывает Столлман знает куда.

urxvt ★★★★★
()
Ответ на: комментарий от mky

не надо этого делать, ибо не переносимо
char buf[256];
scanf("%255s", buf);

Reset ★★★★★
()
Ответ на: комментарий от tzukko

>Но указывает оно не обязательно в стек. Или туплю уже?

printf нам поможет, скорее всего так получается, что в стэк... не обязательно

dimon555 ★★★★★
()
Ответ на: комментарий от tzukko

>>пока стек не переполниться, ведь char *name явно на стеке выделиться

>Но указывает оно не обязательно в стек. Или туплю уже?

Инициализации нет, так что хз куда оно указывает. Короче, сплошная лотерея.

const86 ★★★★★
()

Исправил исходник и привел его к более нормальному виду:

#include <stdlib.h>
#include <stdio.h>

void foo(const char* name){

if (name == NULL)
exit(1);

FILE *fd=fopen(name, "a+");
if (fd == NULL)
exit(1);
fprintf(fd,"foo\n");
fclose(fd);
}

int main(int argc, char* argv[]){

char name[1];

printf("Enter filename: ");
scanf("%15s",name);
foo(name);


return 0;
}

Если указать char name[1];(scanf почему-то работает с вводом строки больше 1 символа) то получаем нормальную работу программы при имени длиной меньше 9 символов, бесконечный цикл с длиной имени в 9 символов и вылет при длине имени более 9 символов(но файл создается):

raptor@raptor ~/Develop/temp $ ./lol
Enter filename: 123456789
Enter filename: 123456789
Enter filename: 12345678
raptor@raptor ~/Develop/temp $

Почему получается цикл? В книге написано что в стеке должен храниться только указатель, получается что нет?

ps: если указать размер name больше - то все нормально.

Rapt0r
() автор топика
Ответ на: комментарий от Dimanc

> Передаешь копию переменной, а функция принимает указатель.

как бы тип char[] и есть указатель

lester ★★★★
()
Ответ на: комментарий от Dimanc

Если выделена память под _один_ символ, то как передается более 1го символа?

И почему получается цикл? И именно на 9 символах?

Rapt0r
() автор топика
Ответ на: комментарий от Rapt0r

> В книге написано что в стеке должен храниться только указатель, получается что нет?
Лекцию же посмотри!

urxvt ★★★★★
()
Ответ на: комментарий от Rapt0r

> if (name == NULL)

компактнее писать if( !name )

> exit(1);


зачем ломать структуру программы, потом будешь думать - чего это программа вылетает на ровном месте

lester ★★★★
()
Ответ на: комментарий от urxvt

Я с английским не слишком дружу, чтобы слушать на нем лекции :(

Rapt0r
() автор топика
Ответ на: комментарий от Rapt0r

дебагер в лапки и на грабли!
измени параметры сборки и кол-во символов волшебным образом изменится

вас из принцыпа ломает достаточно памяти выделить? используйте другой языка :-\

hizel ★★★★★
()
Ответ на: комментарий от hizel

> вас из принцыпа ломает достаточно памяти выделить?

Нет же. Просто было интересно взглянуть как поведет себя char name[1]; Результат оказался забавным.

И не спрашивайте как я до этого бреда додумался (:

Rapt0r
() автор топика
Ответ на: комментарий от Rapt0r

>Другого способа нет?

Считывать посимвольно и выделять память маллоком.

Dudraug ★★★★★
()

если программа GNU Libc only, то можно еще

char *ptr;

scanf("%as", &ptr);

chicane
()
Вы не можете добавлять комментарии в эту тему. Тема перемещена в архив.