我要说的是一个小问题,感觉写在博客里面比较好。以后看到了可以回忆警示一下。
问题是这样的:在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就是个穷指针。
相关推荐
赋值操作符需要特别注意,因为它涉及到对象的深拷贝和浅拷贝问题,以及可能的自我赋值情况,所以在重载时需要特别小心。 总的来说,多态性是面向对象编程中一个强大的工具,它通过提供通用的接口处理不同类型的数据...
如果没有序列点的概念,就很难解释为什么表达式中的自增操作符(具有较高优先级)会在这个例子中后于赋值操作符求值。 逻辑与操作符&&和逻辑或操作符II也存在序列点,以支持其“短路”特性。逻辑与操作符&&在求值...
Swift语言还包括了基本操作符,比如赋值操作符、算术操作符、余数操作符、增量和减量操作符、逻辑操作符和范围操作符等,以支持数值和逻辑运算。同时,Swift支持字符串和字符的操作,包括字符串插值、字符串比较、...
14.2.1 派生类中的赋值操作符和复制 构造函数 426 14.2.2 派生类的析构函数 426 14.2.3 保护继承和私有继承 436 14.2.4 多继承 437 第15章 多态与虚函数 442 15.1 虚函数基础 442 15.1.1 后绑定 442 15.1.2 ...
在C++从零开始(四)中,你将了解简单的赋值操作符(=)以及复合赋值操作符(如+=、-=等),它们是如何在代码中改变变量状态的。 “何谓指针”是C++的一个特色,它允许你直接操作内存地址。在C++从零开始(五)中,...
- 讲解了操作符,如算术、比较和逻辑操作符,以及它们的优先级。 - 介绍了如何组合使用操作符和变量来表达复杂的计算。 第3章 函数: - 讨论了浮点数和类型转换,如double到int。 - 介绍了一些数学函数,如平方根和...
笔记中还提到了一种利用编译错误预防常见编程错误的方法,即通过改变条件表达式顺序来避免误用赋值操作符等于号。 第五章简要介绍了类的概念,成员函数被定义为类的一部分,有时被称为“类方法”。学习笔记中提醒了...
解释:在C语言中,&操作符是 取地址运算符,可以获取变量的内存地址。*&a表示获取a的地址,然后将其赋值给point指针变量。 2. 若有说明:int *p, m = 5, n; 以下正确的程序段是: 答案:A. p = &n; 解释:在C语言...
本篇复习题旨在帮助学生掌握Python语言的基础知识,包括语法、数据类型、操作符优先级、注释方式、变量赋值以及常用的内置函数。 1. **标识符**:在Python中,合法的标识符可以由字母、数字和下划线组成,但不能以...
3. 变量和操作符:包括变量的声明和赋值,状态图,打印变量,以及算术操作符。在这一部分中,读者可以学习到如何在Java中存储和操作数据。 4. 输入输出操作:利用System类和Scanner类进行输入输出操作,介绍了程序...
2. **操作符与表达式**:包括算术操作符、比较操作符、逻辑操作符,以及三元条件运算符。理解这些操作符的用法对于编写逻辑复杂的代码至关重要。 3. **函数**:JavaScript中的函数是可重用的代码块,可以接受参数并...
- **操作符**:介绍Python中的比较操作符、赋值操作符、算术操作符、逻辑操作符等。 ### 其他知识点 - **攻击技术**:书中可能包含如何使用各种工具和脚本进行网络攻击的知识。 - **安全攻防**:涵盖安全测试与...
3. **优先考虑复制构造函数和赋值操作符**:为了确保对象的正确复制和赋值,作者建议程序员显式定义复制构造函数和赋值操作符,尤其是当类包含资源管理逻辑时。 4. **使用const正确地表达意图**:通过合理地使用...
3. **操作符**:包括算术操作符、逻辑操作符、比较操作符和位操作符等,如+、-、&、|、<、>、~等,用于实现逻辑功能。 4. **进程与语句**:如always块用于描述时序逻辑,initial块用于初始化值,case语句和if-else...
- 所有的二元数学操作符都有相应的增强赋值操作符,例如 `+=`、`-=` 等。 - 并非所有的数学运算都需要引用第三方库 `math`,Python 内置了很多常用的数学运算功能。 ### 5. 运算符优先级 - 表达式 `25\2` 中,反...
创建 `Person` 对象并设置其属性值后,通过赋值操作符 `=` 可以将一个对象赋值给另一个对象,如 `b = a;`。在这种情况下,`b` 和 `a` 指向相同的内存地址,因此修改 `b` 的属性会影响到 `a`。 关于对象在内存中的...
操作符也是脚本编程中的重要元素,包括算术操作符、关系操作符和逻辑操作符等。 当学习者对基础有了一定掌握之后,可以进入更高级的学习阶段,例如变量重游,这涉及到操作字符串、参数替换、声明变量类型以及变量的...
在本章节中,读者将接触到C++的基础知识,包括但不限于变量、数据类型、操作符、表达式、控制流以及函数的使用。下面将对这些知识点进行详细阐述。 首先,变量是程序中存储数据的容器。在C++中,我们需要先声明变量...