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 рабочие, проверял неоднократно. Используются просто для вывода ошибок и выхода с программы.

У тебя strlen обращается по неинициализированному указателю kode.

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

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

наркоман.

tbuf = (char *) malloc(strlen(kode) + 1); kode = (char *) malloc(strlen(kode) + strlen(buf) + 1);

указатель kode не инициализирован еще а ты с него хочешь длину получить.

anonymous ()

strlen(kode)

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

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

Не знаю, что такое куча, только начал программировать. А чего странный то? Не то что бы мне самому мой код нравился, но все таки хотелось бы немного детализации. Надо ведь знать над чем работать

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

Выход из процесса осуществляется функцией err_sys. Лучше бы не прятать побочное действие внутрь функции (тем более с таким именем). static как уже сказали выше не нужен.

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

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

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

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

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

Это пять!

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

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

Прям как маленькие, ей богу: я когда впервые на бейсике в пятом классе писал, я вообще считал что подпрограммы - это блажь и готу решает. И удивлялся версии бейсика в которой не было номеров строк (как по готу переходить то?). А тут прям нормальный код, даже функции есть. А вы - ведро, палка..

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

А тут прям нормальный код, даже функции есть. А вы - ведро, палка..

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

Тут тоже все хороши.

1. Никто не заметил, что strcat для стекового буфера не обязан найтись \0, read сам его не записывает.

2. Никто не сказал, что для начала стоило бы сделать man realloc, да и (char *) malloc — это даже 50 лет назад не надо было, когда не было (void *), ибо даже тогда у malloc возвращался (char *) по умолчанию.

И так далее.

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

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

man malloc

void *malloc(size_t size);

У меня особенный ман?

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

У меня особенный ман?

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

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

Ты не по-русски написал и теперь кидаешься какашками.

ибо даже тогда у malloc возвращался (char *) по умолчанию

По-русски это значит, что и сейчас malloc возвращает char*. Или так, или слово «даже» надо убрать

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

ни тогда, ни сейчас не требуется кастование для malloc().

Но совершенно по другой причине: в си есть implicit conversion в/из void *, malloc возвращает void * и его результат может быть сохранен в указатель любого типа. В плюсах всё не так, но там есть new.

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

Но совершенно по другой причине

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

и его результат может быть сохранен в указатель любого типа

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

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

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

Открой для себя valgrind

На этом этапе открывать для себя Valgrind слишком рано. Есть неслабый такой шанс съехать в «я пишу нормальный код, а Valgrind на него фолзит». Сначала нужно набрать достаточно опыта, чтобы мысль о том, что нашёл в компиляторе баг лезла в голову только после тщательной проверки своего кода. Осознать, что и после этого есть немалый шанс пропустить свой баг. Без этого всегда виноватыми будут инструменты.

i-rinat ★★★★★ ()

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

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

char *kode = (char *) malloc(1);

char *kode = NULL; size_t buf_sz = 0;

kode = (char *) malloc(strlen(kode) + strlen(buf));
strcat(kode, buf);

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';
vodz ★★ ()
Последнее исправление: vodz (всего исправлений: 3)
Ответ на: комментарий от vodz

Нульчую этого оратора.

1. Зачем делать malloc(1), уж лучше не инициализировать его при объявлении, хотябы предупреждение от компилятора получишь.

2. Если уж инициализируешь таким образом указатель, - не забудь сделать kode[0] = 0;

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

Если уж инициализируешь таким образом указатель

Это всё мелочи. А это ничего, что следующий malloc предыдущий буфер не обязан сохранять? А это ничего, что read не вставляет в конце '\0' ?

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

Ну, может там надо только последний случай...

Что? Ваше kode[0]=0 совершенно бесполезно, так как в цикле у него идёт следующий malloc.

Кстати, а где там free?

А зачем в этом коде free? Надо прочитать файл в буфер и отдать наружу. Вот как снаружи этот буфер заиспользуют, только потом надо free. В исходном коде это return из main, то есть free самой системой.

Кстати, вызов exit(code) в main() вместо return придумано каким-то идиотом и кочует из кода в код совершенно необъяснимо. Спросишь у автора: «Зачем?», а в ответ хорошо если что-то вроде: «Ну да, действительно нет смысла».

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

Что?

Последний кусок файла, или последнюю строку в файле, или еще чего, явно же код не «боевой».

Надо прочитать файл в буфер и отдать наружу.

Да хрен его знает что там надо на самом дел...

Хотя скорее всего я ступил, да...

В исходном коде это return из main, то есть free самой системой.

Не стоит надеяться на систему..

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

Последний кусок файла

Строки файла заканчиваются обычно переводом строк, а не '\0'.

Не стоит надеяться на систему..

Не стоит надеяться на того, кто вам такое сказал. Ибо такой системой пользоваться нельзя.

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

Строки файла заканчиваются обычно переводом строк, а не '\0'.

Почти всегда:

http://www.open-std.org/jtc1/sc22/wg14/www/docs/n1570.pdf

7.21.2

Whether the last line requires a terminating new-line character is implementation-defined.

Не стоит надеяться на того, кто вам такое сказал.

Там же

7.22.4.3

Ибо такой системой пользоваться нельзя.

Это уже другой вопрос.

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

Почти всегда:

Вы вообще разницу для начала уясните между new-line и zero-terminate, а потом ищите уже ключевые слова в дурацких pdf-ах.

Это уже другой вопрос.

Это тот же самый вопрос из-за непонимания основ.

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

И удивлялся версии бейсика в которой не было номеров строк (как по готу переходить то?)

В таком бейсике были метки.

А тут прям нормальный код, даже функции есть.

Нормальный с какой точки зрения? Для ученика из пятого класса?

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

Строки файла заканчиваются обычно переводом строк, а не '\0'.

А что такое строки файла? А если у меня файл состоит исключительно из 0x00?

Не стоит надеяться на того, кто вам такое сказал. Ибо такой системой пользоваться нельзя

А потом удивляются, почему же течет память при запущенном приложении.

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

А если у меня файл состоит исключительно из 0x00?

Если у вас 0x00 значимые символы, тогда это не задача от ТСа, когда он хочет работать с буфером функциями str*(). И вообще вы о чём-то своём, обычный тут через зубы выдавленный техноснобизм. Спор с предыдущим оратором был вообще о том, что он думает, что в конце файла вам обязательно встретится '\0'. Ко мне то какие притензии? Мой код, в отличии от всех предложенных тут как раз работает с бинарными файлами точно также. Вы то вообще ничего не предложили.

А потом удивляются,

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

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

В таком бейсике были метки.

Да кэп, спасибо, сегодня вы просто сами себя превосходите!

Нормальный с какой точки зрения? Для ученика из пятого класса?

Человек же сказал «пишу первую программу или около того»:

Не знаю, что такое куча, только начал программировать.

Хороший код для начала.

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

Вы то вообще ничего не предложили.

А должен был?

Тю, а потом удивляются, почему всё тормозит

Глядя на код ТСа я удивлюсь только одному - если оно будет хоть как-то работать.

то эту функцию надо документировать

Достаточно просто дать правильное имя такой функции.

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

А должен был?

Нет, конечно, оставайтесь балаболом и хамом.

Достаточно просто дать правильное имя такой функции.

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

vodz ★★ ()

ОП, ты так пробовал?

char* read_kode(const char *arg){
    FILE * f;
    ssize_t fsz;
    ssize_t rsz;
    char * ret;
    
    f = fopen(arg, "r");

    if (NULL == f){
        return NULL;
    }

    if (fseek(f, 0, SEEK_END)){
        goto error;
    }

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

    ret = malloc(fsz);

    if (NULL == ret){
        goto error;
    }

    rsz = fread(f, ret, fsz);
    
    if (0 != fsz - rsz){
        free(ret);
        goto error;
    }

    fclose(f);
    return ret;

error:
    fclose(f);
    return NULL;    
}

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

if (fseek(f, 0, SEEK_END))

Это не универсально, не всё можно сикать.

ret = malloc(fsz);

Типичная ошибка, для текстовых файлов надо fsz+1 и дописывать '\0' и молиться, что там его в файле нет, или придётся еще возвращать размер файла, чтобы было потом до чего сканировать буфер.

goto error;

Я не являюсь ярым противником goto, но тут вы так переборщили где не надо, что сделали иллюстрацию почему goto плохо.

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

Типичная ошибка

Бывает

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

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

сделали иллюстрацию почему goto плохо.

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

shkolnick-kun ★★ ()