Адрес указателя C изменяется без присваивания

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

printf("B: %p\n", txt->point);
for(i = 0; i < input_sz; i++)
{
    txt->point[i] = input[i];
}
printf("A: %p\n", txt->point);

дает вывод:

B: 0x7fc111803200
A: 0x7fc111803265

где B — значение до, а A — значение после копирования.

Любая помощь в отладке будет очень признательна!


РЕДАКТИРОВАТЬ: Вот еще код:

Структура:

struct text_storage {
    char* start;
    char* point;
    char* end;
} typedef text_t;

Функция инициализации:

text_t* text_init(void *memory, size_t size)
{
    text_t* to_return;
    if(size < sizeof(text_t))
    {
        return NULL;
    }
    to_return = (text_t*) memory;
    to_return->start = to_return;

    to_return->end = to_return->start + size;
    to_return->point = to_return->start;

    printf("Start: %p, point: %p, end: %p, end-start: %d\n", to_return->start, to_return->point, to_return->end, (to_return->end - to_return->start));


    return to_return;
}

Метод сохранения текста, в котором возникает ошибка:

int text_store_entry(text_t *txt, const char *input, size_t input_sz)
{
    int to_return;
    char* begin = txt->point;
    int i;

    if(input_sz > (txt->end - txt->point))
    {
        return -1;
    }

    printf("Start: %p, point: %p, end: %p, end-start: %d\n", txt->start, txt->point, txt->end, (txt->end - txt->start));


    printf("B: %p\n", txt->point);
    for(i = 0; i < input_sz; i++)
    {
        txt->point[i] = input[i];
    }
    printf("A: %p\n", txt->point);

}

Основная функция (только в целях тестирования):

int main(int argc, char* argv[])
{
    void* memory = malloc(10000);
    char* a = "hei pa deg din trekkbasun";
    text_t* txt;
    int memoverwritten;

    txt = text_init(memory, 10000);

    memoverwritten = text_store_entry(txt, a, (size_t)26);


    printf("got through\n");
    return 0;
}

person Henrik Hillestad Løvold    schedule 21.09.2013    source источник
comment
Показать объявления и другой код. - возможно Неопределенное поведение   -  person Grijesh Chauhan    schedule 21.09.2013
comment
Добавлено много кода. Спасибо @GrjeshChauhan   -  person Henrik Hillestad Løvold    schedule 21.09.2013
comment
Но я не вижу, где вы вызываете функцию text_store_entry()?   -  person Grijesh Chauhan    schedule 21.09.2013
comment
Это в основной функции, я добавлю. Это только для целей тестирования.   -  person Henrik Hillestad Løvold    schedule 21.09.2013
comment
to_return->start = to_return; выглядит неправильно start является указателем char*, а to_return имеет тип text_t*.   -  person Grijesh Chauhan    schedule 21.09.2013
comment
void* memory = malloc(10000); неправильно, должно быть void* memory = malloc(10000 * sizeof text_t); даже тогда много ошибок. и 10000 не лучший выбор.   -  person Grijesh Chauhan    schedule 21.09.2013
comment
@GrjeshChauhan Кажется, это действительно работает. Когда я делаю первую печать, он говорит: Начало: 0x7fc111803200, точка: 0x7fc111803200, конец: 0x7fc111805910, конец-начало: 10000   -  person Henrik Hillestad Løvold    schedule 21.09.2013
comment
Ха-ха, я тоже работаю над этим заданием! +1 за актуальность (моим интересам)   -  person Plasma    schedule 22.09.2013


Ответы (2)


Проблема скорее всего связана с инициализацией структур типа struct text_storage. Такие структуры содержат три указателя на текст. Каждый указатель должен быть инициализирован, возможно, с помощью malloc. Ваша функция text_init не делает этого должным образом. На самом деле место хранения указателя start перекрывается с первыми байтами той памяти, которую вы хотите использовать.

Я предполагаю, что вам нужна такая структура:

typedef struct text_storage {
    char* start;
    char* point;
    char* end;
    char* data;
} text_t;

инициализируется такой функцией:

text_t text_init(void *memory, size_t size)
{
  text_t to_return;
  to_return.data = (char *) memory;
  to_return.start = to_return.data;
  to_return.end = to_return.start + size;
  to_return.point = to_return.start;
  return to_return;
}
person nickie    schedule 21.09.2013
comment
Присваивание указывает, что единственное пространство кучи, которое нам разрешено использовать, — это то, которое передается функции text_init. Нам не разрешено резервировать память кучи за пределами этого блока. Боюсь, это оставляет меня без malloc :( - person Henrik Hillestad Løvold; 21.09.2013
comment
Хорошо, нет malloc, см. выше. Если вы хотите, чтобы memory сохранял полную структуру, вам понадобится структура с последним полем переменного размера, см. здесь. - person nickie; 21.09.2013
comment
Благодарю вас! Итак, вы используете другой указатель на данные? Что вы думаете об изменении начального и конечного указателей на массивы нулевой длины? Тогда они будут занимать 0 байт и указывать только на что-то в памяти, верно? - person Henrik Hillestad Løvold; 21.09.2013
comment
Вы не можете иметь два массива нулевой длины в одной и той же структуре. У вас может быть только одно такое поле, и оно должно быть последним. Это уловка, полезная, если у вас есть структуры, фактическая длина которых вам неизвестна, но известны только их первые поля. Избегайте этого, если можете. - person nickie; 21.09.2013
comment
Спасибо, я пытаюсь следовать вашему совету здесь, но я получаю ошибку компилятора в строке to_return.end = to_return.start + size;. Есть идеи, почему? Я не понимаю, почему это не сработает. - person Henrik Hillestad Løvold; 21.09.2013
comment
Что говорит ошибка компилятора? Здесь компилируется нормально. У вас есть #include <stdlib.h>, я полагаю (он нужен для size_t). - person nickie; 22.09.2013

Выведите txt->point в цикле и посмотрите, в какой точке он изменится. Я предполагаю, что это меняется при назначении txt->point[0]. Я не полностью знаком с printf, поэтому я не уверен, что он выводит для вас, но имя массива ссылается на первое местоположение. Если printf выводит указатель, txt->point[i] всегда является указателем на char, а printf может разыменовывать txt->point, что даст ему первую запись, а затем покажет там адрес, который вы назначаете когда вы меняете точку на input[i].

person Charles J. Daniels    schedule 21.09.2013
comment
Это кажется правильным. Адрес точки изменяется на новое значение (+65 от начала) при входе в первую итерацию и сохраняет это значение на протяжении всего цикла. При печати адреса txt-›point[i] внутри цикла я вижу, что он перемещает 4 байта на каждой итерации. Что имеет смысл, потому что мы храним символы. - person Henrik Hillestad Løvold; 21.09.2013
comment
В этом случае измените оператор printf на print &txt-›point[0], и, надеюсь, он останется постоянным, показывая, что ваш массив не движется. Хотя я бы не ожидал, что printf будет меняться на каждой итерации, как вы говорите, поэтому мне интересно. - person Charles J. Daniels; 21.09.2013
comment
Такая отладка не нужна, проблема ясна. При инициализации структур txt, &(txt->start) и txt->start все указывают на один и тот же адрес (memory). Когда вы начинаете добавлять текст, вы стираете значение txt->start. - person nickie; 21.09.2013