LINUX.ORG.RU

Help. C.


1

2

Доброго времени суток. Изучаю C. Столкнулся с проблемой: если я открываю 2 разных файла при помощи fopen, то при использованиие gets или fgets вылетает

Segmentation fault

Если fopen использован 1, то все хорошо.

Где искать ошибку?

Сильно не бейте.


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

Я просто говорю, что делать инкремент к массиву нельзя. Зачем ты вообще переходишь на оскарбления? Если что-то не нравится, проходи мимо.

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

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

Да, в сишке n может быть не константой.

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

Ну ТС где-то в начале ветки написал:

В первом случае мы не можем сделать s++, а во втором можем

а модификатор константности снимает эквивалентность. Просто признай, что сам плохо в С разбираешься, не верти, а прими удар судьбы.

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

КР протухшее говно, нахрен ты его приплетаешь, нихрена даже о нём не знаешь?

Для справки - {} - это не отсутвие инициализации, а нулевая(пустая) инициализация.

char * str = (char[256]){};//тут будет 256 нулей.
char str1[256];//тут же будет 256 неинициализированных значений.

В первом случае str является указателем, который можно менять. str ты можешь менять, ++str - это инкримент, оператор изменяющий значение. Он возвращает изменённое значение str;

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

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

С той же вершины пролей свет на «что в данном случае является модификатором константности».

momo
() автор топика
Ответ на: комментарий от momo
int main(int argc, char * argv[]) {
  size_t len = strlen(*argv) + 1;//runtime
  char buf[len];//runtime
  fprintf(stderr, "%s\n", memcpy(buf, *argv, len));
}

Выходит такое:

int main(int argc, char * argv[]) {
  size_t len = strlen(*argv) + 1;//runtime
  fprintf(stderr, "%s\n", memcpy(alloca(len), *argv, len));
}

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

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

Ты попираешь одну из основ работы с указателями в сишке - это воид. Воид это не «пустой» указатель(указатель на пустоту), как думают всякие плюсовые балаболы.

Воид - это ВАЛИДНЫЙ указатель на всё что угодно с ВАЛИДНЫМ АВТОМАТИЧЕСКИМ кастом в воид и из воида.

Поэтому когда твоя функция возвращает void * - она ВАЛИДНО автоматически кастится во все типы указателей. ТАк же как и все типы указателей ВАЛИДНО автоматом кастятся в воид.

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

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

Спасибо. Если будет у тебя время, King of C, чиркни мне в скайп или на почту, я тебя пару вопросов задам, докучать не буду.

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

Ничего. Может попытаться почитать новые стандарты - там много всяких примеров. А так все учебники и рядовые сишники завязли в 70-80-х. Если ты хочешь знать сишку на уровне ansi C, либо ещё более раннего KR С, то КР тебе хватит.

c89 разбирается в любом учебнике, вменяемых учебников чего-то выше я не видел.

Учебников которые учат пониманию сишки я вообще не видел, разве чутка в КР и помелочи. Да и вообще способность понять сишку это врожденное, а не приобретаемое. Это определённое мировоззрение. Которое формируется не учебниками.

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

Я не юзаю этот анальный маздайский зонд.

Есть вопросы - пиши на лоре(создавай тему) - я отвечу. И мы разные аннонимусы.

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

Я тут должен обратить внимание на массив argv? Что тут удивительного произошло и я не уловил?

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

Это пример, тут у массива buf[n] n не является константой, а вычисляется в рантайме.

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

man 3 free

The free() function frees the memory space pointed to by ptr, which must have been returned by a previous call to malloc(), calloc() or realloc(). Otherwise, or if free(ptr) has already been called before, undefined behavior occurs. If ptr is NULL, no operation is performed.

Это память в куче, а на стеке массив автоматичен, его не нужно освобождать — накатываем и зануляем если нужно (иначе мусор), либо берём статичный массив, либо в куче, если на стеке, то C99 умеет VLA, если нужен указатель на что-то в массиве, то указатель:

static char s[128]; // нули, статично

char s[128]; // мусор, стек

char s[128] = { 0 }; // опять нули, стек

char s[n]; // VLA, стек, мусор
memset(s, 0, n); // нули

char *s = malloc(n); // мусор, куча
memset(s, 0, n); // нули

char *s = calloc(n, 1); // нули, куча

char *sp = s + 1;
++sp;
quasimoto ★★★★
()
Ответ на: комментарий от anonymous

пока нет. что после к&р почитать по си? подскажите, пожалуйста.

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

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

Т.е. если мы напишем:

char * s = {};// {} - будут иметь тип char *. Это инициализация.

Мы же можем скобочки кастовать во всё, что угодно:

char * s = (char[128]){};//в данном случае это 128*sizeof(char); В данном случае это уже не инициализатор, а копирование, а конструктор - создание "объекта". В данном случае массива.

Если мы напишем так:

char m[128] = (char[128]){};// тут копирование массива из коснтруктора(безымянного) в массив m. Но массивы в сишке не копируются присваиванием, поэтому будет ошибка. Вернее присваивается указатель, а m константа, пэтому ошибка.

Память у конструктора имеет тип в зависимости от области применение. Т.е. внутри функции - это стек, а в глобальном пространстве «статическая» память.

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

Тыж читал стандарт, ответь мне на вопрос:

По логике VLA должно дёргать кучу на конечном стеке. Т.е. конпелятор должен отслеживать переполнение стека и когда юзается char s[100500000]; он стек юзать не должен. Об этом есть что-либо в стандарте? Или там поклали на это?

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

cast int13h;

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

Возможно они есть - я их не знаю. В основном книги это рецепты по готовке.

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

Можно почитать новые стандарты - там есть много примеров.

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

А можешь подкинуть примеры задач, на которых поучиться?

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

в КР какой стандарт учитывается? читать последний или все после того, который учитывается в КР?

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

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

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

В КР КР си, ибо писали её до с89. В основном везде с89.

Читать с99 с11.

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

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

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

Пруфец будет?

Тыж наверное понимаешь, что {0} - это инициализация первого елемента? И в этой конструкции логики нет.

Т.е.

void f(void) {}//тоже плюсовая ссанина?

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

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

Уж сколько стека жрёт функция он может посчитать и запилить оптицию - предел стека для функции проще паренной репы. Ввести ratio для аллокаций, т.е. если аллоцируется на стеке больше чем 20-30% стека - вставлять рантайм проверку.

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

а еще в мане gets написано: никогда не используйте gets()

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

Поищи на сошке по словам «c initializer», лень копаться. Второе не инициализатор, зачем шланга включать?

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

Количнство стека заюзанного до функции не проще пареной репы, это очевидно имхо. И зачем эта глупая логика с процентами, если она не закрывает вопрос. Просто пища для размышлений, без претензии на пруф.

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

хм, для меня стало откровением, что указатель занимает 8 байт, а int при этом 4 :) мне казалось, что на x64 и int должен быть 8 байт

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

читай алгоритмы Седживика на си и еще есть не плохая книжка по лекциям мфти Ворожцов и Винокуров «алгоритмы...» по сути k&r достаточно чтобы более или менее понимать си.

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

В стандарте я не вижу чего-либо про кучу или стек. Там есть понятия объектов, памяти, размещения (статичного, тред-локального, автоматического и аллокцируемого), времени жизни и области видимости, так что синтаксические конструкции нестатических массивов/VLA будут иметь автоматическую память в своём блоке, а аллокация динамической памяти осуществляется с помощью библиотечных функций.

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

А зачем вы пишите в скобочках ноль?

{} это C++ фича, не С. В С неполная инициализация инициализирует первую часть как сказано, а остальное — нулём, так что { 0 } это частный случай который инициализирует первый элемент нулём и остальные им же (т.к. неполная инициализация, правда в случае массива неизвестной длинны так будет выводиться единичная длинна).

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

Количнство стека заюзанного до функции не проще пареной репы, это очевидно имхо.

А причем тут кол-во стека заюзанного до функции? Я где-то про это говорил?

И зачем эта глупая логика с процентами, если она не закрывает вопрос.

Она закрывает вопрос на 98%.

Просто пища для размышлений, без претензии на пруф.

В каком месте? Отвечая мне на то, о чем я не писал и не спрашивал, после чего отвечая ещё раз на то, чего я не писал? Гениально.

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

) мне казалось, что на x64 и int должен быть 8 байт

Чем ты руководствовался, когда тебе это казалось?

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

Куча в сишной аналогии есть аллоцируемая/динамическая память. Правда вся сишная терминалогия бесполезное убожество, поэтому я её не юзаю.

Значит про это ничего нету, ок.

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

Чтобы соответствовать стандарту вообще напрягаться не нужно — можно не использовать регистров, стека, всё делать через кучу и вообще массивы не хранить непрерывно (лишь бы они выглядели так внутри языка). Все эти вещи это уже не стандарт языка, а стандарт на ABI (http://www.x86-64.org/documentation/abi.pdf) и детали поведения компилятора, стандартной библиотеки и ядра на/для данной архитектуры.

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

{} это C++ фича, не С.

Пруфец будет? Что-то я не нашел упоминания о том, что {} не валидно.

В С неполная инициализация инициализирует первую часть как сказано, а остальное — нулём, так что { 0 } это частный случай который инициализирует первый элемент нулём и остальные им же (т.к. неполная инициализация, правда в случае массива неизвестной длинны так будет выводиться единичная длинна).

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

Ещё раз, где написано, что {} не валиден?

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