У меня вопрос по процессу выделения памяти массива. У меня есть массив с именем list, который изначально имеет 3 значения.
The initial of value of the 1th element is: 0
The address of the 1th element is 0x12de06a10
The initial ofvalue of the 2th element is: 0
The address of the 2th element is 0x12de06a14
The initial ofvalue of the 3th element is: 0
The address of the 3th element is 0x12de06a18
The value of the 1th element is: 1
The address of the 1th element is 0x12de06a10
The value of the 2th element is: 2
The address of the 2th element is 0x12de06a14
The value of the 3th element is: 3
The address of the 3th element is 0x12de06a18
Мы используем realloc для увеличения размера массива до 4 и присваиваем значение 4 новому члену списка как таковому:
The value of the 4th element is: 4
The address of the 4th element is 0x12de06a1c
Мой вопрос: как нам быть, когда адрес 0x12de06a1c занят фиктивным значением?
Это мой код:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int *dummy_point = (int*) 0x12de06a1c;
*dummy_point = 20;
int *list = (int*)calloc(sizeof(int), 3);
if (list == NULL)
{
free(list);
printf("Erorr \n");
return 1;
}
//int list[3];
for(int i = 0; i < 3; i++)
{
printf("The initial ofvalue of the %ith element is: %i \n", i+1, list[i]);
printf("\t\tThe address of the %ith element is %p \n", i+1, &list[i]);
}
printf("\n\n");
list[0] = 1;
list[1] = 2;
list[2] = 3;
for(int i = 0; i < 3; i++)
{
printf("The value of the %ith element is: %i \n", i+1, list[i]);
printf("\t\tThe address of the %ith element is %p \n", i+1, &list[i]);
}
//free(list);
// this is just for good practice in order to verify if the newly allocated chunck of memory is valid or not
int *temp = (int*)realloc(list, 5 * sizeof(int));
if (temp == NULL)
{
free(temp);
printf("Erorr \n");
return 1;
}
//if the process is a success the list will take the new values of temp;
list = temp;
list[3] = 4;
printf("\n\n");
for(int i = 0; i < 4; i++)
{
printf("The value of the %ith element is: %i \n", i+1, list[i]);
printf("\t\tThe address of the %ith element is %p \n", i+1, &list[i]);
}
}
Чего-то не хватает, или я не так понимаю?
Непонятно, для чего dummy_point . И вы не можете просто назначить случайный адрес на настольном ПК.
Также память, выделенная с помощью malloc, или новая память, выделенная с помощью realloc, никак не инициализируется. Содержание этой памяти неопределенно. А использование неопределенных значений может привести к неопределенному поведению.
Я понятия не имею, в чем смысл переменной dummy_point. Это не имеет никакого смысла. *dummy_point = 20 - это неопределенное поведение, вы не можете писать/читать в/из произвольного адреса, например, на моем компьютере это заканчивается сбоем. Какой результат вы ожидаете? Чем он отличается от того, что вы получаете?
OT: free(list) бесполезен, когда list равен NULL. OTOH это не делает ничего плохого, так как free(NULL) это NOP (IOW это ничего не делает).
Возможно, вы захотите прочитать это, особенно раздел а).
Спасибо Джаббервоки! за полезный ресурс :D. Цель фиктивного значения - просто имитировать тот кусок памяти, который занят. Просто пытаюсь лучше понять malloc/calloc и realloc, когда вы работаете в средах с ограничениями памяти.
@MirceaPotlogia, вы не можете этого сделать, это не имеет смысла. Важно знать, что если память расширяется с помощью realloc, содержимое новой части массива не определено. Это может быть что угодно, и вы не можете ожидать какой-то особой ценности.
Похоже, что OP предвидел место в памяти, которое станет частью распределения, которое можно было бы узнать, только запустив код без него. С рандомизацией адресного пространства это должно сделать это невозможным, потому что при следующем запуске кода адрес выделения будет другим.
malloc и друзья не предоставят вам память, которая законно занята кем-либо еще.
@Jabberwocky спасибо, теперь я понял!
Вы знаете, что if (temp == NULL) { free(temp); ... } имеет очень мало смысла?
Не важно, но... free(temp); должно быть free(list);
Присвоение фиксированного значения указателю, такому как int *dummy_point = (int*) 0x12de06a1c;, — это то, что вы делаете только при написании низкоуровневого (т.е. близкого к HW) кода. Обычно во встроенных системах, где у вас есть полный контроль/знание об отображении (внешних) устройств в пространство памяти и управление преобразованием адресов (если оно имеется).



Вы не можете инициализировать массив в этом месте и даже не можете объявить, что он там есть.
Однако вы можете использовать указатель для управления значениями, уже существующими в этом месте.
это мой результат без инициализации манекена:
The initial ofvalue of the 1th element is: 0
The address of the 1th element is 0xa00000fd0
The initial ofvalue of the 2th element is: 0
The address of the 2th element is 0xa00000fd4
The initial ofvalue of the 3th element is: 0
The address of the 3th element is 0xa00000fd8
The value of the 1th element is: 1
The address of the 1th element is 0xa00000fd0
The value of the 2th element is: 2
The address of the 2th element is 0xa00000fd4
The value of the 3th element is: 3
The address of the 3th element is 0xa00000fd8
The value of the 1th element is: 1
The address of the 1th element is 0xa00000fd0
The value of the 2th element is: 2
The address of the 2th element is 0xa00000fd4
The value of the 3th element is: 3
The address of the 3th element is 0xa00000fd8
The value of the 4th element is: 4
The address of the 4th element is 0xa00000fdc
Как вы можете видеть, в вашем результате есть разные адреса. Это вызвано различным аппаратным обеспечением, использованием памяти, реализацией компилятора, которые у нас есть. Когда вы инициализируете переменную, адрес переменной, который вы видите, дается только во время выполнения. Перед этим адресом есть и другие этапы.
Давайте проанализируем:
int* dummy_point = (int* ) 0x12de06a1c;
мой результат выполнения после успешной компиляции:
0 [main] a 1730 cygwin_exception::open_stackdumpfile: Dumping stack trace to a.exe.stackdump
вы вводите long int как int*, но 0x12de06a1c — это значение, а не переменная. Компилятор реализован таким образом, что компиляция завершается успешно, потому что синтаксически код правильный, а семантически нет.
это правильный способ увидеть, что компилятор все равно перезаписывает адрес:
int *dummy_point;
dummy_point=(int*)0xa0000042c; //copied address from a previous execution of mine.
*dummy_point = 20;
результат :
The initial ofvalue of the 1th element is: 0
The address of the 1th element is 0xa00000420
The initial ofvalue of the 2th element is: 0
The address of the 2th element is 0xa00000424
The initial ofvalue of the 3th element is: 0
The address of the 3th element is 0xa00000428
The value of the 1th element is: 1
The address of the 1th element is 0xa00000420
The value of the 2th element is: 2
The address of the 2th element is 0xa00000424
The value of the 3th element is: 3
The address of the 3th element is 0xa00000428
The value of the 1th element is: 1
The address of the 1th element is 0xa00000420
The value of the 2th element is: 2
The address of the 2th element is 0xa00000424
The value of the 3th element is: 3
The address of the 3th element is 0xa00000428
The value of the 4th element is: 4
The address of the 4th element is 0xa0000042c
Инициализация статических переменных происходит в два последовательных этапа: статическая и динамическая инициализация.
Статическая инициализация происходит первой и обычно во время компиляции. Если возможно, начальные значения статических переменных оцениваются во время компиляции и записываются в раздел данных исполняемого файла. Это называется инициализацией констант. В идеальном мире все статические переменные инициализируются константой.
Если начальное значение статической переменной невозможно оценить во время компиляции, компилятор выполнит инициализацию нулями. Следовательно, во время статической инициализации все статические переменные либо инициализируются константой, либо инициализируются нулями.
После статической инициализации происходит динамическая инициализация. Динамическая инициализация происходит во время выполнения для переменных, которые не могут быть оценены во время компиляции2. Здесь статические переменные инициализируются каждый раз при запуске исполняемого файла, а не только один раз во время компиляции.
Таким образом, вы просто пытаетесь нарушить правила компиляции, принудительно инициализируя переменную по определенному адресу статически, к динамической переменной, где обращение к ее компетенции компилятора не принадлежит вам.
если вы хотите сделать такое, вам нужно кодировать на ассемблере и создать свой собственный компилятор;)
PS: если вы хотите больше узнать о компиляторах, купите или скачайте книги Дершем - Джиппинг. Языки программирования: структуры и модели.
Вау, спасибо за ваше объяснение! Теперь я полностью понимаю концепцию, большой палец вверх
Я не согласен со следующим предложением: "if you want to do such a thing you have to code in assembler an create your own compiler ;)" -- Программирование на ассемблере или создание собственного компилятора, вероятно, не обязательно. Это скорее зависит от того, какую платформу вы используете. Например, в Linux можно выделить память по определенному адресу с помощью системного вызова mmap . В Microsoft Windows аналогичную функциональность обеспечивает функция VirtualAlloc.
@MirceaPotlogia: Этот «ответ» полон неточностей, неправильного использования языка и ошибок. Вам следует подумать о том, чтобы пометить его как принятый, и вы не должны использовать содержащиеся в нем утверждения.
int *dummy_point = (int*) 0x12de06a1c;? Кто тебя этому научил? Зачем ты это делаешь? Что это за проблема, и следующее*dummy_point = 20задание должно решить?