賦值操作符的思考

         我要說的是一個小問題,感覺寫在博客裏面比較好。以後看到了可以回憶警示一下。

    問題是這樣的:在Java中數組之間能不能通過數組名直接賦值,爲什麼?

                             在C中數組之間能不能通過數組名直接賦值,爲什麼

我們先來分析C語言中的情況:

        char arr[3]={'a','b','c'};
	char arrB[3]=arr;    //錯的。
	int intArr[3]={1,2,3};
	int intArr2[3]=intArr;   //錯的。

      原因很簡單,在C語言中數組名相當於一個引用(C++中的引用),由於數組名不是一個變量,所以是不能作爲賦值操作符的左值的。舉個極端的例子,就像1++;和1=2;肯定是非法的一樣(至於深層次的原因,可能是因爲C語言爲了安全性所做的規定)。

 

但是注意了在C語言中,以下卻是可以的:

        char *p="hello";
	char *pB=p;
	printf("%s\n",pB);
//輸出結果:
hello

      原因也很簡單,“hello”在常量區,p指針保存一個地址指向了"hello"。將p的值賦值給pB也僅僅就是將這個字符串地址的值賦值給了pB。pB是一個指針變量可以作爲賦值操作符的左值,所以他接受到了“hello”的地址。

     所以,此時的內存佈局是:p和pB兩個指針所存儲的值是一樣的,都是“hello”在常量區的地址。也就是常說的p和pB指向了同一塊內存。

 

下來看一下Java環境下的分析:

public class Son{
	public static void main(String args[]){
		int arr[]={1,2,3};
		int arrB[]=arr;
		arrB[0]=5;
		System.out.println(Arrays.toString(arr));
	}
}
//運行結果:
[5, 2, 3]

     可見在Java環境中,採用數組名實現數組之間的賦值是可行的。原因也很簡單,在Java中都是值傳遞,Java中的引用相當於C中的指針。所以arr和arrB是指向了同一塊堆。是不是和上面那個C的例子很相像。

 

     最後說一下,在C中結構體是可以通過結構體名相互賦值的:

typedef struct Node{
	int value;
}node;
int main()
{
	node node1={3};
	node node2=node1;
	printf("%d\n",node2.value);

	node2.value=8;
	printf("%d\n",node1.value);
	
	system("pause");
	return 0;
}
//輸出結果:
3
3

    我們發現結果竟然不是3和8,所以結構體通過結構體名進行賦值就是簡單的值傳遞的。node1和node2在堆內存中開闢了兩個空間,各自是獨立的。僅僅是將node1的成員的值賦值給了node2相應的成員。

 

     最後看一個我經常容易忽視的問題:

        char *p="hello";
	char *pB=p
	pB[1]='a';
	printf("%s\n",pB);

 猜猜上面會輸出什麼?

 答案:發生中斷,報錯。

原因分析:“hello”是在常量區呀,p只是個指針,並沒有給p分配用於存儲“hello”的空間,所以p和pB同時指向了常量區的"hello"。常量區是不能修改的。所以報錯。

 

解決辦法:

        char *p=(char*)malloc(sizeof("hello"));
	memcpy(p,"hello",sizeof("hello"));
	char *pB=p;

	pB[2]='a';
	printf("%s\n",p);
	printf("%s\n",pB);

 此時,p擁有了自己的存儲"hello"的內存空間(在堆區),但是pB沒有。pB僅僅就是指向了p的那塊內存。所以可以說pB就是個窮指針。

發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章