LINUX.ORG.RU

Help. C.


1

2

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

Segmentation fault

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

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

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


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

Нет, динамическая память есть куча, и динамическая память есть в стандарте. И динамическая память/куча есть в либц.

Все эти вещи это уже не стандарт языка, а стандарт на ABI

Никакой жопой они к abi не относятся - это понятия матчасти и libc, которая входит в стандарт. В частности куча.

Ты реально не отличаешь понятия от реализаций? Ты же мне расскажешь какой жопой стек/куча относятся к твоему abi? Ты наверное их спутал с реализацией стека/кучи(вернее про кучу в твоём abi тоже нихрена нет) на х86_64? Дак вот не путай.

Понятие «куча» в стандарте есть. Куча это, чем рулит манагер памяти, который есть в стандарте. Какой синоним там юзается это не важно.

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

Я сказал, что автоматическую память (из стандарта) ты можешь делать хоть через кучу, хоть через нормальный стек, хоть как ещё угодно. Это деталь реализации. Динамическая память в стандарте есть — библиотечные функции, которые ты тоже можешь делать как хочешь (называя кучей или как хочешь, в стандарте про это нет). Аналогично со способом вызова функций, отображением сишной памяти на физическую и прочими деталями реализации.

quasimoto ★★★★
()
Ответ на: комментарий от anonymous
$ make
cc -g -Wall -std=c99 -pedantic x.c -o a.out
x.c:8:25: warning: use of GNU empty initializer extension [-Wgnu-empty-initializer]
    struct timeval tv = { };
arturpub ★★
()
Ответ на: комментарий от anonymous

конпелятор должен отслеживать переполнение стека

Это глупость, которая очевидна и без чтения стандартов.

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

Ещё раз, ты возможно потерял суть разговора, повторю вопрос.

Есть ли что-то в стандарте про юзанье VLA"ом ДИНАМИЧЕСКОЙ ПАМЯТИ.

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

Речь, разумеется, только про инициализацию массивов T x[...] = {...} — стандартный си хочет строго больше нуля вещей вместо ... в фигурных скобках (полная или нет инициализация), а C++ и расширенный гнутый си понимают {}.

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

Я понял про что идёт речь. Дело не в том, такая же схема как ты описал должна быть для блоков кода. Где она?

Мне твоя схема ниочем не говорит, если эта строгая схема для всех синтаксических конструкций, то она должна быть для блоков кода, где должно быть написано как в С++ { }. Я же этого не нашел.

Т.е.

{ bla-bla }
bla-bla: тут всё, что можно юзать в блоке.
{ }//вот этого я не вижу, а должно быть по твоей логике.

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

Это глупость, которая очевидна и без чтения стандартов.

Т.е. ты съехал. Тыж мне найдёшь «конпелятор должен отслеживать переполнение стека» в том комменте, на который ты отвечаешь, ок?

Ещё раз для отбитых - там(откуда ты это скопипастил) говорится про VLA - это РАНТАЙМ(вернее на длину заданную в рантайме) аллокация на стеке. Дак вот, в рантайме можно вычислить кол-во используемого стека.

На то, что ты отвечаешь - я тебе дал решения достаточного в 98% случаев для определения переполнения стека аллокациями.

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

Я уже сказал — int x[n] автоматичен, как и int x[CONST]. Но реализация автоматической памяти через динамическую (то есть в обход стека) никак не противоречит стандарту.

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

void f(size_t n) {
    int x[n];
    memset(x, 0, sizeof(x));
    for (size_t i = 0; i < n; ++i)
        printf("%d\n", x[i]);
}

int main(int argc, char **argv) {
    if (argc > 1)
        f(atoi(argv[1]));
}

/*

$ strace ./a.out 1000 > /dev/null 2>&1 | grep mmap | wc -l 
9
$ strace ./a.out 10000 > /dev/null 2>&1 | grep mmap | wc -l 
9
$ strace ./a.out 100000 > /dev/null 2>&1 | grep mmap | wc -l 
9
$ strace ./a.out 1000000 > /dev/null 2>&1 | grep mmap | wc -l 
9
$ strace ./a.out 10000000 > /dev/null 2>&1 | grep mmap | wc -l 
8
[1]    3075 segmentation fault

$ strace valgrind --max-stackframe=1000000000 --main-stacksize=1000000000 ./a.out 1000 > /dev/null 2>&1 | grep mmap | wc -l 
63
$ strace valgrind --max-stackframe=1000000000 --main-stacksize=1000000000 ./a.out 10000 > /dev/null 2>&1 | grep mmap | wc -l 
64
$ strace valgrind --max-stackframe=1000000000 --main-stacksize=1000000000 ./a.out 100000 > /dev/null 2>&1 | grep mmap | wc -l 
71
$ strace valgrind --max-stackframe=1000000000 --main-stacksize=1000000000 ./a.out 1000000 > /dev/null 2>&1 | grep mmap | wc -l 
126
$ strace valgrind --max-stackframe=1000000000 --main-stacksize=1000000000 ./a.out 2000000 > /dev/null 2>&1 | grep mmap | wc -l 
188
$ strace valgrind --max-stackframe=1000000000 --main-stacksize=1000000000 ./a.out 4000000 > /dev/null 2>&1 | grep mmap | wc -l 
309

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

Синтаксис блоков и функций (6.8.2.1 и 6.9.1.1, C11) и инициализаторов (6.7.9.1, C11) это два разных синтаксиса. Весь синтаксис описан в 6 главе. Либо погугли C BNF, будет компактно, например https://cs.wmich.edu/~gupta/teaching/cs4850/sumII06/The syntax of C in Backus... (<function-definition> , <compound-statement> и <initializer-list>).

quasimoto ★★★★
()
Ответ на: комментарий от quasimoto
$ strace valgrind --max-stackframe=1000000000 --main-stacksize=1000000000 ./a.out 10000000 > /dev/null 2>&1 | grep mmap | wc -l 
675
quasimoto ★★★★
()
Ответ на: комментарий от quasimoto

Синтаксис блоков и функций (6.8.2.1 и 6.9.1.1, C11) и инициализаторов (6.7.9.1, C11) это два разных синтаксиса.

Да, но ты понимаешь, что в синтаксисе блоков функции {} - валидная конструкция, значит она должна быть в синтаксисе блока функции, но я её не вижу.

Как мы выяснили в синтаксисе инициализаторов (6.7.9.1, C11) конструкции {} нет.

Где она в синтаксисе блоков и функций (6.8.2.1 и 6.9.1.1, C11)? Она должна там быть, ибо она валидна.

anonymous
()
Ответ на: комментарий от anonymous
function-definition:
  declaration-specifiers declarator declaration-listopt compound-statement
compound-statement:
  { block-item-list_opt }

opt значит, что block-item-list может отсутствовать — будет {} в качестве compound-statement, то есть тела функции в function-definition.

quasimoto ★★★★
()

Прочёл ник автора темы как «mono». Долго думал.

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

Только вот вопрос по логике, какого хрена в стандарте плюсов(C++11, 8.5.1.) написали не opt, а просто отдельно { }?

Почему не:

aced-init-list:
{ initializer-list_opt ,opt }
а:
aced-init-list:
{ initializer-list ,opt }
{ }

Кто пишет эти стандарты? Ладно была бы у { } какая-то отдельная логика, но её нет.

Отсутвие в С11 пустых скобок-инициализаторов тотальный даунизм, этот «стандарт» годится только для подтирания.

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

Тупой тут ты. Увидь разницу между a++ и a + 5. Инкрементировать так:

char a[128] = "some";
a++;
нельзя.

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

Этот opt относится только к запятой, можно было написать { [initializer-list ,opt]opt } вместо { initializer-list ,opt } | {}, но разницы нет. А смысл у {} (в плюсах) в value-initialization — дефолтные конструкторы, value-инициализация элементов массива, zero-initialization.

Отсутвие в С11 пустых скобок-инициализаторов тотальный даунизм

Ну как бы да — если неполная инициализация инициализирует неполно и делает всё остальное как если бы оно было static, то есть нулём, то совсем неполная инициализация, то есть пустая, должна просто делать всё нулём, что сделали в плюсах и расширениях компиляторов.

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