【原创】浅谈指针(三)

上期链接

https://www.cnblogs.com/jisuanjizhishizatan/p/15365823.html

前言

我写本文的初衷是为了让更多的人了解指针。最近一直有人在我的博文点反对,我也不想点名,只是想说:不要对指针怀有偏见。你可以认为本文的东西都在胡扯,但是,不管如何,请你自己在自己的电脑上运行一下,检验我的言论是否正确。我撰写这些文章之前,一定阅读了很多参考资料,不会随便乱写一通。如果真有什么错误之处,也请大家在评论区指出。

引用和指针

言归正传,上期我们讲了swap函数,花了很大的篇幅。但是,仔细观察algorithm库中的swap,在调用的时候不需要写&符号取地址?这是由于它使用了C++的引用机制。
什么是引用?它和指针有什么异同之处?我们一起观察。首先,我们看一个简短的例子。

#include<bits/stdc++.h>
using namespace std;
int main(){
  int a=10;
  int &ref=a;
  printf("a..%d,ref..%d\n",a,ref);
  ++a;
  printf("a..%d,ref..%d\n",a,ref);
  return 0;
}

把第7行的++a换为++ref,结果相同。
int &ref=a,表示建立一个变量为a的引用,名为f。很多书上这样写:

ref相当于a的别名,使用ref就是使用a。

我可以负责任的告诉你,上述描述是错误的。
事实上,ref和a,不是“别名”的关系,而是两个使用相同地址的变量。一般定义两个变量,它们地址一定不相同,但是引用变量和被引用变量的地址相同,才能导致“修改ref就是修改a”的效果。
在swap中,如果我们指定参数中的ab和main中的ab地址相同,就可以“不使用指针进行交换”了。(但是其实C++编译过程中,引用就是用指针实现的)我们可以这样写代码:

void Swap(int &a,int &b){
    int t=a;a=b;b=t;
}

这样一来,swap中的ab和main中的ab地址相同,就可以直接交换,省去了取地址的操作。

引用的内部实现

我们尝试把这一篇中,使用引用的swap和上一篇使用指针的swap进行反汇编,看看生成的汇编代码有何不同。我这边使用在线工具:https://godbolt.org/
实验证明:两个swap函数内部完全相同。这也表明,C++在编译的时候,会把引用当作指针处理。
事实上,不可能存在地址完全相同的变量,其中一个变量必定是指针才能实现这样的效果(即让其中一个变量指向另一个)。只不过,我们在引用的书写中,不需要多写一个&符号和*符号而已。

可变长结构体

注:这一段是参考《征服C指针》写的,由于该书出版第一版时C99未发行,因此可能内容与最新的C或C++有一定出入,见谅。
假设我们要开发一个画图软件,其中有一个折线的功能。折线是由多条直线构成的,因此,结构体应该这样定义:

struct Point{
    int x,y;
};
struct Line{
    Point p1,p2;
};
struct Polyline{
    int n;
    Line *l;
};

如果要对Polyline分配内存,那么必须使用new分配两次内存。一次给polyline整体分配内存,第二次需要给成员l分配内存。(原书由于是C语言,写的是malloc,本文给了一些修改)

Polyline *p;
p=new Polyline;
p.l=new Line [n];

但是我们可以这样写结构体,这样只需分配一次内存了。

struct Polyline{
  int n;
  Line l[1];
};

然后使用如下的方法分配内存:

p=(Polyline*)malloc(sizeof(Polyline)+n*sizeof(Line));

虽然数组只定义了一个,但是在分配p空间的时候,我们发现,多分配了n个空间,给到后面的Line。这样一来,即使Line的后续元素(第2个,第3个)不在结构体中,也能使用。图示如下:(自己画的)

这种写法称作可变长结构体。在C99中,专门扩展了这个语法(之前的这种写法都属于“违反标准的技巧”),并且可以在定义最后元素l的时候直接使用空方括号[]。

free/delete

free和delete用于释放内存。free一般用于C语言,释放malloc的内存。delete用于C++,释放new的内存。程序实例:

#include<bits/stdc++.h>
using namespace std;
int main(){
    int *p=new int;
    *p=100;
    cout<<*p;
    delete p;
}

如果把第4行的new换为malloc,那么最后一行也要换为free(p)。
注意事项:
1.以前有个函数叫做cfree,和calloc配对使用。(calloc也用于内存分配)但是现在建议大家不要使用cfree。
2.delete数组的时候,要加上[]符号,例如 delete []p
3.小心多个指针同时指向同一内存时,如果free掉其中一个指针,其他指针仍在使用将会非常危险。

今天内容到此为止。

posted @ 2021-10-04 21:57  计算机知识杂谈  阅读(269)  评论(0编辑  收藏  举报