从用作函数参数和构造链表的角度来区分C指针CJava引用
CC++的数据和代码块存储到内存,都有一个地址对应,对于变量,我们显式使用其值,需要显式使用其地址时,用指针变量。
指针变量有"己"和"他"的区隔,包括己型、己址、己值,他型、也址、他值,"己"和"他"都可以做左值,带来便利的同时,也带来了复杂性和安全问题。
多个指针指向同一块栈内存还好说,只存在多个指针可以修改值的问题,不存在内存释放的问题,因为栈内存可以自动释放。如果多个指针指向一块堆内存,就会存在一个所有权的问题,在手动释放时,就会存在一个指针释放,可能另一个指向相同堆内存的指针还在使用的问题。
C++最初只是"C with class",自然也是包含了指针变量这一语法机制。考虑到指针自身做左值的安全性,以及解引用写起来了的麻烦,C++引入了引用类型,设计引用变量为一个实现了自动解引用的具有常量性质的指针(常量除了要求不能用做左值外,还要求初始化)。
Java作为试图改良C++的编程语言,一定程度上摒弃了C++的复杂性,其中就包括指针,虽然也有引用类型,但是一个与C++不同的引用类型,Java的引用也是一个特殊的指针(显式的地址使用),但不是一个常量,可以用做左值,没有C++考虑让引用作为常量的原因(安全问题)的问题吗,没有,因为其有自动GC(Garbage collection 垃圾回收)功能,且所有对象都是通过一个引用变量来操作,对象本身生存在堆内存上,引用本身生存在栈内存上,由GC根据对象引用的情况来确定对象回收的时间。
JAVA中的对象类型本质上应该叫做对象指针类型。那么传统的对象类型呢?在JAVA里已经不见了踪影!既然没有了传统的对象类型,那么对象引用变量前面的*也就可以不要了。对象引用变量也就可以简称为对象变量了,反正也不会和其它概念混淆! 所有的对象变量都是引用,没有非引用的对象变量,想不用引用都不行,这就是指针的泛化和强化。 不叫指针了,就叫对象变量,这就是概念上的淡化和弱化。 没有了指针的加减运算,也没有了解引用*、对象指针成员引用->等运算符,这是对指针的简单化。1 指针变量对普通变量和指针变量的副作用#include // 指针的副作用要解引用做左值, // 要对主调函数的一个一级指针产生副作用,被调函数对应的形参必须是一个二级指针 #include void test(int **pp,int *p,int n) // pp对一个一级指针产生副作用,p对一个变量产生副作用,n传址 { *pp = (int *)malloc(sizeof(int)); **pp = n*10; *p = ++n; p = (int *)malloc(sizeof(int));// 指针产生副作用要求解引用做左值,否则是自身的操作,不会产生负作用 *p = n*100; // 此时的解引用不会影响主调函数的值,因为其指针有了另指向 printf("%d ",*p); // 1200 } int main() { int a = 11; int *p = &a; test(&p,&a,a); printf("%d ",a); // 12 printf("%d ",*p); // 110 getchar(); }2 数组指针用作函数参数
在C语言中,数组是一个特殊指针,是一个具有常量性质,而下标索引也只不过是指针算术运算的语法糖。#include #include void test(int (*ap)[4],int n) { *(*(ap+2)+3) = 23; // 产生副作用也是解引用机制,解引用也就是ap指向的目标对象 //ap是一个指针,指向类型是int[4],所以需要二次解引用产生别作用 // ap[2][3] = 23; // 下标操作是上述写法的语法糖 ap = (int(*)[4])malloc(sizeof(int)*4*n); // ap自身(己型、己值)做左值,没有副作用 int arr[3][4] = {0}; ap = arr; ap[2][3] = 46; } int main() { int arr[3][4] = {0}; int n = sizeof arr / sizeof *arr; test(arr,n); printf("%d ",arr[2][3]); // 23 getchar(); }3 结构体和结构体指针用作函数参数#include // 结构体和结构体指针做函数参数 typedef struct contact{ char * name; char * tel; }ct,*pct; void test(ct c,pct p) { c.name = "ABC"; // 结构体传值不存在副作用 (*p).name = "DEF"; // 解引用对成员产生副作用 // p->name = "DEF";// 上述写法的语法糖 ct d = {"xyz","789"}; p = &d; // 指针本身做左值,不会对指针目标对象产生副作用 p->name = "JPG"; } int main() { ct c = {"abc","123"}; ct d = {"def","456"}; test(c,&d); printf("%s ",c.name); // abc printf("%s ",d.name); // DEF getchar(); }4 C++引用相对于指针,使用更简洁#include // C++引用相对于指针,使用更简洁 void swap(int *a,int *b) { int t = *a; *a = *b; *b = t; } void swap(int &a,int &b) { int t = a; a = b; b = t; } int main() { int a=3,b=4; swap(&a,&b); swap(a,b); getchar(); }5 C++实现单链表
结构体可以包含一个自指向的指针变量,因为对于一个数据类型来说,只需要类型确定,需要的内存空间确定。对于自指向的结构体来说,其自指向指针的类型是确定的,内存大小也是确定的(因为所有指针大小都是一个字长对应的字节),所以结构体类型本身也是确定的。#include using namespace std; struct node //定义结点结构类型 { char data; //用于存放字符数据 node *next; //用于指向下一个结点(后继结点) }; // …………创建………… node * Create() { node *head=NULL; //表头指针,一开始没有任何结点,所以为NULL node *pEnd=head; //表尾指针,一开始没有任何结点,所以指向表头 node *pS; //创建新结点时使用的指针 char temp ; //用于存放从键盘输入的字符 cout<<"请输入字符串,以#结尾:" <>temp; if(temp!="#") //如果输入的字符不是#,则建立新结点 { pS=new node; //创建新结点 pS->data=temp; //新结点的数据为temp pS->next=NULL; //新结点将成为表尾,所以next为NULL if(head==NULL) //如果链表还没有任何结点存在 head=pS; //则表头指针指向这个新结点 else //否则 pEnd->next=pS; //把这个新结点连接在表尾 pEnd=pS; //这个新结点成为了新的表尾 } }while(temp!="#"); //一旦输入了#,则跳出循环 return head; //返回表头指针 } //…………遍历………… void Showlist(node *head) { node *pRead=head; //访问指针一开始指向表头 cout<<"链表中的数据为:" <data; //输出当前访问结点的数据 pRead=pRead->next; //访问指针向后移动(指针偏移) } cout<data==keyWord) //如果当前结点的数据和查找的数据相符 { return pRead; //则返回当前结点的指针 } pRead=pRead->next; //数据不匹配,pRead指针向后移动,准备查找下一个结点 } return NULL; //所有的结点都不匹配,返回NULL } // …………插入………… void Insert(node * &head,char keyWord,char newdata) //keyWord是查找的字符(确定插入的位置) { node *newnode=new node; //新建结点 newnode->data=newdata; //newdata是新结点的数据 node *pGuard=Search(head,keyWord); //pGuard是插入位置前的结点指针 if(head==NULL || pGuard==NULL) //如果链表没有结点或找不到关键字结点 { //则插入表头位置 newnode->next=head; //先连 head=newnode; //后断 } else //否则 { //插入在pGuard之后 newnode->next=pGuard->next; //先连 pGuard->next=newnode; //后断 } } // …………节点删除………… void Delete(node * &head,char keyWord) //可能要操作表头指针,所以head是引用 { if(head!=NULL) //如果链表没有结点,就直接输出提示 { node *p; node *pGuard=head; //初始化pGuard指针 if(head->data==keyWord) //如果头结点数据符合关键字 { p=head; //头结点是待删除结点 head=head->next; //先连 delete p; //后断 cout<<"被删除的结点是" <next!=NULL) //当pGuard没有达到表尾 { if(pGuard->next->data==keyWord) //如果pGuard后继结点数据符合关键字 { p=pGuard->next; //pGuard后继结点是待删除结点 pGuard->next=p->next; //先连 delete p; //后断 cout<<"被删除的结点是" <next; //pGuard指针向后移动 } } } cout<<"The keyword node is not found or the link list is empty!" <next; //先连 delete p; //后断 } cout<<"The link list has been deleted!" <
游戏机还是电脑主机?GPDWIN3外观揭晓后玩家直呼爱了从儿时的小霸王到现在的任天堂,相信大家都接触过不少的游戏机。虽说游戏不是生活的全部,不过游戏却给我们带来了无限的快乐。然而随着生活节奏的加快,固定场所的游戏已然不能满足我们的需求,
音乐和聊天软件的互联,为我们生活带来了什么改变?近日,一个知乎KOL菇凉子在平台上分享了一个女生巧用微信状态页分享歌曲歌词的功能,解决了恋爱中的烦恼的故事。不得不说,真的是科技改变恋爱。一个小小的微信页面分享QQ音乐功能就可以解
WiFi6MESH,没有天线的路由器,锐捷星耀M18来了快餐时代缺的永远是生产力,如何让生活工作效率更高,是人们一直的追求。路由器作为连接网络与移动设备的媒介产品,它的优劣会直接影响到网络的使用,今天我们一同来看一下锐捷发布的最新无线网
联想闪退科创板,含科量问题到底多大?wumiancaijing。com在招股书中,联想罗列了一些科研成果,其中包括量子位颁发的中国人工智能领航企业TOP50,而量子位是一家自媒体账号。本文由无冕财经(wumianca
最大架构调整!商业化元老出走,快手发生了什么?焦点wumiancaijing。com电商被视为快手第二增长曲线,但在接近2万亿的体量中,快手的20亿营收显得有些微不足道。本文由无冕财经(wumiancaijing)原创发布作者海棠
从全国第15名到第4名,深圳国资委有哪些不可告人的机密wumiancaijing。com深圳国资委的成功不是偶然现象,背后隐藏着大杀器,一套科学合理的融投管退投资体系。本文经授权转载自公众号无冕财报局IDwmukbnews作者饶祖分编
打的就是精锐!份额飙至16。2,荣耀要从iPhone13口中抢食wumiancaijing。com尽管中国手机厂商从去年就开始加快对高端市场的布局,但仍未能接住华为空出的空间这部分空间,都被苹果吃下了。荣耀Magic3系列的入局,也许是破局的开
股价暴跌近9成后,匆忙卖物业,这家千亿房企有多危险?深度wumiancaijing。com股价暴跌前,有消息称总部员工全员降薪,而面对10月到期的美元债,有投资者心急催促创始人想办法归还,新力控股有多缺钱?本文由无冕财经(wumianc
十大历史文化名楼中国历史悠久,文化底蕴深厚。古往今来,历朝历代,上至皇帝诸侯,下至州府官员,都喜欢于风景名胜江边河岸处修建楼阁。或用来歌功颂德宣扬政绩或镇妖伏魔保一方安宁或瞭望守备,抵御外敌。总之
世界十大猛禽世界十大猛禽分别是非洲冕雕,雕鸮,皱脸秃鹫,髯鹫,美洲角雕,菲律宾鹰,金雕,毛腿鱼鸮,虎头海雕,猛雕非洲冕雕非洲冕雕体长8991厘米,体重45公斤,翼展1。82。5米,属于大型猛禽
独角兽神话传说中的生物独角兽为神话传说中的一种虚构的生物。现行西方神话的独角兽则形如白马,额前有一个螺旋角,代表高贵高傲和纯洁。有的故事中描述为长有一双翅膀,甚至还有独角兽是黑色的描述。西方独角兽的原型