LINUX.ORG.RU

Ошибки при сборке тренировочного задания по C

 , , , ,


1

2

Есть код на C, для выполнения тренировочного задания: напишите программу для вывода всех строк входного потока, имеющих длину более 80 символов. Вот код: http://ix.io/12jI

Собираю с помощью GCC, вот выхлоп "cc -v"

Using built-in specs.
COLLECT_GCC=cc
COLLECT_LTO_WRAPPER=/usr/lib/gcc/x86_64-linux-gnu/4.9/lto-wrapper
Target: x86_64-linux-gnu
Configured with: ../src/configure -v --with-pkgversion='Debian 4.9.2-10' --with-bugurl=file:///usr/share/doc/gcc-4.9/README.Bugs --enable-languages=c,c++,java,go,d,fortran,objc,obj-c++ --prefix=/usr --program-suffix=-4.9 --enable-shared --enable-linker-build-id --libexecdir=/usr/lib --without-included-gettext --enable-threads=posix --with-gxx-include-dir=/usr/include/c++/4.9 --libdir=/usr/lib --enable-nls --with-sysroot=/ --enable-clocale=gnu --enable-libstdcxx-debug --enable-libstdcxx-time=yes --enable-gnu-unique-object --disable-vtable-verify --enable-plugin --with-system-zlib --disable-browser-plugin --enable-java-awt=gtk --enable-gtk-cairo --with-java-home=/usr/lib/jvm/java-1.5.0-gcj-4.9-amd64/jre --enable-java-home --with-jvm-root-dir=/usr/lib/jvm/java-1.5.0-gcj-4.9-amd64 --with-jvm-jar-dir=/usr/lib/jvm-exports/java-1.5.0-gcj-4.9-amd64 --with-arch-directory=amd64 --with-ecj-jar=/usr/share/java/eclipse-ecj.jar --enable-objc-gc --enable-multiarch --with-arch-32=i586 --with-abi=m64 --with-multilib-list=m32,m64,mx32 --enable-multilib --with-tune=generic --enable-checking=release --build=x86_64-linux-gnu --host=x86_64-linux-gnu --target=x86_64-linux-gnu
Thread model: posix
gcc version 4.9.2 (Debian 4.9.2-10)
Получаю ошибки:
hw.c:5:5: error: conflicting types for ‘getline’
 int getline(char line[], int limit);
     ^
In file included from hw.c:1:0:
/usr/include/stdio.h:678:20: note: previous declaration of ‘getline’ was here
 extern _IO_ssize_t getline (char **__restrict __lineptr,
                    ^
hw.c:16:5: error: conflicting types for ‘getline’
 int getline(char line[], int limit) {
     ^
In file included from hw.c:1:0:
/usr/include/stdio.h:678:20: note: previous declaration of ‘getline’ was here
 extern _IO_ssize_t getline (char **__restrict __lineptr,
Не могу понять, что не так. Пожалуйста, помогите разобраться.

★★

Функция getline() уже есть в стандартной библиотеке, имя занято. Выбери для своей функции другое имя.

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

Жёстко. У меня с той же ошибкой не собирался написанный в K&R пример, в котором самопальная функция тоже называлась getline. Я тогда просто пожал плечами и пошёл дальше, но, тысяча чертей, как же так? Переименовал в mygetline, собралось, спасибо.

Norong ★★
() автор топика

error: conflicting types for ‘getline’

Ты объявляешь функцию с именем уже существующей, объявленной в stdio.h. Проблема ещё и в том, что функция getline (твоя) делает не то, что заявлено (как бы get line — «получить строку», а возвращает int). Ну и вообще к коду вопросов много возникает, но это уже оффтоп

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

Ну, она возвращает-то int, но ещё и строку пишет в нужную переменную. Я там уже нашёл ещё косяк в том, что у меня в функции getline символ s нигде не считывается (починил), и в printf лишний перевод строки (убрал). Если там что-то ещё не так, не расскажешь? Мне будет полезно поразгребать свои косяки.

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

K&R

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

Я раньше думал, что это у программистов синдром «смотри, как я могу». А оказалось, что трюкам учат в K&R.

i-rinat ★★★★★
()
Ответ на: комментарий от Norong

К тому, откуда такие ошибки берутся: разные полезные функции были стандартизированы позже издания книги. Часть в c99/c11, часть в POSIX 2003/2008 (как getline). По умолчанию GCC компилирует вариант C, который GNU-C (gnu11 в 5.3) и в котором включены разные стандарты и расширения. Если компилировать с помощью команды c89 или gcc -std=c89, то таких конфликтов быть не должно.

xaizek ★★★★★
()
$cat more80.c
#include<stdio.h>
#define NLENGTH 80+1

main(){
	char c,head[NLENGTH+1];
	head[NLENGTH]='\0';
	int pos=0;
	while(EOF!=(c=head[pos++]=getchar())){
		if(pos==NLENGTH){
			printf("%s",head);
			do{
				c=getchar();
				if(c==EOF){
					break;
				}
				putchar(c);
			}while(c!='\n');
		}
		if(c=='\n'){
			pos=0;
		}
	}
}
anonymous
()
Ответ на: комментарий от xaizek

Спасибо, буду использовать c89 :)

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

Наверное, ошибка в том, что должно быть if(pos != NLENGTH)?

Но мне не всё ясно. Например, форма 80+1 в DEFINE; тот факт, что \0 стоит не последним элементом массива head; что есть do?

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

А не подскажешь ещё, как мне «обнулить» элемент массива, чтобы просто в нём ничего не оказалось?

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

нет переж принтом проверять что с!='\n' иначе(сейчас) на строках которые ровно в 79символов+'\n' программа копирует не только такую строку но и всю следующую за этой строкой строку.

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

как мне «обнулить» элемент массива

= '\0', видимо. Или memset если хочется весь массив, но в этом не должно быть необходимости (первый ноль остановит обработку строки).

чтобы просто в нём ничего не оказалось?

В нём в любом случае будет какое-то значение, у элемента нет специального значения «пустота».

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

У меня тут ещё немного кода: https://gist.github.com/anonymous/6d85dc527599e84d8e556e4b182e882c

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

Что-то оно совсем не работает - строки возвращаются без изменений. Раньше 39 строка выглядела просто как единственная точка с запятой, я думал, что \0 на месте первого пробела/таба из хвоста просто заставить printf хвост отрезать.

Не мог бы ты посмотреть на этот код, если тебя не затруднит?

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

Если там что-то ещё не так, не расскажешь?

Там вообще не нужно создавать вторую функцию. У меня вышло примерно так (функция main() псевдокодом, максимально приближённом к сишке):

char *s;
ssize_t read;
size_t length;

s = NULL;
length = 0;

do
  {
	read = getline(&s, &length, stdin);
	if (length >= LENGTH)
		puts(s);
  } while (read != -1)

return EXIT_SUCCESS;

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

Строки заканчиваются на \n, поэтому проверки на пробелы не срабатывают. Там ещё в цикле в removest нет проверки на то, что i не уйдёт ниже нуля.

я думал, что \0 на месте первого пробела/таба из хвоста просто заставить printf хвост отрезать.

Так и есть. Просто без захода в цикл i сразу указывает на нулевой символ.

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

Понял. Т.е. выходит, что у меня, в зависимости от формата ввода, каждая строка кончается либо на \0, либо на \n\0? В таком случае, если я в цикле for функции removest добавлю '\n' наравне с ' ' и '\t', а в printf добавлю перевод строки, это будет нормальным решением, или это - костыль, и надо придумать что-то ещё?

И насчёт ухода i ниже нуля - а такое возможно в этом случае? Я же каждый раз проверяю, является ли предыдущий символ каким-то из перечисленных. Если нет - то выхожу.

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

если я в цикле for функции removest добавлю '\n' наравне с ' ' и '\t', а в printf добавлю перевод строки, это будет нормальным решением, или это - костыль, и надо придумать что-то ещё?

В той функции костыльно. Если убирать, то после чтения строки (только надо проверять, что там именно этот символ). Добавлять в printf нормально, хотя проще использовать puts, который всегда добавляет перевод строки.

И насчёт ухода i ниже нуля - а такое возможно в этом случае? Я же каждый раз проверяю, является ли предыдущий символ каким-то из перечисленных. Если нет - то выхожу.

Возможно. Перед этим массивом находятся другие данные, если там будут байты с теми же значениями, то i уйдёт в минус.

xaizek ★★★★★
()

update


#include<stdio.h>
#define NLENGTH 80+1

main(){
	char c,head[NLENGTH+1];
	head[NLENGTH]='\0';
	int pos=0;
	while(EOF!=(c=head[pos++]=getchar())){
		if((pos==NLENGTH)&&(c!='\n')){
			printf("%s",head);
			do{
				if(EOF==(c=getchar()))
					return;
				putchar(c);
			}while(c!='\n');
		}
		if(c=='\n'){
			pos=0;
		}
	}
}
anonymous
()
Ответ на: комментарий от xaizek

У меня возник ещё небольшой вопрос. В учебнике мне советуют в конец символьного массива при заполнении помещать '\0', символизирующий конец строки. Но я сейчас просто объявил пустой массив и увидел, что каждый элемент равен как раз-таки '\0'. Нужно ли тогда вручную ставить '\0' в конце строки, если он там, вроде, и так есть, если не поставлено что-то другое?

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

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

Я тут ещё написал код для задания «напишите функцию reverse(s), которая переписывает свой строковый аргумент s в обратном порядке. Воспользуйтесь ею для написания программы, которая бы выполняла такое обращение над каждой строкой входного потока по очереди». Вот что получилось: https://gist.github.com/anonymous/13faebfac1dcaeea1ffdd21425f49232

В принципе, оно работает, но для латинских входных данных всё хорошо, а для кириллицы получается лапша. Что-то мне подсказывает, что хитрость где-то в putchar. Там есть что-то неочевидное при работе с кириллицей?

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

https://ru.wikipedia.org/wiki/UTF-8

скорее всего у тебя utf-8 - поэтому переворачивание мультибайт символов лапшится.

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

Всегда нужно. Нули там потому что стэк выделяется заполненный нулями и это самая верхняя функция. В общем случае там будет мусор.

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

Анонимус всё сказал, дело в мультибайтной кодировке. Там так просто строку не перевернёшь, так как некоторые состоят из больше чем одного элемента массива (становится проще, если преобразовать в или работать с wchar_t).

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

если строка длинее максленч


#include<stdio.h>
main(){
	extern void revst(void);
	extern int g;
	while(revst(),g!=EOF)
		putchar('\n');
}

void revst(void){
	extern int g;
	char c=getchar();
	if(c==EOF||c=='\n'){
		g=c;
		return;
	}
	revst();
	putchar(c);
}

int g;
anonymous
()
Ответ на: если строка длинее максленч от anonymous

update


#include<stdio.h>
main(){
	extern int revst(void);
	while(revst()!=EOF)
		putchar('\n');
}

int revst(void){
	static g;
	char c=getchar();
	if(c==EOF||c=='\n'){
		return c;
	}
	return g=revst(),putchar(c),g;
}
anonymous
()
Ответ на: комментарий от xaizek

И это снова я. У меня тут возникла трудность на этапе придумывания алгоритма для ещё одной задачи /* извини, что я так много за помощью обращаюсь; если тебе это надоело - так и скажи, я умолкну или хотя бы перестану дёргать тебя лично :) */

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

Увидев условие про очень длинные строки, я подумал, что нельзя хранить всю считанную строку в массиве, ведь он может оказаться недостаточно длинным, поэтому решил обрабатывать по символам. Без условия про удаление пробелов и табуляций я получил: https://gist.github.com/anonymous/5f070700119f124c2a000a4bd74bf9ce, это было несложно, но вот с табами и пробелами уже проблема.

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

Я, конечно, могу хранить в двух переменных кол-во полученных табов и пробелов, сбрасывать их на ноль при получении не-таба и не-пробела, а при сбросе выводить M пробелов и N табов. Таким образом, если я табами и пробелами дохожу до нужного столбца, они не выводятся (после этого можно просто сбросить эти две переменные), а все табы и пробелы, после которых идут обычные символы, будут выведены. Выглядеть это будет абсолютно также, но вот структурно у меня табы и пробелы, которые могли быть перемешаны, теперь выстроятся - сначала одно, потом другое. Не совсем то, что нужно, вроде. Ты не мог бы подсказать мне, в каком направлении думать? Заранее спасибо.

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

Я не против поотвечать, оно много времени не занимает.

решил обрабатывать по символам

И отсюда проблемы. Если контекст (здесь: смежные символы) необходим для решения задачи, то не стоит от него избавляться. getline() на самом деле подходит, надо только её применить в свете того, что буфер может быть меньше длины строки. Читать строку по частям это не ошибка, если правильно её обрабатывать.

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

Постарайтесь

Странное условие у задачи. Либо нужно удалять, либо нельзя, либо программа может поступать любым удобным образом. А тут — «постарайтесь».

i-rinat ★★★★★
()
Ответ на: комментарий от xaizek

Я, кажется, понял твой намёк, и накодил вот что: https://gist.github.com/anonymous/167ed1475a4699f143d9718fa2eedae3

В принципе, оно работает, но для входных данных http://ix.io/12ZY (выдели всё целиком, там в концах строк пробелы есть) у меня в выхлопе есть лишняя пустая строка. Изначально код был без onlySpaces и проверки на табы и пробелы в строке 35; я подумал, что эта пустая строка появляется из-за остаточных табов и пробелов, которые не влезают в буфер и оттого не убиваются. Вроде, onlySpaces и та проверка должны были их убить, но пустая строка по-прежнему есть.

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

Хвост из пробелов заканчивается \n и выполнение идёт по else, а буфер пустой, отсюда и пустая строка. Надо как-то отличать пустую строку во входе от такого хвоста.

Кстати, может быть полезно начать осваивать gdb (с --tui). Как раз на простых примерах это легче чем на больших приложениях.

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

man кольцевой буфер.

используешь кольцевой буфер размером чуть больше ширины сворачивания - как раз узнаешь про read write примитивы.

читаешь кусками химичишь пишешь и так

вообще ведь входной поток вот и работой с потоком и буфером(скользящем окном) размера свёртки

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

Ну вот я его вроде и замутил в последнем варианте (на коммент выше твоего).

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

И снова я. Вторая глава, типы данных, и меня просят вычислить (именно вычислить) диапазон значений для типа float. Перед этим были signed/unsigned char/int/short/long, было более-менее ясно, потому что мне сказали, сколько бит под каждый из них отведено, плюс я нашёл полезное в заголовочном файле limits.h; но вот с float мне совсем не ясно - меня посылают смотреть float.h, но там я нашёл только готовые символические константы, содержащие минимум и максимум - а мне вычислить надо. Ты не мог бы подсказать, в каком направлении думать?

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

Там же определены константы *_RADIX, *_DIG и *_EXP. Видимо, предполагается использовать их. Там и формулы в комментариях приведены.

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

зайти со стороны https://ru.wikipedia.org/wiki/IEEE_754-2008

т.е через void* из битов достаточно размерно целого построй нужные(экстремальные по абсолюту большести малости) тебе float|double

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

Там где-то не хватает точности float для промежуточных вычислений и оно выливается в inf. Если вычислять в double, всё должно быть нормально.

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

Заменил все float на double, получил хорошее длинное число. А что за фишка с недостаточной точностью?

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

А что за фишка с недостаточной точностью?

Первый множитель меньше единицы из чего следует, что второй множитель превосходит FLT_MAX, поэтому float power() на нём даст inf из-за невозможности представления в виде float.

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

А double спасает, потому что позволяет большие числа обрабатывать? И ещё: вот говорят - одинарная точность, половинная, двойная. Прочитал на вики. Там же фишка, получается, не только в точности, но и в максимальных значениях? Правильно ли я понимаю, что увеличение кол-ва бит под мантиссу увеличивает точность, а увеличение кол-ва бит под порядок - размер?

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

А double спасает, потому что позволяет большие числа обрабатывать?

Да, диапазон шире и в него эти числа помещаются, что спасает от переполнения.

И ещё: вот говорят - одинарная точность, половинная, двойная. Прочитал на вики. Там же фишка, получается, не только в точности, но и в максимальных значениях?

Ага, я «точность» сказал в общем смысле, без разделение на количество цифр и диапазон.

Правильно ли я понимаю, что увеличение кол-ва бит под мантиссу увеличивает точность, а увеличение кол-ва бит под порядок - размер?

Да, только порядок тоже в своем роде на точность влияет. Например, если порядок отрицательный, то чем диапазон порядка меньше тем больше придётся отбросить для очень малых чисел при их округлении (это, вроде, тоже к слову «точность» подходит).

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

Отлично, я всё понял, спасибо :)

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