Как можно задействовать пустой массив в расчете? - PullRequest
0 голосов
/ 27 января 2019
#include <stdio.h>

int f( int *x ) {
    *x = 35;
}

int main( int argc, char *argv[] ) {
    int p[32];
    int *q = p + 5;

    f( q );

    printf( "%d", p[5] );

    return 0;    
}

Не могли бы вы объяснить, почему вывод 35?

Я попытался вывести значение p с помощью printf("%d", p) и сразу после int p[32] вернуло -2077686688.

Я думаю, это просто потому, что я еще не присвоил значение массиву p[32], поэтому он просто возвратил случайное число.

Однако, часть, которая меня больше всего смущает, это *q = p + 5

Как массив может сделать это?

Поскольку в массиве p нет значения, как он может просто вернуть свой размер в этом выражении?

Ответы [ 3 ]

0 голосов
/ 27 января 2019

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

Давайте сначала разберем вашу функцию main.

int p[32];

Когда в вашей программе вызывается функция, ей выделяется некоторый раздел в ОЗУ, назначенный вашему процессу.Этот раздел называется стеком.С помощью этого оператора вы сообщаете компилятору, что вашей функции (main) нужно место для 32 целых чисел в стеке.Дальнейшие операторы, которые вы делаете с переменной p, будут работать с этим пространством, зарезервированным для 32 целых чисел.

Обратите внимание, что вы ничего не говорите компилятору о том, как эта часть памяти назначена для p инициализируется.Таким образом, все эти байты, выделенные для 32 целых чисел, будут хранить все, что они содержали до вызова вашей функции.

Давайте рассмотрим следующий.

int *q = p + 5;

Это очень похоже, но теперь вы спрашиваетедля некоторой памяти в стеке с размером, который может соответствовать «указателю на целое число».Указатель - это абстракция C для простого «адреса памяти с типом».Таким образом, это пространство будет использоваться для хранения адресов в памяти, и эти адреса будут ссылаться на другое пространство в ОЗУ, предназначенное для хранения целых чисел.

Вы также говорите компилятору инициализировать пространство стека для q, со значением p + 5.В отличие от пробела для 32 целых чисел (p), пробел для q будет инициализирован сразу после вызова вашей функции.

Выражение p + 5 применяет то, что называется "арифметикой указателей",Это используется для получения адреса в ОЗУ и увеличения или уменьшения в зависимости от необходимого смещения.Помните, p был массивом, и массивы в C работают как указатели (адреса), когда они участвуют в арифметике указателей.Таким образом, на самом деле p + 5 означает «адрес, который является 5 целыми числами после того, как первый адрес p указывает на».В конечном итоге это «указатель на шестой элемент p» (сначала это p[0]), другими словами, адрес p[5].

f(q);

В этом утверждении выпередача адреса, хранящегося в q, который оказался адресом шестого элемента в p.Функция f в свою очередь присваивает 35 местоположению в ОЗУ, указанному по этому адресу, следовательно, заменяя целое число, к которому будет обращаться p[5], на целочисленное значение 35.

Прямо вВ этой точке p[5] является единственным элементом в p, который имеет инициализированное значение.Все другие целые числа в p будут продолжать хранить то, что они держали до того, как main был вызван во время инициализации вашей программы.

printf( "%d", p[5] );

Когда выполнение вернется обратно к main, целое число, которое можетдоступ к p[5] теперь установлен на 35, и это именно то, что вы ожидаете увидеть с этим оператором printf.

0 голосов
/ 27 января 2019

int main() {
    int p[32] = { 0 };
    // initializing array with zeros; no mode random values in array!

    int *q = p + 5;

    if (&p == &p[0] && &3[p] == &p[3]) {
        printf("Sick sad C world\n");
    }
    /* We can say that there's no such thing as 'array' in C!
     * (actually, C has arrays)
     * but C arrays are 'thin layer'; try to compare JS Array and C Arrays
     * See this: https://stackoverflow.com/a/381549/10972945
     * So: p[0] == *(p + 0) == *p
     * 'Array' is an address of it's zero element! */

    printf(
        "p located at %p\n"
        "p + 1 located at %p\n"
        "p + 5 located at %p\n"
        "Size of int (in bytes) is %zu\n",
        (void*) p,
        (void*) (p + 1),
        (void*) (p + 5),
        sizeof(int) 
    );
    /*  Try to run this code and substract addresses, one from another.

            p located at 0x7ffee3e04750
            p + 1 located at 0x7ffee3e04754
            p + 5 located at 0x7ffee3e04764
            Size of int (in bytes) is 4

        See:
        address of (p + 1) - address of p
            == 0x7ffee3e04754 - 0x7ffee3e04750
            == 4 == sizeof(int)
        address(p + 5) - address(p)
            == 0x7ffee3e04764 - 0x7ffee3e04750
            == 0x14 == 20 == 5 * sizeof(int)
     */
}
0 голосов
/ 27 января 2019

В вашем коде int p[32] выделяет массив размером 32, на который можно ссылаться с помощью p.Когда вы определяете q как p + 5, вы назначаете q как указатель на 6-й (1-индексированный) элемент в памяти, начиная с того места, на которое указывает p.

Когда выпередать q в f(), значение в q устанавливается равным 35 из того, что было раньше (неинициализированная память).Поскольку q указывает на то же местоположение, что и p[5], p[5] будет 35, поскольку это значение установлено в местоположении в памяти с помощью f().

Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...