前言
??最近在攻读《深入理解C指针》,做一下笔记。
问题
??我们都知道,在C语言里动态分配内存并不难:
int* p = (int*)malloc(sizeof(int));
??如果我们希望通过一个函数,令一个指针指向一块新分配的内存,并在函数中完成赋值呢? ??根据函数设计的本质来区分,有两个方案。
方案一:返回指针
??这个是最好想的方案了。首先,让一个指针指向一块新分配的内存,并在内存中依次赋值(可以将内存理解为一个数组),这种事,不需要封装在函数里也OK的吧。既然你非得把它放到函数里,那我就在函数中设一个形参,令这个形参完成这一系列动作,完事了通过返回值返回,赋值给实际的指针不就好了? ??上代码:
int* allocateArray(int size, int value) {
int* arr = (int*)malloc(size * sizeof(int));
for (int i = 0;i < size;i++) {
*(arr +i) = value;
}
return arr;
}
??赋值的方法和数组赋值一样所以下面两行代码是等价的:
*(arr +i) = value;
arr[i] = value;
??关于*(arr +i) = value; 这行代码倒是可以多说两句,因为指针这种东西不见得一次能看明白。 ??首先回头看这一句:int* arr = (int*)malloc(size * sizeof(int)); 这行代码产生了什么效果?指针变量,arr里面存的内容就是新内存的首地址。 ??继续,arr+i ,我们把他具体一点看,arr+1 是什么意思? ??这个arr+1 可不是说首地址的数值增加1啊。在C/C++中规定对于指针变量的内容,加减操作都是以该指针指向的类型作为基本单位来计算的。所以arr+1 不是地址加了1,而是地址加了1*4(我们假设是32位机,int是4个字节)。 ??明白这些之后,arr +i 的意思就很清晰了:在新开辟的内存中依次产生4个字节的移动。随后使用解引用过给每个int类型赋值! ??那么,有没有方案能够,不用返回值,我想调用起来省事,直接修改行不行呢?
方案二:传递指针的指针
??我们继续思考,函数的返回值是值传递后参数与实参传递的桥梁,依靠返回值写函数就不需要考虑太多关于值传递的内容。当失去返回值之后,我们就需要从函数传参的角度出发,去思考函数的编写。 ??函数传参分为普通的值传递,指针传递与引用传递,因为今天是指针环节,所以引用就不考虑了;而值传递是无法将运算结果传出到函数外的(因为函数的内容都在栈里,结束之后销毁所有形参)。因此我们考虑使用指针传递去解决问题。 ??我们的目标是让一个指针指向一块新分配的内存,也就是改变一个指针变量的内容,令该指针变量里存放的内容为新内存的首地址。OK,我们说,改变常规变量的内容,需要传入指针,如果需要改变指针的内容,就需要传入指针的指针,即双指针。 ??上代码:
void allocateArray2(int **arr, int size, int value) {
*arr = (int *)malloc(size * sizeof(int));
if (*arr != nullptr) {
for (int i = 0;i < size;i++) {
*(*arr + i) = value;
}
}
}
??在使用双指针的时候一定要缕清每一层的关系。 ??先说arr,这是一个双指针,它本身的地址不重要,不去讨论,重要的是arr里的内容。由双指针的概念可以得知, arr里面的内容是一个指针的地址,而arr就是arr指向的指针的地址,我们将(int *)malloc(size * sizeof(int)) 这个值赋给它,等于是修改了arr指向的指针的内容。 ??这样arr指向的就是新开辟的内存的首地址,实际上这里的*arr就是第一个方案里的arr 。显然方案一用的是一级指针,方案二用的是二级指针,那么二级指针加上星号进行解引用,自然是一级指针。 ??搞清楚一级指针和二级指针后*(*arr + i) = value; 这样的赋值语句也很好理解了。 ??最后附上全部的实现与调用代码:
int* allocateArray(int size, int value) {
int* arr = (int*)malloc(size * sizeof(int));
for (int i = 0;i < size;i++) {
*(arr +i) = value;
}
return arr;
}
void allocateArray2(int **arr, int size, int value) {
*arr = (int *)malloc(size * sizeof(int));
if (*arr != nullptr) {
for (int i = 0;i < size;i++) {
*(*arr + i) = value;
}
}
}
int main()
{
int *vector = nullptr;
vector = allocateArray(2, 5);
for (int i = 0;i < 2;i++) {
cout << vector[i] << endl;
}
allocateArray2(&vector, 3, 3);
for (int i = 0;i < 3;i++) {
cout << vector[i] << endl;
}
free(vector);
}
??因为是c++文件,所以输出用了iostream里的函数,在C语言中改成printf形式的即可。
|