刚开始学二维数组的时候,各种带括号的 * 和不带括号的 * 再加上数组下标[ ]让人痛不欲生……
但是想了半个月之后,我突然明白了他们的关系,所以特意梳理出来,希望能帮到想我之前一样的初学者们~
首先,先弄清几个基本的知识:
- 指针的双重性质
不同于我们之前的数据类型,指针包含了两重含义:第一,它本身是常量还是变量;第二,它所指向的是一个常量还是一个变量。
也就是说,如果指针本身是一个常量,那么它所指向的内容就是固定的,永远只能指向那一个数据,不可以被修改成指向其他的数据;如果指针指向的是一个常量,那么就不可以通过指针来对这个常量进行修改,但是如果这个指针本身是一个变量,那么就可以使它再指向另外的数据。
假如我们这样声明一个指针:
1.const int * ptr(等同于int const*ptr),那么这代表这个指针是一个指向常量的变量指针,不可以通过指针的间接访问来修改所指向的值。
int main() {
const int*ptr;
int number=5;
ptr=&number;
(*ptr)++; 试图通过指针间接访问来修改number的值
printf("%d\n",number);
return 0;
}
尝试编译运行,就会看到编译器报错:“increment of read-only location”。当然了,常量是不能进行写操作,而只能进行读操作。
但是值得注意的是,number本身是一个变量,不代表它的值不可以变化,但是只能通过number直接修改,比如number++,这样是不会报错的。
2.int*const ptr 这是一个指向变量的常量指针,不能再让这个指针指向别的量了。这种常量指针一定要在声明的时候同时进行初始化!
int main() {
int number1=5,number2=10;
int*const ptr=&number1;
ptr=&number2;
return 0;
}
这样也会报错,“assignment of read-only variable”。
- 运算符的优先级问题
相信很多人一开始接触指针的时候,都搞不明白这样一个事情:
int ( * matrix) [50] 和 int * matrix [50]
究竟有什么区别??
要弄明白这个事,首先要知道数组下标[ ]的优先级是高于 * 的!
所以,如果不加括号,那么matrix会先与[50]结合,然后整体再与 int * 结合,也就是形成了一个数组,数组的类型是int*,也就是50个指向int类型的指针,matrix是这个数组指针的首地址。也就是说,这不过是一个基类型是int*的一个数组而已,这些数组中的元素在内存中都是连续的,但是指向的内容不一定在内存中连续。
加上括号之后,matrix先与int* 结合,那这个时候matrix代表了什么呢?如果我们把 *matrix这个东西看做一个整体,比如将它替换成variable,那么原来的式子就变成了int variable[50],就是一个普通的数组,variable是数组的首地址。而 * matrix=variable,所以,matrix就是一个指向数组首地址的指针!!!,相当于一个二维指针。
想明白这一点,你就会知道为什么int ( * matrix) [50] 这种形式可以用作函数中二维数组的参数啦!当然,在数组下标(最后一个)中的数字是不可以省略的!
但是二维数组int matrix[10] [50] 就等同于int ( * matrix) [50]吗?
二者仍然有区别的!
要知道,不管是维数多大的数组,它在内存中永远都是一维的线性表示的,也就是在内存中以连续的地址表示。就是说matrix[0][49]后面就是matrix[1][0]。
但是在int ( * matrix) [50]中,从matrix[0][0]到matrix[0][49]确实是连续的,但是matrix[0][49]跟matrix[1][0]却不一定连续!,但是matrix[1][0]到matrix[1][49]却也是连续的,以此类推。
- 动态分配二维数组
我们先来看两个函数原型:
spin_matrix(int(*matrix)[20],int row,int col);
spin_matrix(int**matrix,int row,int col);
其实只从函数原型来看,我们也大体可以确定第一个是静态分配在栈上的数组,而后者是动态分配在堆上的数组。
那么究竟如何对二维数组进行动态分配呢?
#include<stdio.h>
#include<stdlib.h>
int main() {
int**matrix;
int row,col;
int i,j;
scanf("%d%d",&row,&col);
matrix=(int**)malloc(sizeof(int*)*row);
for(i=0;i<row;i++) {
matrix[i]=(int*)malloc(sizeof(int)*col);
}
return 0;
}
每次动态分配都不要忘记最后还要手动收回!不过收回的时候要先回收matrix [i],最后再回收matrix,否则会导致matrix[i]找不到,就成了内存垃圾。
for(i=0;i<row;i++) {
free(matrix[i]);
}
free(matrix);
4.二维数组作为函数参数
今天在做一道矩阵乘法的题目的时候,想用动态分配,把分配和输入的两个部分一起做了一个函数,但是一开始我的函数原型是这样的:
void get_matrix(int**matrix1,int**matrix2,int**result,int size);
没错……我忘记了对matrix进行动态分配的时候matrix的值发生了变化,**如果不按地址传递,变化是传不回main函数中的!**也就是说数组实际上还是相当于没有分配内存!!
所以最后这部分的函数应该写成:
void get_matrix(int***matrix1,int***matrix2,int***result,int size) {
int i,j;
*matrix1=malloc(sizeof(int*)*size);
*matrix2=malloc(sizeof(int*)*size);
*result=malloc(sizeof(int*)*size);
for(i=0;i<size;i++) {
(*matrix1)[i]=malloc(sizeof(int)*size);
(*matrix2)[i]=malloc(sizeof(int)*size);
(*result)[i]=malloc(sizeof(int)*size);
}
for(i=0;i<size;i++) {
for(j=0;j<size;j++) {
scanf("%d",&(*matrix1)[i][j]);
}
}
for(i=0;i<size;i++) {
for(j=0;j<size;j++) {
scanf("%d",&(*matrix2)[i][j]);
}
}
return;
}