1. 程式人生 > >C語言中的二級指標(1) -- 值傳遞問題

C語言中的二級指標(1) -- 值傳遞問題

先看一個我們非常熟悉的程式碼:
#include <stdio.h>

void swap(int a, int b)
{
	int tmp;

	tmp = a;
	a = b;
	b = tmp;
}

int main()
{
	int a = 3, b = 5;
	swap(a, b);
	printf("a = %d, b = %d\n", a, b);
	return 0;
}
我們都知道,這段程式碼中的swap()函式並沒有起作用,因為呼叫swap的時候使用值傳遞的方式(將變數a的地址和b的地址中的值取出來傳給swap()),實際上只是傳遞給swap()兩個立即數而已,swap()將這兩個立即數放到自己的棧裡去操作,最終swap()執行結束後,它自己的棧也就消失了。而main函式中的a和b並不受影響。
如果將程式碼改為下面的寫法:
#include <stdio.h>

void swap(int * a, int * b)
{
	int tmp;

	tmp = *a;
	*a = *b;
	*b = tmp;
}

int main()
{
	int a = 3, b = 5;
	swap(&a, &b);
	printf("a = %d, b = %d\n", a, b);
	return 0;
}

在main()函式中傳給swap()是a和b的地址,這樣,雖然swap()也是將a的地址和b的地址複製一份放入自己的棧裡,但是swap()執行的結果為修改了這兩個地址中的內容,在返回main()函式時這兩個地址的內容仍是有效的。

*****************************************************************

所以,在向函式傳參時,如果想在函式中修改這個引數並且在函式返回時修改仍生效,就要傳入這個引數的地址。例如,傳遞一個int型的引數,就要傳入這個int型別引數的地址。

那麼,如果我們想傳遞一個指標型別的引數,並且想修改這個指標自身,就要傳遞這個指標的地址。在被呼叫函式接受引數時就體現為指標的指標,即二級指標。
我們看下面這個例子(例子中省略了一些合法性檢查的程式碼):

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

#define WORKER_NAME_MAX	32

struct worker {
	char name[WORKER_NAME_MAX];
	int wid;
	int wshift;
};

static struct worker master = {"zhangsan", 1001, 1};

/* 1. 獲取master的資訊 */
void get_master_info(struct worker * worker)
{
	worker = &master;
}

/* 2. 傳遞指標 */
int change_worker_shift(struct worker * worker, int shift)
{
	worker->wshift = shift;
	return 0;
}

/* 3. 使用二級指標,獲取master的資訊 */
void get_master_real_info(struct worker ** worker)
{
	*worker = &master;
}

int main()
{
	struct worker * lisi;
	lisi = (struct worker *)calloc(1, sizeof(struct worker));

	/* 1. 獲取master的資訊 */
	get_master_info(lisi);
	printf("name: %s (id = %d, shift = %d)\n", lisi->name, lisi->wid, lisi->wshift);
	
	strncpy(lisi->name, "lisi", WORKER_NAME_MAX);
	lisi->wid = 1002;
	lisi->wshift = 0;
	/* 2. 修改李四的wshift為1 */
	change_worker_shift(lisi, 1);
	printf("name: %s (id = %d, shift = %d)\n", lisi->name, lisi->wid, lisi->wshift);

	free(lisi);

	/* 3. 獲取master的資訊 */
	get_master_real_info(&lisi);
	printf("name: %s (id = %d, shift = %d)\n", lisi->name, lisi->wid, lisi->wshift);
	
	return 0;
}
執行結果:
[[email protected] zhenfg]# gcc pptest.c -o pptest
[[email protected] zhenfg]# ./pptest 
name:  (id = 0, shift = 0)
name: lisi (id = 1002, shift = 1)
name: zhangsan (id = 1001, shift = 1)
這個程式在main()函式定義了一個指標lisi,然後依次呼叫的三個函式嘗試去修改lisi的內容:
1. 第一次要獲取master這個全域性結構的內容並賦值給lisi,但是我們通過程式執行結果看到呼叫get_master_info(lisi)函式並沒有更新lisi變數的內容,因為這裡只是將lisi這個指標自身內容取出來,放到一個臨時區域傳給get_master_info()函式,get_master_info()函式可以使用lisi的值,但是修改引數卻不會影響到main()裡面原來的指標。
如下圖(圖中“tmp lisi”為被呼叫函式接收到的引數,除了“tmp lisi”,圖中其他變數在main函式執行期間地址固定):


2. 第二次要修改lisi結構體中的wshift成員,我們看到修改成功了,因為我們要修改wshift,而傳入的是lisi這個指標,實際上就是傳入了wshift的地址。如下圖,


3. 第三次和第一次的目的一樣,要獲取master這個全域性結構的內容並賦值給lisi,並且我們看到修改成功了,因為傳入的引數為lisi這個指標的地址。如下圖,

另外,讀者可能已經注意到main函式中free()被呼叫的位置。之所以不在最後呼叫free(),是因為在第3步之後,lisi指標的地址已經改變成master的地址了,如果這時呼叫free()實際上是在嘗試釋放master的內容。

相關推薦

C語言二級指標(1) -- 傳遞問題

先看一個我們非常熟悉的程式碼:#include <stdio.h> void swap(int a, int b) { int tmp; tmp = a; a = b; b = tmp; } int main() { int a = 3, b =

c語言二級指標空間的分配

定義二級指標變數 ,假設是個N介矩陣 int** p;// define int i; p=(int**)malloc(N*sizeof(int*)); for(i=0;i<N;i++) *(p+i)=(int*)malloc(N*sizeof(int)); 千萬別用這

C語言二級指標使用

C/C++中使用指標可以減少函式傳遞的引數 例如: typedef struct { int r[MAX]; int length; }SqList; 呼叫void test(

詳解:C語言指標和p, p+1, *(p+1), *P+1, p[0], &p[0] 的含義

解析:C語言中的指標和p, p+1, *(p+1), *P+1, p[0], &p[0] 每一種表示式的含義  一、先解決一個問題:什麼是指標 指標就是存放地址的變數。很好,百度上就是這個答案(哈哈,感覺這句話很廢話)。 指標是一個大小固定為4個byte的變數,不管

c語言通過指標將數值賦到制定記憶體地址

1.一種直觀的方法假設現在需要往記憶體0x12ff7c地址上存入一個整型數0x100。我們怎麼才能做到呢?我們知道可以通過一個指標向其指向的記憶體地址寫入資料,那麼這裡的記憶體地址0x12ff7c其本質不就是一個指標嘛。所以我們可以用下面的方法:int *p = (int *)0x12ff7c; *p = 0

C語言指標以及二級指標

很多初學者都對C中的指標很迷糊,希望這篇blog能幫助到大家: 1.什麼是“指標”: 在執行C程式的時候,由於我們的資料是儲存在記憶體中的。所以對於C程式本身來說,如果想找到相應被呼叫的資料,就要知道儲存該資料的記憶體地址是多少,換言之,C程式通過已知的記憶體地址到相應的記

C語言打印返回

返回值 struct demo bsp %d return username har strdup demo: ----return :返回值------------------ int mosquitto_username

初探C語言指標

IT小菜鳥,年後考研複試要考C,所以寒假就重溫了一下C語言,看到指標這個曾經讓我10分噁心的東東,決定記錄下點東西,一來當成筆記,二來可以幫助一些剛剛入門的小夥伴們深刻理解一下指標這玩意。如果有哪裡說得不對,歡迎大家批評指正。 首先,我們要區分兩個概念。 1 指標 2指標變數

C語言學習指標遇到的問題與以後的學習道路

C語言中學習指標遇到的問題與以後的學習道路 在這個指標的學習裡,我學習的可謂是相當的掙扎了。 沒有了往日學習其它章節的高效性,有的只是無窮無盡的問題與懵懂。 他就像是一層迷霧,令我捉摸不透。 首先要注意的就是指標這個概念:它指的就是地址。沒其它任何含義 然後就是指標變數這個東西,不就是加

C語言函式指標陣列的初始化和使用

不比多說上一個程式碼,就懂了! 程式碼一: #include <stdio.h> int func(int i) {     printf("%d\n",i);     return i*i; } int

C語言指標

這算我第一篇比較正式的學習性播客吧,我想大概說一下C語言指標上的問題。 int i; //定義整形變數 int *p; //定義一個指向int的指標變數 int a[10]; //定義一個int陣列,有十個元素 int *p[10]; //

C語言輸出指標的問題

#include<stdio.h> void main(void){ char *p; char i = 'c'; p = &i; printf("i的值為:%c\n", i); printf("i的地址為:%p\n", &i);

C語言二級指標

#include<stdio.h>int main(){ int a=10;            //宣告一個int型變數a int

C語言指標

野指標 野指標通常是因為指標變數中儲存的值不是一個合法的記憶體地址而造成的 野指標不是NULL指標,是指向不可用記憶體的指標 NULL指標不容易用錯,因為if語句很好判斷一個指標是不是NULL (注意

C語言指標常量(*const)和常量指標(const*)的區別(很重要!!!)

參考連結:https://blog.csdn.net/qiu931110/article/details/80580295   這個哥們講的還可以,但是我想用白話在描述一下,方便理解:   const限定符作用於指標 常量指標(先常量限制符號,在指標符號,co

C語言結構體賦問題的討論

結構體直接賦值的實現 下面是一個例項: #include <stdio.h> struct Foo { char a; int b; double c; }foo1, foo2; //define two

C語言指標陣列和陣列指標

可以將 *string看成陣列 a[] 下的a,即指標是指向陣列的首地址的; 指標陣列是陣列元素為指標的陣列(例如 int *p[3],定義了p[0],p[1],p[2]三個指標),其本質為陣列。 指

c語言指標陣列

指標陣列,陣列元素是一個指標 附上程式碼 #include <stdio.h> #include <stdlib.h> /* run this program using th

C語言關於指標的資料型別和指標運算的小結

有關指標的資料型別小結 記憶訣竅: 容易混淆的幾個int *p[n] 、int (*p)[n],其中int *p[n]是一個數組,陣列的元素是指標;int (*p)[n]是個指標,是一個指向二維陣列的

C語言結構體賦的討論

今天幫師姐調一個程式的BUG,師姐的程式中有個結構體直接賦值的語句,在我印象中結構體好像是不能直接賦值的,正如陣列不能直接賦值那樣,我懷疑這個地方有問題,但最後證明並不是這個問題。那麼就總結一下C語言中結構體賦值的問題吧: 結構體直接賦值的實現 下面是一個例項: #