假設有兩個指針*p1和*p2,一定要理解語句
*p1=*p2 ; P1=p1 ;
的含義。為了說明這個問題,先介紹大端存儲和小端存儲的概念。
1.大端存儲和小端存儲
當CPU和內存打交道時,在CPU內部的地址總線和數據總線是和內存的地址總線和數據總線連接在一起的。當一個數從內存中向CPU傳送時,有時是以一個字節為單位,有時又以一個字(4個字節)為單位。傳過來是放在寄存器裡(一般是32個字節),在寄存器中,一個字的表示是右邊應該屬於低位,左邊屬於高位,如果寄存器的高位和內存中的高地址相對應,低位和內存的低地址相對應,這就屬於小尾端存儲。反之則稱為大尾端存儲。大部分處理器都是小端存儲的。
因為16進制的2位正好是1個字節,所以選16進制0x12345678為例,對小尾端存儲,低位是0x78,應存入低位地址,所以存入的順序是
0x78 0x56 0x34 0x12
反之,對於高端存儲則為
0x12 0x34 0x56 0x78
圖14-1以0x0A0B0C0D為例。
圖14-1 圖解大端和小端存儲
下面利用union的成員共有地址的性質,用一個程序來具體說明小端存儲。
【例14.9】演示小端存儲的程序。
#include <stdio.h> union s{ int a ; char s1[4] ; }uc ; int main ( ) { int i=0 ; uc.a=0x12345678 ; printf (\"0x%xn\" ,&uc ); for (i=0 ;i<4 ;i++ ) printf (\"0x%x 0x%xn\" ,&uc.s1[i] ,uc.s1[i] ); return 0 ; }
聲明16進制整數a,它與字符串數組共有地址,a的最低一個字節是0x78,按小端存儲,則應存入&uc.s1[0]中,也就是0x4227c0中,最高位地址0x4227c3則應存入0x12,也就是數據的高位。下面的運行結果證明了這一點。其實,可以在調試環境中直接看到這些結果。
0x4227c0 0x4227c0 0x78 0x4227c1 0x56 0x4227c2 0x34 0x4227c3 0x12
2.指針相等操作
兩個指針變量相等,是指它們指向同一個地址。例如:
p2=p1 ;
不僅使得p1和p2都指向原來p1指向的地址,而且保證*p2=*p1。注意它們的值是原來*p1的值。也就是說,p2放棄自己原來的指向地址及指向地址裡存儲的值。而語句
*p2=*p1 ;
的作用是使p2放棄自己原來的指向地址裡存儲的值,改用p1指向地址裡的存儲值*p1,但並沒有放棄自己的指向地址,即p1和p2仍然保留各自原來的指向。但由此也不能得出p2指向地址裡存儲的內容就是p1指向地址裡存儲內容的結論。例如,對整數而言,指向的存儲內容是一樣的,但對字符數組而言,語句只是使第1個字符是一樣的。下面是用兩個不同結果說明這一點的例子。
【例14.10】演示整數指針相等操作的程序。
#include <stdio.h> int main ( ) { int *p1 , *p2 ; int s1=0x12345678 ,s2=0x78 ; p1=&s1 ;p2=&s2 ; printf (\"0x%xt0x%xn\" ,p1 ,p2 ); *p2=*p1 ; printf (\"0x%xt0x%xn\" ,*p2 ,*p1 ); // 值相等 printf (\"0x%xt0x%xn\" ,p1 ,p2 ); // 地址不變,即不相等 p2=p1 ; printf (\"0x%xt0x%xn\" ,*p1 ,*p2 ); // 值相等 printf (\"0x%xt0x%xn\" ,p1 ,p2 ); // 地址也變為相等 return 0 ; }
這個例子的語句「*p2=*p1;」使用*p1取代*p2,但p2不變。運行結果證明了這一點。
0x12ff74 0x12ff70 0x12345678 0x12345678 0x12ff74 0x12ff70 0x12345678 0x12345678 0x12ff74 0x12ff74
在有些操作中,常常碰到先執行「*p2=*p1;」,然後又執行一項「p2=p1;」的操作,其目的也是顯而易見的。
【例14.11】演示字符指針相等操作的程序。
#include <stdio.h> int main ( ) { char *p1 , *p2 ; char s1[16]=\"123456789\" ,s2[16]=\"GH\" ; p1=s1 ;p2=s2 ; printf (\"0x%xt0x%xn\" ,p1 ,p2 ); *p2=*p1 ; printf (\"%stt%sn\" ,p2 ,p1 ); // 值並不相等 printf (\"0x%xt0x%xn\" ,p1 ,p2 ); // 地址不變,即不相等 p2=p1 ; printf (\"%st%sn\" ,p2 ,p1 ); // 值相等 printf (\"0x%xt0x%xn\" ,p1 ,p2 ); // 地址也變為相等 return 0 ; }
這個例子的語句「*p2=*p1;」並不是用p1指向地址裡存儲的字符串取代p2指向的字符串,而是使用字符「1」取代原來的第1個字符「G」,運行結果如下:
0x12ff68 0x12ff58 1H 123456789 0x12ff68 0x12ff58 123456789 123456789 0x12ff68 0x12ff68
這是字符操作特徵引起的,所以不能只看表面現象。進一步的分析可以參見16.3.3節的複製字符串的例子。