LINUX.ORG.RU

Изменение адреса массива структур после выхода из функции

 , , , ,


0

1

Добрый день! После помещения адреса массива структур в функцию и изменения некоторых полей, адрес массива изменяется. Я не так давно начал учиться, и не первый раз сталкиваюсь с этой проблемой, перерыл много ресурсов и никак не могу найти ответ: почему???))

Есть файл struct_list.h, в котором нечто подобное:

struct tegTODO_STRUCT
{
char task[100];
char date[15];
};
typedef struct tegTODO_STRUCT TODO;

В main.c я инициализирую массив структур:

...
TODO todo_list[100];

Далее идёт функция (вынесенная в отдельный файл operations.c, объявляется в operations.h): В main’е:

...
add_task(todo_list, ...);
...

Файл operations.h:

...
void add_task(TODO* todo_list, ...);
...

В самой функции я добавляю значения в одну структуру массива todo_list:

void add_task(TODO* todo_list, ...)
{
...
sscanf(task, "%[^\n]%*c", todo_list[i].task);
sscanf(task, "%s", todo_list[i].date);
}

После чего начинаются интересные и непонятные мне вещи. Причём код в одном файле работал, проблемы начались после экспериментов (хочу научиться на маленьких задачах делать большие проекты) с разнесением кода по разным файлам. Программа компилируется, запускается до места следующего использования данной структуры, дальше Segmentation falt. Выяснил, что внутри функции всё работает, данные в структуру записываются (выводил всё через printf в консоль). Веселье начинается на выходе из функции, при возвращении в main. Выводил адреса массива структур todo_list: в main’е до функции, внeтри функции до самого конца адрес массива один, а сразу после функции печатаю тот же адрес массива -, а он другой.. Соответственно, отсюда и Segmentation falt: адреса то нет такого. Объясните, пожалуйста, знающие люди, в чём загвоздка, и чего я не понимаю. Везде, где печатал адрес, строка:

printf("%d", todo_list);

Заранее спасибо!!!

Похоже, что проблема тут в типах и том, как они приводятся. К примеру, компилятор знает, что тип этой переменной:

TODO todo_list[100];

Это массив из 100 элементов типа TODO. Но он может привести этот тип к TODO *. Но я не уверен, что тут тип будет приведён как Вам нужно:

sscanf(task, "%[^\n]%*c", todo_list[i].task);
sscanf(task, "%s", todo_list[i].date);

Попробуйте явно получить адрес нулевого элемента:

sscanf(task, "%[^\n]%*c", &todo_list[i].task[0]);
sscanf(task, "%s", &todo_list[i].date[0]);

и печатайте адрес нулевого элемента массива:

printf("%d", &todo_list[0]);
dsl
()

По симптомам - ты где то пишешь за границу массива, и видимо переписываешь указатель на массив в main. Наглядно, где это происходит ты можешь с помощью gdb watchpoints например, или передав указатель на указатель на массив в фукнцию добавления тасок и логгируя этот указатель там. Мне лень разбираться, но, предположу, что дело в способе ввода, он никак не ограничен по размеру и может легко выйти за границы буфера. Странно только, что не переписывается адрес возврата.

pon4ik ★★★★★
()

А тебе точно надо писать это на С? Умные дядьки давным-давно придумали как избежать детских проблем с сырыми указателями и ручным управлением памятью.

anonymous
()
sscanf(task, "%[^\n]%*c", todo_list[i].task);
sscanf(task, "%s", todo_list[i].date);

Объясни, какой в этих вызовах смысл?

Попробуй так:

sscanf(task, "%99[^\n]%*c", todo_list[i].task);
sscanf(task, "%14s", todo_list[i].date);
anonymous
()

Лучше бы вы полный код привели, т.к. вы опустили большое количество тех самых тонких-слабых мест.

printf("%d", todo_list); // для вывода указателя нужно "%p"

Плюс могу ошибаться, но

sscanf(task, "%[^\n]%*c", todo_list[i].task);

Ничего не читает, но пропускает символы

AKonia ★★
()

минимальный воспроизводимый пример в студию! иначе не было.

deep-purple ★★★★★
()
Ответ на: комментарий от pon4ik

Нашел ошибку

Спасибо за совет! Просто я думал, что уж указатель то переписываться не должен, и полдня пытался понять, почему и где это происходит))) А дело действительно размере;) В самой структуре я выделил памяти на 100 символов и решил, что с запасом хватит, а в функции ввел временную переменную, чтоб в неё с помощью strcat записать все аргументы кроме последнего. И её я сделал маленькой, подумав, что strcat, добавляя строки, добавляет и память))))

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

Он считывает все символы до \n, вместе с пробелами.

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

Спасибо за совет! Именно с памятью в одном месте ошибся, по незнанию)) Так и буду делать в дальнейшем.

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

Ответ оказался чуть проще)) хотя насчет типов тоже были сомнения, конечно (они постоянно есть, благо, поводов в Си хватает). Памяти я мало в одном месте выделил, думал, что strcat при добавлении строки сам память добавляет. А оказалось, что нет. Ошибку нашел. Просто не думал, по отсутствию опыта, что указатель на сам массив можно переписать, и на этом потратил много времени на поиски. Отчаявшись, написал сюда)))

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

Если есть сомнения по поводу той или иной функции из стандартной библиотеки, то могу порекомендовать cppreference.com. Хорошо что нашли ошибку :)

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