Две целочисленные переменные, находящиеся в одном адресе памяти?


Я изучаю указатели на языке Си и пытаюсь решить упражнения на указателях, доступных в интернете. Хотя приведенный ниже Вопрос не использует указатели, я понимаю, что неправильный вывод связан с отсутствием использования указателей. Вот в чем вопрос -

/* p2.c 
Find out (add code to print out) the address of the variable x in foo1, and the 
variable y in foo2. What do you notice? Can you explain this? 
*/

И вот мой ответ -

#include <stdio.h>
void foo1(int xval) 
{ 
 int x; 
 x = xval; 
 /* print the address and value of x here */ 
 printf("\n Address of variable x is:%p\n", &x);
 printf("\n Value of variable x is: %d\n", x); 

} 
void foo2(int dummy) 
{ 
 int y;
 y=dummy; 
 /* print the address and value of y here */ 
 printf("\n Address of variable y is:%p\n", &y);
 printf("\n Value of variable y is: %d\n", y); 
} 

int main() 
{ 
 foo1(7); 
 foo2(11); 

 return 0; 
} 

Выход при компиляции программы -

 Address of variable x is:0x7fff558fcb98

 Value of variable x is: 7

 Address of variable y is:0x7fff558fcb98

 Value of variable y is: 11

Из того, что я понимаю, когда программа запускается, и foo1 с целым числом в качестве аргумента функции вызывается, то целое число 7 берется и сохраняется в целочисленной переменной x. Затем функция foo1 выводит адрес и значение переменной x. То же самое повторяется с функцией foo2.

Но я не мог понять, как это получается, что две целочисленные переменные с разными значениями находятся в одном и том же адресе памяти 0x7fff558fcb98? Это из-за проблем с управлением памятью в C (malloc, free и т. д.-Я еще не там!)?

Любая помощь будет высоко ценится. Спасибо.

7   4  

7 ответов:

Полезно визуализировать состояние стека, чтобы понять его поведение. Когда вы находитесь в main, допустим, стек выглядит следующим образом:

Введите описание изображения здесь

Когда вы вводите foo1, кадр стека для foo1 добавляется в стек, и он выглядит следующим образом:

Введите описание изображения здесь

Когда вы вернетесь из foo1, стек вернется к:

Введите описание изображения здесь

Когда вы вводите foo2, Кадр стека для foo2 добавляется в стек, и он выглядит следующим образом:

Введите описание изображения здесь

В состояние кадра стека выглядит очень похожим для foo1 и foo2. Неудивительно, что адреса локальных переменных x и y идентичны.

Если бы количество аргументов, типы аргументов или типы локальных переменных были разными, вы бы заметили разные значения для адресов локальных переменных.

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

Большинство компиляторов выделяют локальные переменные в стеке, находясь внутри функции.

Когда функция возвращается, память возвращается в систему, и другая функция может повторно использовать память для другой локальной переменной.

Другими словами, foo1 выделяет память для x, но когда она возвращается, память возвращается в систему, так как x больше не используется.

Тот же адрес памяти затем повторно используется в foo2 для хранения y.

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

void foo1(int xval) и void foo2(int dummy) - это две разные функции, поэтому, когда одна функция выполняется, только переменные этой функции находятся в стеке. Как только вы вызываете другую функцию или возвращаете из функции, локальная переменная этой функции присутствует в стеке. Таким образом, две переменные разной функции могут иметь один и тот же адрес (но в разное время).

Посмотрите на разницу между "статическим" и "автоматическим" выделением памяти. Вы используете автоматическое выделение памяти в объявлениях функций, и память освобождается при выходе из функции:

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

Нижняя линия. После того, как foo1(7) выходит, та же память используется для 7 является повторно используется для 11 в foo2(11).

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

Main --> foo1 --> allocate x --> do the work in foo1 --> free the memory location used by x -- > вызовите foo2, затем повторите для y то, что было сделано для x (здесь он будет использовать ту же самую область памяти, которая была освобождена от x).

Это не потому, что вы не использовали указатели. Вы можете захотеть (вы должны попробовать) использовать указатели, как показано ниже , но ожидайте опять тот же результат:

#include <stdio.h>
void foo1(int xval) 
{ 
 int *x; 
 x = &xval; 
 /* print the address and value of x here */ 
 printf("\n Address of variable pointed by x is:%p\n", x);
 printf("\n Value of variable x is: %d\n", *x); 

} 
void foo2(int dummy) 
{ 
 int *y;
 y=&dummy; 
 /* print the address and value of y here */ 
 printf("\n Address of variable y is:%p\n", y);
 printf("\n Value of variable y is: %d\n", *y); 
} 

int main() 
{ 
 foo1(7); 
 foo2(11); 

 return 0; 
} 

Возможно, вы ищете вот это:

 main()                                                           
   {
       char   a;                                                    
       int    x;                                                    
       float  p, q;                                                 

       a  = 'A';                                                    
       x  = 125;                                                    
       p  = 10.25, q = 18.76;                                       
       printf("%c is stored at addr %u.\n", a, &a);                 
       printf("%d is stored at addr %u.\n", x, &x);                 
       printf("%f is stored at addr %u.\n", p, &p);                
       printf("%f is stored at addr %u.\n", q, &q);                 

       }

Или

// Declare and initialize an int variable

int var = 34;

// Declare a pointer to int variable

int *ptr;

// Initialize ptr to point to variable var

ptr = &var;



// Access var directly and indirectly

printf("\nDirect access, variable var value = var = %d", var);

// you can use %p for the pointer memory address directly or

// %0x or %0X or %p in hexadecimal representative instead of

// %d, just to avoid confusion here

printf("\nIndirect access, variable var value = *ptr = %d", *ptr);

// Display the address of var two ways

printf("\n\nThe memory address of variable var = &var = %p", &var);

printf("\nThe memory address of variable var = ptr = %p\n", ptr);