Я пытаюсь лучше узнать, как работает указатель на C и указатель на указатель на структуру вещей. У меня есть 3 вопроса:
i
чтобы он указывал на правильный элемент массива, и (3) добавить смещение id поле структуры. И после этого я получу адрес, где я могу записать значение id
в памяти, не так ли? Правильно ли я делаю это?Почему значение * тестов было изменено? Переполнение буфера?
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: Обновлен код цикла от одной чудовищной линии к пошаговым действиям.
Предполагая, что вы хотите, чтобы tests
были array-of-pointers-to-struct-TestCase
с 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
, но это не влияет на математику в последующих двух строках.
В ваших тестах кода есть тройной *, удалите дополнительный * из строки malloc и проверите задания [0] → id.
Если вам нужен высокий уровень доступа к смещению, назначьте значения, как вам было раньше, в вопрос 1. IE - тесты [0] → id = 0x3834 или memcpy для динамических присвоений. Нет необходимости во всех этих ссылках и переводах.
Потому что тесты были завербованы в первой строке вашего итератора.
Благодаря @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