C указатели и память - PullRequest
       0

C указатели и память

2 голосов
/ 09 марта 2012

Я учу C, и теперь я врезался в стену.Мне трудно понять указатели.

Представьте, что у меня есть этот код:

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

#define DELTA 33

int calls, seed=356;

int sum_ds(int a){    
 int d=DELTA;          
 calls++;               
 return a+d+seed; 
}                       

int main() {
    int num;                                
    int *ptr;
    int **handle;

     num = 14;                              
     ptr = (int *)malloc(2 * sizeof(int));  
     handle = &ptr;
     *(*handle+0) = num;                    
     *(*handle+1) = num+1;  
     *ptr = num-2;      
     ptr = &num;        
     *ptr = sum_ds(num-2);
}

Давайте пошагово пройдемся через мое понимание.

1 - вызовы int создаютпеременная по имени вызывает и не инициализирует ее, поэтому она содержит мусор.Он хранится в DATA и, скажем, с адресом памяти 0xFFAA.

2 - int seed создает переменную с именем seed, инициализированную целым числом 356. Он хранится в DATA и, скажем, с адресом памяти 0xFFAB.

3 - int num создает переменную с именем num и не инициализирует ее, поэтому содержит мусор.Он хранится в STACK и, скажем, с адресом памяти 0xFFAC.

4 - int * ptr создает указатель на int и не назначает ему никакого адреса.Он хранится в STACK и, скажем, с адресом памяти 0xFFAD.

5 - дескриптор int ** создает указатель на указатель на int и не присваивает ему никакого адреса.Он хранится в STACK и, скажем, с адресом памяти 0xFFAE.(МНОГО СОМНЕНИЙ ЗДЕСЬ)

6 - num = 14 переходит на адрес 0xFFAC и сохраняет на нем число 14.Это делается в STACK.

7 - ptr = (int *) malloc (2 * sizeof (int)) В HEAP ему назначен размер памяти для 2-х дюймов и адрес первого байта памяти (скажем,0xFFZZ) хранится (в STACK) в ptr, поэтому теперь * ptr указывает на этот адрес памяти.

8 - handle = & ptr handle теперь указывает на ptr.Я полагаю, что теперь это указывает на то, что находится на 0xFFZZ (МНОГИЕ ЗДЕСЬ ЗДЕСЬ)

9 - * (* handle + 0) = num указатель на указатель int теперь назначен со значением num (14)(МНОГИЕ МНОГИЕ МНОГИЕ СОМНЯ ЗДЕСЬ)

10 - * (* handle + 1) = num + 1 указатель указателя плюс один из int теперь назначен со значением num + 1 (15) (MANYМНОГО МНОГО МНОГО СОМНЕНИЙ ЗДЕСЬ)

11 - * ptr = num-2 точка значения, указанная ptr, присваивается со значением num - 2 (12).Я полагаю, что он идет по адресу памяти 0xFFZZ и сохраняет там число 12.

12 - ptr = & num ptr теперь указывает на num, я считаю, что теперь он указывает на 0xFFAC.

13 - *ptr = sum_ds (num-2) значение, указанное ptr, является возвращаемым значением sum_ds.Я верю, что 0xFFAC присвоено 401 (12 + 33 + 356)

Это правильно?

Ответы [ 3 ]

4 голосов
/ 09 марта 2012

1 - вызовы int создают переменную с именем звонков и не инициализируют ее, поэтому она содержит мусор.Он хранится в DATA и, скажем, с адресом памяти 0xFFAA.

2 - int seed создает переменную с именем seed, инициализированную целым числом 356. Он хранится в DATA и, скажем, с адресом памяти 0xFFAB.

Одна маленькая деталь: sizeof(int) больше 1 (это 4 на большинстве основных платформ, поэтому 2-й адрес не может быть на 1 выше 1-го. В остальном, AFAIK, вы правы, поэтомуfar.

3 - int num создает переменную с именем num и не инициализирует ее, поэтому содержит мусор. Он хранится в STACK и, скажем, с адресом памяти 0xFFAC.

4 - int * ptr создает указатель на int и не назначает ему никакого адреса. Он хранится в STACK и, скажем, с адресом памяти 0xFFAD.

Еще одна небольшая деталь: onНа большинстве основных платформ стек растет вниз, поэтому 4-й адрес будет меньше 3-го. Кроме этого, AFAIK, вы правы до сих пор. (Более того, адреса на данныхgment, куча и стек в реальной жизни будут довольно разными.)

7 - ptr = (int *) malloc (2 * sizeof (int)) В HEAP ему назначен размер памяти для2 дюйма, и адрес первого байта памяти (скажем, 0xFFZZ) сохраняется (в STACK) на ptr, так что теперь * ptr указывает на этот адрес памяти.

Чтобы быть чётким, 'Z'не шестнадцатеричное число :-) Итак, давайте скажем, что вместо него 0x1000.

8 - handle = & ptr handle теперь указывает на ptr.Я полагаю, что теперь это указывает на то, что находится на 0xFFZZ (МНОГО СОМНЯ ЗДЕСЬ)

Нет, handle теперь содержит адрес ptr, то есть 0xFFAD. Косвенно хотя - через ptr - оно действительно указывает на 0x1000 (было 0xFFZZ в вашем примере).

9 - * (* handle + 0) =num указатель на указатель на int теперь ему присвоено значение num (14) (МНОГО МНОГО МНОГО МНОГО СОМНЕНИЙ ЗДЕСЬ)

В основном правильно.Нотация, которую вы используете, не самая простая, с которой вам труднее следить за происходящим.После шага 8 *handle эквивалентно ptr.А так как указатели и массивы взаимозаменяемы во многих распространенных ситуациях, * (ptr + 0) эквивалентно ptr[0], а также *ptr.

10 - * (* handle + 1)) = num + 1 указатель указателя плюс один из int теперь назначен со значением num + 1 (15) (МНОГО МНОГО МНОГО МНОГО СОМНЕНИЙ ЗДЕСЬ)

Как и в предыдущем пункте, выв действительности присваивают ptr[1] = num+1.Имейте в виду, что ptr равно int*, поэтому разность адресов между ptr и ptr + 1 равна sizeof(int), что, как упоминалось выше, обычно 4.

11 - * ptr = num-2 точка значения ptr назначается значению num - 2 (12).Я полагаю, что он идет по адресу памяти 0xFFZZ и сохраняет там число 12.

Да, это перезаписывает значение, установленное на шаге 9.

12 - ptr = & numptr теперь указывает на num, я считаю, что теперь он указывает на 0xFFAC.

Correct.

13 - * ptr = sum_ds (num-2) значение, указанное ptrВозвращаемое значение sum_ds.Я верю, что 0xFFAC назначено с 401 (12 + 33 + 356)

Правильно.Поскольку предыдущий шаг сделал *ptr эквивалентным num, этот вызов также эквивалентен num = sum_ds(num-2).

1 голос
/ 10 марта 2012

Переменная имеет адрес, и в этом адресе хранится значение, которое вы только что положили:

int a = 10;

Верно?

Указатель - это разновидность переменной, в которой хранится адресдругая переменная.Итак ...

int a = 10;
int *p = &a;

Это означает, что "p" хранит адрес "a", который имеет значение, которое вы хотите использовать.

Выполните этот код ниже, и выпонять: printf ("% p% p% d% d \ n", p, & a, * p, a);

1 голос
/ 09 марта 2012

Поскольку calls находится вне какой-либо функции, это переменная static. Статические переменные инициализируются в 0.

Поскольку num является локальной переменной (auto класс хранения), она не инициализирована.

В вашей точке 9, *(*handle+0) = num;, вероятно, легче всего расшифровать, имея в виду, что handle = &ptr, следовательно, *handle = ptr, так что это в основном эквивалентно *(ptr+0) = num;, что (в свою очередь) эквивалентно ptr[0] = num;.

Для пункта 10 вы получаете почти одно и то же, за исключением +1 в обоих случаях, поэтому он говорит: ptr[1] = num+1;.

Для пункта 11 *ptr=num-2; перезаписывает то, что было написано в пункте 9, т.е. * ptr совпадает с *(ptr+0), так что это эквивалентно ptr[0] = num-2;

В пункте 12 вы правы, что для ptr установлено значение num. Это означает, что в пункте 13 присвоение эквивалентно num=sum_ds(num-2);

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