LINUX.ORG.RU

Си /*ошибка сегментирования */


0

0

Собственно, пример из книжки, и пример банальный - программа должна скопировать текст из одного файла в другой. При компиляции через gcc ни одного предупреждения, или чего-то подобного. Но потом в терминале при запуске «Ошибка сегментирования».



#include "stdafx.h"
#include "stdlib.h"


void err(int e);
int main(int argc, char*argv[])
{
	FILE *in, *out;
	char *ch,line[255];

	if (argc!=3) {
		printf("You should select input and output files. \n");
		exit(1);
	}
	if ((in=fopen(argv[1], "r"))==NULL) {
		printf("Unable to open user`s file for reading %s. \n", argv[1]);
			exit(1);
	}
	if ((out=fopen(argv[2], "w"))==NULL) {
		printf("Unable to open user`s file for writing %s. \n", argv[2]);
		exit(1);
	}

	
	do {
		ch=fgets(line,sizeof(line),in);
		fputs(ch,out);
	} while(!feof(in));
	fclose(in);
	fclose(out);
	return 0;
}


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

Тут разницы нет, эта функция работает абсолютно корректно - она лишь копирует нужное количество символов. Более того, файл копируется полностью(можно проверить выводом на стандартный ввод) и потом вылетает "Ошибка сегментирования" и программа завершает работу.

dogged
() автор топика

Внимательно читаем man fgets, особенно строчку:
gets() and fgets() return s on success, and NULL on error or when end of file occurs while no characters have been read.

И теперь делаем:
if (ch != NULL) {
fputs(ch,out);
}

gaa ★★
()

Я, конечно, библиотеку C знаю хреново, но...

"stdafx.h is a file, generated by Microsoft Visual Studio IDE wizards, that describes both standard system and project specific include files that are used frequently but hardly ever changed." (c) Wikipedia

Это точно gcc?

После замены stdafx на stdio всё работает. Правда, неправильно (и неудивительно). Ты хоть сам попытался проинтерпретировать эту программу у себя в голове?

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

gaa, если подсунуть NULL вместо !(feof(in)), то ошибка та же самая.

Miguel, да, я просто писал на ноуте а код еще перед тем как отправлять проверил с домашнего компа, потому stdhio.h заменил на stdafx.h

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

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

> gaa, если подсунуть NULL вместо !(feof(in)), то ошибка та же самая. 

Вот тебе полный код. Он работает:

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

void err(int e);
int main(int argc, char*argv[])
{
   FILE *in, *out;
   char *ch,line[255];

   if (argc!=3) {
      printf("You should select input and output files. \n");
      exit(1);
   }
   if ((in=fopen(argv[1], "r"))==NULL) {
      printf("Unable to open user`s file for reading %s. \n", argv[1]);
         exit(1);
   }
   if ((out=fopen(argv[2], "w"))==NULL) {
      printf("Unable to open user`s file for writing %s. \n", argv[2]);
      exit(1);
   }

   
   do {
      ch=fgets(line,sizeof(line),in);
      if (ch != NULL) {
        fputs(ch,out);
      }
   } while(!feof(in));
   fclose(in);
   fclose(out);
   return 0;
}

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

> Спасибо, а как еще можно закончить читать файл при достижении его конца.

Это такой дзен-буддизм: читать после EOF? :)

Попробуй всё-таки дочитать книжку до конца, а потом почитать маны на fopen/fclose/fread/fwrite/fgetc/fputc/fgets/fputs

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

>Спасибо, а как еще можно закончить читать файл при достижении его конца.
[telephaty]
Можно считать размер файла и количество считанных байт
после того как количество прочитаных байт=размеру файла закончить чтение
[/telephaty]

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

=р Вот он, способ наиболее правильный на мой взгяд.) Не вызывающий таких косяков, как проверка на feof.

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

> =р Вот он, способ наиболее правильный на мой взгяд.) Не вызывающий таких косяков, как проверка на feof.

Там ещё и проверок на ошибки нет, так что тоже не хорошо.

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

> Можно считать размер файла и количество считанных байт после того как количество прочитаных байт=размеру файла закончить чтение

Особенно глупо это будет выглядеть, если возьмёшься читать из пайпа или сокета :)

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

>Особенно глупо это будет выглядеть, если возьмёшься читать из пайпа или сокета :)

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

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

>=р Вот он, способ наиболее правильный на мой взгяд.) Не вызывающий таких косяков, как проверка на feof.

Мсье не желает поделиться свежими билдами libastraal, чтобы заранее узнавать сколько считать из pipe'а?

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

> Однако, если файл не текстовый и в середине будет нулевой байт, то фокус с fgets может не удасться

да ну? это как это, интересно знать?

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

> Однако, если файл не текстовый и в середине будет нулевой байт, то
фокус с fgets может не удасться

Почему же? fgets возвращает указатель на первый символ, в случае,
если этим символом будет нулевой символ, указатель от этого NULL-евым
не станет.
[ NULL ]


[fgets_ret]
    |
    |
    v
[ sym1 ][ sym2 ]...[ symn ]

В случае ошибки:

[ NULL ]
    ^
    |
[fgets_ret]

В случае нулевого символа:

[ NULL ]


[fgets_ret]
    |
    |
    v
[ '\0' ][ sym2 ]...[ symn ]

Т.е. нулевым будет *(fgets(...)), а не fgets(...)

Как я понимаю.

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

>> Однако, если файл не текстовый и в середине будет нулевой байт, то
фокус с fgets может не удасться

> Почему же? fgets возвращает указатель на первый символ, в случае,

если этим символом будет нулевой символ, указатель от этого NULL-евым
не станет.

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

Проверь сам на этом файле:

$ xxd -r <<EOF
> 0000000: 6162 6162 6162 6100 6364 6364 6364 6364 abababa.cdcdcdcd

> EOF

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