Изменение размера массивов в программировании на C

У меня вопрос по процессу выделения памяти массива. У меня есть массив с именем 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]);
    }
    
    
    
    
}


Чего-то не хватает, или я не так понимаю?

int *dummy_point = (int*) 0x12de06a1c;? Кто тебя этому научил? Зачем ты это делаешь? Что это за проблема, и следующее *dummy_point = 20 задание должно решить?
Some programmer dude 13.07.2023 10:55

Непонятно, для чего dummy_point . И вы не можете просто назначить случайный адрес на настольном ПК.

Weather Vane 13.07.2023 10:55

Также память, выделенная с помощью malloc, или новая память, выделенная с помощью realloc, никак не инициализируется. Содержание этой памяти неопределенно. А использование неопределенных значений может привести к неопределенному поведению.

Some programmer dude 13.07.2023 10:55

Я понятия не имею, в чем смысл переменной dummy_point. Это не имеет никакого смысла. *dummy_point = 20 - это неопределенное поведение, вы не можете писать/читать в/из произвольного адреса, например, на моем компьютере это заканчивается сбоем. Какой результат вы ожидаете? Чем он отличается от того, что вы получаете?

Jabberwocky 13.07.2023 11:02

OT: free(list) бесполезен, когда list равен NULL. OTOH это не делает ничего плохого, так как free(NULL) это NOP (IOW это ничего не делает).

Jabberwocky 13.07.2023 11:04

Возможно, вы захотите прочитать это, особенно раздел а).

Jabberwocky 13.07.2023 11:08

Спасибо Джаббервоки! за полезный ресурс :D. Цель фиктивного значения - просто имитировать тот кусок памяти, который занят. Просто пытаюсь лучше понять malloc/calloc и realloc, когда вы работаете в средах с ограничениями памяти.

Mircea Potlogia 13.07.2023 11:26

@MirceaPotlogia, вы не можете этого сделать, это не имеет смысла. Важно знать, что если память расширяется с помощью realloc, содержимое новой части массива не определено. Это может быть что угодно, и вы не можете ожидать какой-то особой ценности.

Jabberwocky 13.07.2023 11:31

Похоже, что OP предвидел место в памяти, которое станет частью распределения, которое можно было бы узнать, только запустив код без него. С рандомизацией адресного пространства это должно сделать это невозможным, потому что при следующем запуске кода адрес выделения будет другим.

Weather Vane 13.07.2023 11:36
malloc и друзья не предоставят вам память, которая законно занята кем-либо еще.
Gerhardh 13.07.2023 11:36

@Jabberwocky спасибо, теперь я понял!

Mircea Potlogia 13.07.2023 11:51

Вы знаете, что if (temp == NULL) { free(temp); ... } имеет очень мало смысла?

tstanisl 13.07.2023 11:53

Не важно, но... free(temp); должно быть free(list);

Support Ukraine 13.07.2023 11:55

Присвоение фиксированного значения указателю, такому как int *dummy_point = (int*) 0x12de06a1c;, — это то, что вы делаете только при написании низкоуровневого (т.е. близкого к HW) кода. Обычно во встроенных системах, где у вас есть полный контроль/знание об отображении (внешних) устройств в пространство памяти и управление преобразованием адресов (если оно имеется).

Support Ukraine 13.07.2023 12:00
Структурированный массив Numpy
Структурированный массив Numpy
Однако в реальных проектах я чаще всего имею дело со списками, состоящими из нескольких типов данных. Как мы можем использовать массивы numpy, чтобы...
T - 1Bits: Генерация последовательного массива
T - 1Bits: Генерация последовательного массива
По мере того, как мы пишем все больше кода, мы привыкаем к определенным способам действий. То тут, то там мы находим код, который заставляет нас...
Что такое деструктуризация массива в JavaScript?
Что такое деструктуризация массива в JavaScript?
Деструктуризация позволяет распаковывать значения из массивов и добавлять их в отдельные переменные.
0
14
80
1
Перейти к ответу Данный вопрос помечен как решенный

Ответы 1

Ответ принят как подходящий

Вы не можете инициализировать массив в этом месте и даже не можете объявить, что он там есть.

Однако вы можете использовать указатель для управления значениями, уже существующими в этом месте.

это мой результат без инициализации манекена:

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: если вы хотите больше узнать о компиляторах, купите или скачайте книги Дершем - Джиппинг. Языки программирования: структуры и модели.

Вау, спасибо за ваше объяснение! Теперь я полностью понимаю концепцию, большой палец вверх

Mircea Potlogia 13.07.2023 12:30

Я не согласен со следующим предложением: "if you want to do such a thing you have to code in assembler an create your own compiler ;)" -- Программирование на ассемблере или создание собственного компилятора, вероятно, не обязательно. Это скорее зависит от того, какую платформу вы используете. Например, в Linux можно выделить память по определенному адресу с помощью системного вызова mmap . В Microsoft Windows аналогичную функциональность обеспечивает функция VirtualAlloc.

Andreas Wenzel 13.07.2023 13:37

@MirceaPotlogia: Этот «ответ» полон неточностей, неправильного использования языка и ошибок. Вам следует подумать о том, чтобы пометить его как принятый, и вы не должны использовать содержащиеся в нем утверждения.

Eric Postpischil 13.07.2023 13:40

Другие вопросы по теме