Работа с массивом структур в C с использованием указателя на указатель

0

Я пытаюсь лучше узнать, как работает указатель на C и указатель на указатель на структуру вещей. У меня есть 3 вопроса:

  1. Если у меня есть структура и указатель на указатель ** тестов на эту структуру (так что это что-то вроде массива), как я могу использовать p для доступа к членам массива (лучший способ)? тесты [i] → id не работают (пример источника ниже)
  2. Наличие этой чудовищной линии с указателями ниже - это что-то плохое в коде, но я тоже хотел бы работать с ней. Я думаю, что я ошибся с его шаблоном, вывод для каждого следующего структурного адреса выглядит как прыжки 32 байта вперед, а размер структуры - всего 4 байта. Поэтому в строке я хочу (1) взять начальный адрес верхнего указателя тестов, (2) добавить к нему размер структуры TestCase, умноженный на i чтобы он указывал на правильный элемент массива, и (3) добавить смещение id поле структуры. И после этого я получу адрес, где я могу записать значение id в памяти, не так ли? Правильно ли я делаю это?
  3. Почему значение * тестов было изменено? Переполнение буфера?

    struct TestCase{
        int id;
    };
    int main()
    {
        TestCase ** tests;
        cout << "Size of TestCase: " << sizeof(TestCase) << endl;
        *tests = (TestCase*)malloc(sizeof(TestCase*)*5);
        cout << "*tests = " << *tests << endl;
        for(int i = 0; i < 5; i++)
        {
            //*(int*)(tests+sizeof(TestCase)*i+(int)&(((struct TestCase*)NULL)->id)) = i;
    
            int addr = tests; // address of structures array in memmory;
            addr += sizeof(TestCase)*i; //address of current structure;
            addr += (int)&(((struct TestCase*)NULL)->id); // Adding id parameter offset in memory to current address
            *(int*)addr = i; // setting id for current structure equal to i
            cout << (int*)(tests+sizeof(TestCase)*i+(int)&(((struct TestCase*)NULL)->id)) << endl;
        }
        cout << "*tests = " << *tests << endl;
        return 0;
    }
    

    Выход:

    Size of TestCase: 4
    *tests = 0x600048600
    0x23ab90
    0x23abb0
    0x23abd0
    0x23abf0
    0x23ac10
    *tests = 0x600000000
    

PS: Обновлен код цикла от одной чудовищной линии к пошаговым действиям.

  • 1
    Извините, я не могу прочитать эту строку кода, поэтому не могу понять, что это за цель. Таким образом, я не могу помочь вам найти лучший способ написать это! Пожалуйста, объясните, для чего предназначен код.
  • 3
    cout это c ++ кстати
Показать ещё 4 комментария
Теги:

3 ответа

4
Лучший ответ

Предполагая, что вы хотите, чтобы tests были array-of-pointers-to-struct-TestCase с 5 указателями на 5 структур, тогда вам нужно

  • выделить массив из 5 указателей и
  • инициализировать каждый указатель, выделяя память для структуры

Как это:

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

struct TestCase
{
    int id;
};

int main( void )
{
    int i;
    struct TestCase **tests;

    // allocate memory for an array of 5 pointers
    tests = malloc( 5 * sizeof(struct TestCase *) );
    if ( tests == NULL )
        exit( 1 );

    // allocate memory for 5 structures (and save each pointer in the array)
    for ( i = 0; i < 5; i++ )
    {
        tests[i] = malloc( sizeof(struct TestCase) );
        if ( tests[i] == NULL )
            exit( 1 );
    }

    // initialize the id in each struct
    for ( i = 0; i < 5; i++ )
        tests[i]->id = i;

    // print the id in each struct
    for ( i = 0; i < 5; i++ )
        printf( "%d\n", tests[i]->id );

    // free memory
    for ( i = 0; i < 5; i++ )
        free( tests[i] );
    free( tests );

    return 0;
}

Я не смог воспроизвести проблему, описанную в пункте 2. Здесь код, который я попробовал (который я поставил перед кодом, который освобождает память)

printf( "%p\n", tests );
for ( i = 0; i < 5; i++ )
{
    intptr_t addr = (intptr_t)tests;
    addr += sizeof(struct TestCase)*i;
    addr += (int)&(((struct TestCase*)NULL)->id);

    printf( "%p\n", (void *)addr );
}

Выход из кода

0xc03950
0xc03950
0xc03954
0xc03958
0xc0395c
0xc03960

Адрес продвигается на 4 байта, как ожидалось. Обратите внимание, что я изменил тип addr на intptr_t чтобы гарантировать, что указатель может быть корректно intptr_t, но это не влияет на математику в последующих двух строках.

  • 0
    Спасибо за решение с тестами [i] -> id. Теперь я вижу свою проблему. Пункты 1 и 3 отвечают на это, но все же я хочу сделать что-то с 2. Эта строка выглядит для меня настолько удивительно, что выглядит как запутывание кода сама по себе) Обновил эту строку до 3 строк в пошаговых инструкциях, как люди спрашивали в комментариях.
  • 0
    @ArturKorobeynyk Я не смог продублировать проблему, когда адрес скачет на 32 байта. Я обновил ответ объяснением.
Показать ещё 1 комментарий
1
  1. В ваших тестах кода есть тройной *, удалите дополнительный * из строки malloc и проверите задания [0] → id.

  2. Если вам нужен высокий уровень доступа к смещению, назначьте значения, как вам было раньше, в вопрос 1. IE - тесты [0] → id = 0x3834 или memcpy для динамических присвоений. Нет необходимости во всех этих ссылках и переводах.

  3. Потому что тесты были завербованы в первой строке вашего итератора.

  • 0
    Спасибо за ответ, но что касается 2. это был смысл, чтобы эта линия работала) Просто для удовольствия
0

Благодаря @user3386109 я смог наконец сделать все, что хотел. Ну, вместо того, чтобы писать на адрес, используя жуткую формулу, я теперь читаю с адреса, используя ту же жуткую формулу:

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

    using namespace std;

    struct TestCase{
        int ida;
        int idb;
    };

    int main()
    {
        TestCase ** tests; //create pointer to pointer
        cout << "Size of TestCase: " << sizeof(TestCase) << endl;
        tests = malloc(sizeof(TestCase*)*5);
        if(tests == NULL)
            exit(1);
        for(int i=0; i< 5; i++)
        {
            tests[i] = malloc(sizeof(struct TestCase));
            if(tests[i] == NULL)
                exit(1);
        }
        cout << "*tests = " << *tests << endl;
        for(int i = 0; i < 5; i++)
        {
            tests[i]->ida = i;
            tests[i]->idb = i+6;
            cout << std::hex << &(tests[i]->idb) << ": " << *(long*)((long)(long*)(tests[i])+(long)&(((TestCase *)NULL)->idb)) << endl;
        }
        for(int i=0; i<5; i++)
        {
            free(tests[i]);
        }
        cout << "*tests = " << *tests << endl;
        free(tests);
        return 0;
    }

Вывод:

    $ ./a.exe
    Size of TestCase: 8
    *tests = 0x600048630
    0x600048634: 6
    0x600048654: 7
    0x600048674: 8
    0x600048694: 9
    0x6000486b4: a
    *tests = 0x600048630

Ещё вопросы

Сообщество Overcoder
Наверх
Меню