赋值操作符的思考

         我要说的是一个小问题,感觉写在博客里面比较好。以后看到了可以回忆警示一下。

    问题是这样的:在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就是个穷指针。

你可能感兴趣的:(操作符)