我不明白這個程式的行為。
根據我的理解, main() 中的指標應該具有現在已銷毀的區域變數的原始地址。因為此時指標被分配了有效地址。
它應該只保留那個地址。為什么會失去那個?
這是程式
#include <stdio.h>
void fun(int* ptr)
{
int a = 5;
ptr = &a;
printf("address: %p, value: %d\n", &a, a);
// address: 0x7fff1aa00374, value: 5
printf("address: %p, value: %d\n", ptr, *ptr);
// address: 0x7fff1aa00374, value: 5
}
int main(void)
{
int* ptr = NULL;
fun(ptr);
printf("address: %p\n", ptr);
// address: (nil)
printf("address: %p\tvalue: %d\n", ptr, *ptr);
// Segmentation fault (core dumped)
return 0;
}
海灣合作委員會版本
gcc (Ubuntu 7.5.0-3ubuntu1~18.04) 7.5.0
uj5u.com熱心網友回復:
為了更好地理解這里發生的事情,將函式的ptr引數重命名fun()為fun_ptr
void fun(int* fun_ptr)
^^^^^^^
當你呼叫fun()函式
int* ptr = NULL;
fun(ptr);
引數的值ptr將分配給fun()函式引數fun_ptr。它類似于這個
fun_ptr = ptr;
ptr是NULL,所以fun_ptr將被分配NULL。您在函式fun_ptr內部所做的任何更改都fun()將保留在fun()函式塊中,因為函式定義中的引數宣告串列中的識別符號范圍具有塊范圍,該范圍在函式回傳時終止。
如果要更改另一個函式中的指標變數,則必須將該指標變數的地址傳遞給呼叫函式。在您的程式背景關系中,它應該是
void fun(int** ptr) {
int a = 5;
*ptr = &a;
// *ptr will be the pointer passed as argument i.e. assign anything
// to *ptr means you are making changes to pointer passed as argument
.....
.....
}
int main(void)
{
int* ptr = NULL;
fun(&ptr);
.....
.....
return 0;
}
即使在進行這些更改之后,您的程式仍將具有未定義行為,因為它正在訪問其范圍之外的區域變數的地址。變數a是一個區域(自動)非靜態變數,它的生命周期僅限于它的作用域,即它被宣告的塊。任何在其生命周期之外訪問它的嘗試都會導致未定義的行為。
要解決此問題,請為指標分配記憶體ptr并為其分配值a。或者,您可以宣告a為static變數。靜態變數的生命周期是程式的整個運行。你可以做:
#include <stdio.h>
#include <stdlib.h>
void fun1 (int** ptr) {
static int a = 5;
*ptr = &a;
printf("fun1(): address: %p, value: %d\n", (void *)&a, a);
printf("fun1(): address: %p, value: %d\n", (void *)*ptr, **ptr);
}
void fun2 (int** ptr) {
static int a = 5;
*ptr = malloc (sizeof (int));
if (*ptr == NULL) {
fprintf (stderr, "Failed to allocate memory\n");
exit (EXIT_FAILURE);
}
**ptr = a;
printf("fun2(): address: %p, value: %d\n", (void *)&a, a);
printf("fun2(): address: %p, value: %d\n", (void *)*ptr, **ptr);
}
int main (void) {
int* ptr1 = NULL;
int* ptr2 = NULL;
fun1(&ptr1);
printf("main(): address: %p\n", (void *)ptr1);
printf("main(): address: %p, value: %d\n", (void *)ptr1, *ptr1);
fun2(&ptr2);
printf("main(): address: %p\n", (void *)ptr2);
printf("main(): address: %p, value: %d\n", (void *)ptr2, *ptr2);
// Once done with dynamic allocated memory, release it
free(ptr2);
return 0;
}
uj5u.com熱心網友回復:
這是因為您是按值傳遞的,就像傳遞整數、字符等一樣。您不能更改按值傳遞的引數。在這種情況下,該值是地址。要實際更改 的地址ptr需要傳遞一個雙指標 ( int **ptr),但這需要對代碼進行更多更改。
uj5u.com熱心網友回復:
這是一個修改后的例子:
#include <stdio.h>
void fun(int p)
{
p = 5;
printf("value: %d\n", p);
}
int main(void)
{
int p = 0;
fun(p);
printf("value: %d\n", p);
return 0;
}
如果您了解為什么這個修改后的示例會列印5then 0,那么您也會明白為什么您的指標版本也不起作用。因為指標也是按值傳遞的。
如果你不明白為什么會列印5then 0,那么你需要閱讀一本初學者級別的 C 書,函式章節。
轉載請註明出處,本文鏈接:https://www.uj5u.com/qiye/315011.html
上一篇:如果以下陳述句在堆上不存在,那么它放在記憶體中的什么位置?
下一篇:減1與遞減迭代器
