数组与指针

数组

一维数组

数组初始化之前数组元素是不确定的,当数值数量少于数组元素时,多余的数组元素被初始化为0

只读数组初始化后不能再对它赋值

如何计算一个数组的大小: sizeof(a)/sizeof(a[0]) 即数组大小除以单个元素的大小

c99新特性:int arr[6]={12,[5]=22,23,[1]=35};这一语句代表第1个元素值为35,第5个值为22,第6个值为23

数组的赋值方式:

  1. 只可以用循环来赋值
  2. 不可以用花括号赋值(仅限于数组初始化),不可以将一个数组赋给另一个数组

数组的边界问题需要程序员来保证,编译器检查索引的合法性,因为c语言信任程序员的原则,不检查边界可以让程序运行更快,解决方法是将数组大小全部定义为符号常量,使用数组大小的时候全部直接引用符号常量

c99之前声明数组时方括号内只能使用整数常量表达式, sizeof被认为是一个整数常量,因此可以放在数组的声明里

指针

在c中,对一个指针加1的结果是对该指针增加1个存储单元。这就是为什么声明指针的时候必须声明它指向的对象类型。

将数组作为参数传入函数时,一般要同时传入数组的大小。因为作为参数传入的实际是一个指向数组元素类型的指针,在函数内部无法用sizeof得出数组的大小,只能得出这个指针的大小。

函数原型允许省略名称:

int sum(int *ar,int n);
int sum(int *,int);
int sum(int ar[],int n);
int sum(int [],int);

函数定义不可以省略名称:

int sum(int *ar,int n){
  //代码
}
int sum(int ar[],int n){
  //代码
}

使用数组的函数有两种方式:

  1. 传入数组元素个数
  2. 传入两个指针,一个指向起始地址,一个指向结束地址(结束地址指向的是数组最后一个元素之后,c语言中指向数组之后的第一个元素的指针也是合法的,仅仅是指针合法,所指的值不合法!

*++的优先级:优先级相同,但是结合时从右往左进行。

指针操作

  1. 赋值
  2. 求值或取值。用*可取出指针指向地址中存储的数值
  3. 去指针地址
  4. 将一个整数加给指针。该整数会先和指针所指类型的字节数相乘,然后所得的结果加到初始地址上
  5. 增加指针的值。ptr++
  6. 从指针中减去一个整数
  7. 减小指针的值
  8. 求差值。通常对指向同一个数组的内的两个元素的指针求差值,以求出元素之间的距离
  9. 比较。前提:两个指针具有相同的类型

常见错误:对未初始化的指针取值,其危害在于未初始化的指针中的初值未知,因此不知道会覆盖哪里的数据。

int *ptr;
*ptr=5;

切记:当创建了一个指针时,系统只是分配了用来存储指针本身的内存空间,并不分配用来存吃数据的内存空间!

指针最基本的功能在于同函数交换信息

保护数组内容

如果希望函数不改变数组的内容,可以在函数原型和定义的形式参量声明中使用关键字const,作用是告诉编译器,函数应当将该数组作为包含常量数据的数组对待。好处是,这样做并不要求原数组是固定不变的

关于const

  1. 用const可以定义指向常量的指针,这样就不可以用该指针来修改它所指的数值,此时const放在 * 前

  2. 将常量或非常量数据的地址赋给指向常量的指针是合法的,但只有非常量数据的指针才可以赋给普通指针。原因:如果指向常量的指针可以赋给普通指针,那么就可以通过该普通指针修改被认为是常量的数据了

    用处:如果函数的原型中形式参数声明使用const,那么该函数既可以接收普通指针,又可以接收指向常量的指针。但是如果函数原型中不使用const,那么就不可以接收指向常量的指针!

  3. 用const可以保证指针不会指向别处,此时const放在 * 之后

  4. 同时用两个const表示既不可以修改所指的数值,又不可以更改所指地址

指针与多维数组

int zippo[4][2]

其中zippo是所指向对象的大小是两个int,zippo[0]所指向的对象是一个int

注意:*(zippo+2)表示zippo[2][0]的地址,*(*(zippo+2)+1)表示zippo[2][1]的值

如何定义指向二维数组的指针?

int (*pz)[2];	//一定要加括号,表示指向一个包含两个int值的数组
pz=zippo;

int *pax[2];	//表示定义两个指针组成的数组

区别于指针可以将非const的指针赋给const的指针,不可以将非const的指针的指针赋给const的指针的指针,这种赋值只允许一层间接关系

const int **pp2;
int *p1;
const int n=13;
pp2=&p1;	//非法,但假设合法
*pp2=&n;//合法,二者都是const,同时也会让p1指向n
*p1=10;//合法,但此时会修改n的值

函数与多维数组

函数原型等价形式:

void somefunction(int (*pr)[4],int rows);
void somefunction(int pt[][4],int);
void somefunction(int [][4],int rows);
void somefunction(int [3][4],int rows);	//合法,但是3会被忽略

每个函数都把pt看作指向包含4个int值的数组的指针,列数在函数体内定义,但行数需要作为参数传入

变长数组

C99标准引入变长数组,允许使用变量定义数组各维

注意:

  1. 变长数组的“变”表示维数可以用变量来指定,而不是创建数组之后可以修改其大小
  2. 变长数组必须是自动存储类的,意味着它们必须在函数内部或作为函数参量声明,而且声明时不可以进行初始化。即不能定义在函数的外部,而且不可以初始化!
int sum2d(int rows,int cols,int ar[rows][cols]);	//合法
int sum2d(int,int,int ar[*][*]);	//合法,可以省略维数参量的名称,用星号代替
int sum2d(int ar[rows][cols],int rows,int cols);	//非法,顺序不对

复合文字

C99新增复合文字,文字是非符号常量,复合文字没有名称,因此必须在创建它们的同时通过某种方法使用它们

如何定义:

(int [2]){10,20}
(int [])={10,20,30}	//可以省略数组大小

使用方法:

  1. 文字常量同时代表首元素的地址,可以用它给一个指向int的指针赋值
  2. 可以作为实参传递给带有类型与之匹配的形式参数的函数。该方法较为常用,好处在于可以给函数传递信息而不必先创建数组
posted @ 2020-02-08 14:40  咸鱼不闲咋整啊  阅读(144)  评论(0编辑  收藏  举报