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;
}


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

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

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

dogged ()

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

Внимательно читаем 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 ★★ ()

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

Я, конечно, библиотеку 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 ★★★★★ ()
Ответ на: Re: Си /*ошибка сегментирования */ от Miguel

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

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

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

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

dogged ()
Ответ на: Re: Си /*ошибка сегментирования */ от dogged

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

> 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 ★★ ()
Ответ на: Re: Си /*ошибка сегментирования */ от dogged

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

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

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

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

gaa ★★ ()
Ответ на: Re: Си /*ошибка сегментирования */ от dogged

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

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

dimon555 ★★★★★ ()
Ответ на: Re: Си /*ошибка сегментирования */ от dogged

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

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

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

gaa ★★ ()
Ответ на: Re: Си /*ошибка сегментирования */ от dimon555

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

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

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

gaa ★★ ()
Ответ на: Re: Си /*ошибка сегментирования */ от gaa

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

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

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

dimon555 ★★★★★ ()
Ответ на: Re: Си /*ошибка сегментирования */ от dogged

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

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

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

teferiincub ()
Ответ на: Re: Си /*ошибка сегментирования */ от dimon555

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

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

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

trapezoid ()
Ответ на: Re: Си /*ошибка сегментирования */ от dimon555

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

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

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


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

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

[ NULL ]
    ^
    |
[fgets_ret]

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

[ NULL ]


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

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

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

Ruth ★★ ()
Ответ на: Re: Си /*ошибка сегментирования */ от Ruth

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

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

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

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

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

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

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

> EOF

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