LINUX.ORG.RU

Не могу разобраться с ошибкой сегментирования

 , , , ,


1

2

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

#include <stdio.h>
#include <string.h>
#include <sys/types.h> 
#include <sys/stat.h>
#include <fcntl.h>
#include <errno.h>
#include <stdarg.h>
#include <stdlib.h>
#include <unistd.h>

#define MAXLINE 256

static void err_doit(int errnoflag, int error, const char *fmt, va_list ap){
	char buf[MAXLINE];
	vsnprintf(buf, MAXLINE, fmt, ap);
	if(errnoflag)
		snprintf(buf+strlen(buf), MAXLINE-strlen(buf), ": %s", strerror(error));
	strcat(buf, "\n");
	fflush(stdout);
	fputs(buf, stderr);
	fflush(NULL);
}

void err_sys(const char *fmt, ...){
	va_list ap;
	
	va_start(ap, fmt);
	err_doit(1, errno, fmt, ap);
	va_end(ap);
	exit(1);
}

char* read_kode(const char *arg){
	int fd;
	ssize_t stat;
        size_t buf_sz = 0;
	char *kode = NULL;
	char buf[MAXLINE];
	
	if((fd = open(arg, O_RDONLY)) < 0)
		err_sys("Can't open file %s", arg);
	
	while((stat = read(fd, buf, MAXLINE)) > 0){
                kode = realloc(kode, buf_sz + stat + 1);
		if(kode == NULL)
			err_sys("Memory exchausted");
		memcpy(kode + buf_sz, buf, stat);
		kode[buf_sz += stat] = '\0';
			
	}
	if(stat==-1)
		err_sys("Read error");
	
	close(fd);
	return kode;
}

int main(int argc, char **argv){
	char *str = read_kode(argv[1]);
	printf("%s", str);
	exit(0);
}

err_doit и err_sys рабочие, проверял неоднократно. Используются просто для вывода ошибок и выхода с программы.

Ответ на: комментарий от shkolnick-kun

Как и в вашем варианте.

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

Тут поподробнее пжалста.

А вот не буду. Про количество goto была совершенно простая прямолинейная мысль, чего тут жевать?

vodz ★★ ()
Последнее исправление: vodz (всего исправлений: 1)
Ответ на: комментарий от vodz

В моём 0 дописывается и память под него выделяется и потому для текстовых применений годится.

Как насчет 0 посреди файла? Точно не придется количество прочитанных байт возвращать?

shkolnick-kun ★★ ()
Последнее исправление: shkolnick-kun (всего исправлений: 1)
Ответ на: комментарий от shkolnick-kun

Как насчет 0 посреди файла?

Вы так говорите, как-будто я про это забыл и не упоминал тут 4 раза. Вы русский ещё не забыли? Речь была о том, что надо делать «или», чтобы это в принципе можно было использовать. С таким же успехом можно говорить, что компилятор глючный и не может догадаться где кавыку надо было закрыть пропущенную.

vodz ★★ ()
Ответ на: комментарий от shkolnick-kun

Т.е. портянка из *_unlock, free, fclose в каждом месте лучше?

Для писателя ОС объясняю:

Можно записать кучей способов. Ненавистники goto вводят флаг ошибки, потом его проверяют на каждом шаге. Но для простейших случаев достаточно у вас было поменять условие на if(!error) и новый отступ.

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

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

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

Помоему, конструкция вида:

char* read_kode(const char *arg){
    FILE * f;

    f = fopen(arg, "r");

    if (NULL != f){
        if (fseek(f, 0, SEEK_END)){
            ssize_t fsz;

            fsz = ftell(f);
            rewind(f);

            ret = malloc(fsz+1);
            if (NULL != ret){
                char * ret;
                ssize_t rsz;

                rsz = fread(f, ret, fsz);

                if (0 == fsz - rsz){
                    fclose(f);
                    ret[fsz] = 0;
                    return ret;    
                }else{
                    free(ret);
                }
            }
        }
        fclose(f);    
    }
    return NULL;    
}
довольно сильно похожа на:
if () {
    if () {
        do {
            if () {
                if () {
                    if () {
                        ...
                    }
                }
                ...
            }
            ...
        }
        while ();
        ...
    }
    else {
        ...
    }
}

И это не пример, а описание распространенного приема рефакторинга, когда:

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

Если ОП/ТС будет увлекаться вложенностью, то рано или поздно он таки создаст вышеописанную проблему.

Так что пусть привыкает к goto error_xxx; или переходит на C++ с исключениями.

shkolnick-kun ★★ ()
Последнее исправление: shkolnick-kun (всего исправлений: 1)
Ответ на: комментарий от shkolnick-kun

довольно сильно похожа на:

А утрировать не надо и не будет похоже. Я где-то говорил, что обязательно первый if тянуть на весь код и полностью отказаться от goto? В первом if нет никакого дополнительного действия кроме как вернуть ошибку. Вынесите не только f на самый верх, а ещё ret = NULL, и вдруг , о чудо, всё становится и красивее и удобнее. Особенно смачно выглядит проверка сика, как-будто это не ваша вина, что поток не сикается. :)

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

Я где-то говорил, что обязательно первый if тянуть на весь код и полностью отказаться от goto?

А где-то говорил, что строки в файле или сам файл кончаются 0?

Нет, я этого не говорил, но это не помешало Вам, уважаемый сноб, додумать мой ответ, не так ли?

Так что привыкайте буквальному, а то и к «креативному» толкованию Ваших слов в интернетах.

Особенно смачно выглядит проверка сика, как-будто это не ваша вина, что поток не сикается.

Текстовый поток должен поддерживать fseek с аргументом SEEK_END, если это не так, то виноват тот, кто не соблюдает стандарт Си, например, передавая в функцию read_kode путь к бинарному файлу.

С учетом правила 95%, проверка не помешает.

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

А где-то говорил, что строки в файле или сам файл кончаются 0?

Вы то? Да, вы влезли в спор с другим человеком ничего не разобрав.

Так что привыкайте буквальному

Щас, разбежался. Я буду отвечать за свои слова, а за чужие выдумки посылать.

Текстовый поток должен поддерживать fseek

Сами придумали или подсказал кто? fseek поддерживает только блочные устройства и файлы на блочных устройств. Не поддерживают пайпы, символьные устройства и потому даже тривиальный stdin из терминала, не говоря уже о сокетах. Так что со своими 98% можете утереться, это гораздо ниже 50%.

vodz ★★ ()
Последнее исправление: vodz (всего исправлений: 2)
Ответ на: комментарий от vodz

Нет, конечно,

В чем тогда претензия?

оставайтесь балаболом и хамом.

Что за необоснованный наезд?

Ну да, ну да. read_file4alloacted_nonreused_buffer...

Заставь дурака богу молиться, он лоб расшибет (с) народная мудрость.

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

Что за необоснованный наезд?

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

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

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

Теперь мы выяснили, что на самом деле балабол именно вы.

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

Теперь мы выяснили, что

Вы ответили через полтора часа от аналогичного ответа выше. Мне пришлось писать пространный пост, что это всё равно не поможет, см пункт 1. www.linux.org.ru/forum/development/13667667?cid=13669141 Ну а далее for(;;) www.linux.org.ru/forum/development/13667667?cid=13675015

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

Да, вы влезли в спор с другим человеком ничего не разобрав.

А зачем к любой фразе в интернете относиться как к попытке завязать спор?

Мы тут какбе ОПу помогаем, примеры кода постим, чтоб впитывал что-нибудь разумное, доброе, вечное...

Сами придумали или подсказал кто?

ISO/IEC 9899:2011 п. 7.21.9.2 описание поведения fseek.

Стоп, там для текстового потока написано, что следует передавать SEEK_SET, а для бинарного написано, что можно не поддерживать SEEK_END...

Либеральненько , однако!

shkolnick-kun ★★ ()
Последнее исправление: shkolnick-kun (всего исправлений: 1)
Ответ на: комментарий от shkolnick-kun

описание поведения fseek

И что, как-то противоречит тому, что я сказал? Там написано, что можно успешно сикать терминал, пайп, сокет? Или там написано про ваши 95% случаев?

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

Это никак не отменяет вашего балабольства и необоснованного наезда.

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

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

Отвечать через полтора часа тем же самым, это либо балабольство для набивания постов и хамство по отношению к автору и читателям.

Разводить тут бестолковую бодягу - вот это действительно балабольство и хамство по отношению к читателям. И вы успешно с этим справляетесь.

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

Балабол такой балабол.

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

Я вам это говорю,

Ваше слово против моего бъётся элементарно: в апдейте топика теперь правильный МОЙ код, а вы даже не способны были ответить как назвать функцию, чтобы было понятно, что она аллокирует malloc-ом и этот адрес и возвращает и не запоминает его, хотя вас за язык никто не тянул. Но от вас был просто флуд и ни одного оригинального решения. А заткнуться вы не можете, как обычно тут на ЛОРе, как же, вас уличили в факапе.

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

Ваше слово против моего бъётся элементарно: в апдейте топика теперь правильный МОЙ код,

И что это по вашему значит?

а вы даже не способны были ответить как назвать функцию, чтобы было понятно, что она аллокирует malloc-ом и этот адрес и возвращает и не запоминает его, хотя вас за язык никто не тянул.

А был такой вопрос и я обещал дать на него ответ?

Но от вас был просто флуд и ни одного оригинального решения.

Нет, я ответил по существу. Для вас даже ссылку привел.

А заткнуться вы не можете, как обычно тут на ЛОРе, как же, вас уличили в факапе.

Вот-вот, все никак не уйметесь. А ведь когда вас макнули мордой в говно, то лучше утереться и запомнить этот урок.

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

И что это по вашему значит?

Да я могу и 4-й раз повторить: флуд в этом топике только от вас.

А был такой вопрос и я обещал дать на него ответ?

Было: "- достаточно назвать...", дан пример, что описать в названии всю документацию всё равно током не удасться, в ответ было: «заставь дурака...». То есть типичное: у нас есть такие приборы... или иначе говоря - обделались.

Нет, я ответил по существу. Для вас даже ссылку привел.

Для вас было объяснено, что это было флудом и хамством.

Вот-вот, все никак не уйметесь.

Вот вот, пошёл уровень детского сада: «сам дурак».

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

Сами придумали?

Ага, и дописал в стандарт c99 пункт 6.3.2.3.

Хотелось бы посмотреть на архитектуру, у которой нельзя «сохранить в указатель любого типа».

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

Никогда не требовалось кастование malloc, но принято было писать для указателя не (char *) для того чтобы заткнуть тупой статический анализатор типа lint.

Я видел такое от плюсовиков, которые пишут иногда на си. Там каст требуется и они приносят его с собой.

grossws ()
Ответ на: комментарий от vodz

Да я могу и 4-й раз повторить: флуд в этом топике только от вас.

Главное повторять мантру вовремя. Вот только топик показывает обратное, балабол и флудер тут вы.

Было: "- достаточно назвать...", дан пример, что описать в названии всю документацию всё равно током не удасться, в ответ было: «заставь дурака...». То есть типичное: у нас есть такие приборы... или иначе говоря - обделались.

Ну если вы обделались, то зачем об этом сообщать всему ЛОРу?

Для вас было объяснено, что это было флудом и хамством.

Чаще мантру повторяйте.

Вот вот, пошёл уровень детского сада: «сам дурак».

Вы свои сообщения даже не читаете?

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

Ага, и дописал в стандарт c99 пункт 6.3.2.3.

Было сказано: «ни тогда, ни сейчас не требуется кастование для malloc().» Даже когда не было (void *) и тем более c99. А вы увидели ключевое слово и радостно ляпнули совсем не по теме.

Это не про архитектуру было, а про потенциальное ub при касте указатель на тип с другим выравниванием.

И чем тут (void *) поможет? Вначале присвоили невыровненное, а потом присвоили до широкого типа.

Я видел такое от плюсовиков, которые пишут иногда на си.

Вы не поняли, в те времена C++ ещё не родился. lint был тупой не от того, что авторы были тупые, а времена такие, под хороший статический анализатор надо много памяти, а было всего 64к на процесс.

vodz ★★ ()
Последнее исправление: vodz (всего исправлений: 1)
Ответ на: комментарий от vodz

Вы заявили

(void *) появился позже, до этого вместо него был (char *), следовательно, ни тогда, ни сейчас не требуется кастование для malloc().

Это, если что, импликация. Мой комментарий был про ложность этой импликации. Но ни с «(void *) появился позже, до этого вместо него был (char *)», ни с «ни тогда, ни сейчас не требуется кастование для malloc()» я не спорил, ибо с обоими этими утверждениями я согласен. Из того, что void * появился позже никоим образом не следует, что каст не нужен. Каст не нужен согласно более-менее современным стандартам.

Как выглядела ситуация в достандартные времена для современного мира почти не релевантно. Был там расширяющий implicit cast из char* у основных компилятором или сигнатура malloc'а с char* для наиболее распространенного случая — не суть.

Вы не поняли, в те времена C++ ещё не родился.

Не нервничайте. Я просто говорю про современность, а не 70-80е гг. У нас уже c99/c11, rust, clang-analyze и прочие радости. Оперативки, правда, бывает существенно меньше 64к, но это на target,а не host.

grossws ()
Последнее исправление: grossws (всего исправлений: 1)
Ответ на: комментарий от grossws

Каст не нужен согласно более-менее современным стандартам.

А слабо следить за нитью разговора, а не придумывать по 5 дней чтобы ещё такое рассказать своим мыслям ? Вы топик открывали вообще? Накой кастовать для указателя kode (sic!) типа char * при присвоении malloc-ом? Что трудного в понимании, фразы «никогда этого не надо было делать, ни когда malloc возвращал char *, ни сейчас, когда специально придуман void *»? Да, это не ошибка, это просто эталонная демонстрация непонимания основ. Тут вон явные ошибки то так предыдущему оратору показать не поучилось, так и ушёл, думая что он в белом, прям эталонная Новодворская. А вы тупо пытаетесь сказать простейшую мысль и третий раз нежелаете вникнуть, что эта банальность не нужна, так как вникать надо о чём речь, прежде чем в спор вступать.

vodz ★★ ()
Последнее исправление: vodz (всего исправлений: 1)
Ответ на: комментарий от vodz

Если вы что-то рассказываете своим мыслям, это ваша проблема. Обращайтесь к специалисту.

Я нигде не говорил, что в Си нужен явный каст из void* в какой-либо тип. Implicit cast, о котором я писал, — это неявное, автоматическое приведение. Для меня явный каст из void* или sizeof(char) — это явный code smell. И абсолютно не важно, делается это с результатом malloc'а или любой другой функции.

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

Я нигде не говорил,

Потому что вы основ и не понимаете. У malloc предназначение - выделить память и результат предназначен для записи в указатель. Предназначение void * именно для того, чтобы не делать касты. Но даже кода void * не было, а был (char *) то даже для тупого lint-а не надо никогда было делать (char *)=(char *). Потому ваше тут выступление, каждое через 3-5 дней после предыдущего выступления не только КО, а натурально какая-то болезнь головы.

vodz ★★ ()
Последнее исправление: vodz (всего исправлений: 2)