第25课 - 指针数组和数组指针分析
思考:
下面这些声明合法吗?
int array[5]; 常规数组
int matrix[3][3]; 二维数组
int* pA = array; pA指针用array初始化,pA指向的是首元素的地址,pA不是数组指针
int* pM = matrix; pM指针用matrix初始化
问题:
l array代表数组首 元素地址,那么matrix代表什么?
l arrry(数组首元素的地址,int*类型)和&array(数组的起始地址)的地址相同,但是意义不同,那么指向它们的指针类型相同吗?
一般情况下声明一个数组之后,比如int array[5],数组名array就是数组首元素的首地址,而且是一个地址常量。但是,在函数声明的形参列表中除外。
在C中, 在几乎所有使用数组的表达式中,数组名的值是个指针常量,也就是数组第一个元素的地址。 它的类型取决于数组元素的类型: 如果它们是int类型,那么数组名的类型就是“指向int的常量指针“。——《C和指针》
在以下两中场合下,数组名并不是用指针常量来表示,就是当数组名作为sizeof操作符和单目操作符&的操作数时。 sizeof返回整个数组的长度,而不是指向数组的指针的长度。 取一个数组名的地址所产生的是一个指向数组的指针,而不是一个指向某个指针常量的指针。所以&a后返回的指针便是指向数组的指针,跟a(一个指向a[0]的指针)在指针的类型上是有区别的。——《C和指针》
“+1”就是偏移量问题:一个类型为T的指针的移动,是以sizeof(T)为移动单位。
即array+1:在数组首元素的首地址的基础上,偏移一个sizeof(array[0])单位。此处的类型T就是数组中的一个int型的首元素。由于程序是以16进制表示地址结果,array+1的结果为:0012FF34+1*sizeof(array[0])=0012FF34+1*sizeof(int)=0012FF38。
即&array+1:在数组的首地址的基础上,偏移一个sizeof(array)单位。此处的类型T就是数组中的一个含有5个int型元素的数组。由于程序是以16进制表示地址结果,&array+1的结果为:0012FF34+1*sizeof(array)=0012FF34+1*sizeof(int)*5=0012FF48。注意1*sizeof(int)*5(等于00000014)要转换成16进制后才能进行相加。
- 数组类型
(1)c语言中的数组有自己特有的类型,数组的类型由元素类型和数组大小共同决定。
eg:
int array[5]的类型为int[5];
(2)C语言中通过typedef为数组类型重命名:typedef type(name)[size];
eg:
typedef int(AINT5)[5];
typedef float(AFLOAT10)[10];
数组定义:AINT5 iArray;
AFLOAT10 fArray;
- 数组指针
(1)数组指针用于指向一个数组。
(2)数组名是数组首元素的地址,但不是数组的起始地址。
(3)通过取地址符&作用于数组名可以得到数组的起始地址。
int i[5]; int* PI = &i;
(4)可通过数组类型定义数组指针:
ArrayType* pointer;(如AINT5* vp)
也可以直接定义:type (*pointer)[n];
pointer为数组指针变量名,type为指向的数组的类型,n为指向的数组的大小。
int (*p)[n];
例程:
#include <stdio.h>
typedef int(AINT5)[5];
typedef float(AFLOAT10)[10];
typedef char(ACHAR9)[9];
// three array's type
int main()
{
AINT5 a1;
float fArray[10];
AFLOAT10* pf = &fArray;
ACHAR9 cArray;
char(*pc)[9] = &cArray; //数组指针
char(*pcw)[4] = cArray; //把char*类型的指针赋值给数组指针,是不合理的,
int i = 0;
printf("%d, %d\n", sizeof(AINT5), sizeof(a1));
for(i=0; i<10; i++)
{
(*pf)[i] = i;
}
for(i=0; i<10; i++)
{
printf("%f\n", fArray[i]);
}
printf("%0X, %0X, %0X\n", &cArray, pc+1, pcw+1);
//pc+1 ----- (unsigned int)pc + 1*sizeof(*pc)
}
运行结果:
20,20
0.000000
1.000000
2.000000
3.000000
4.000000
5.000000
6.000000
7.000000
8.000000
9.000000
18FEFC,18FF05,18FF00
分析:18FF05与18FEFC差九个字节,18FF00与18FEFC差四个字节。
- 指针数组
(1)指针数组是一个普通的数组。
(2)指针数组中每个元素为一个指针。
(3)指针数组的定义:type* pArray [n];
type*为数组中每个元素的类型,pArray为数组名,n为数组大小。
eg:
例子:指针数组的使用,关键字查找
#include <stdio.h>
#include <string.h>
int lookup_keyword(const char* key, const char* table[], const int size)
{
//数组在函数中变成了一个指针,大小必须要另一个变量来定义
int ret = -1;
int i = 0;
for(i=0; i<size; i++)
{
if( strcmp(key, table[i]) == 0 )
{
ret = i;
break;
}
}
return ret;
}
#define DIM(a) (sizeof(a)/sizeof(*a))
int main()
{
const char* keyword[] = {
"do",
"for",
"if",
"register",
"return",
"switch",
"while",
"case",
"static"
};//char*指向字符串
printf("%d\n", lookup_keyword("return", keyword, DIM(keyword)));
printf("%d\n", lookup_keyword("main", keyword, DIM(keyword)));
}
运行结果:
4
-1
- main函数的参数
(1)main函数可以理解为操作系统调用的函数。
(2)在执行程序的时候可以向main函数传递参数。
int main()
int main(int argc)
int main(int argc, char* argv[])
int main(int argc, char* argv[], char* env[])
argc:命令行参数个数
argv:命令行参数数组
env:环境变量数组
例子:
#include <stdio.h>
#include <string.h>
int lookup_keyword(const char* key, const char* table[], const int size)
{
//数组在函数中变成了一个指针,大小必须要另一个变量来定义
int ret = -1;
int i = 0;
for(i=0; i<size; i++)
{
if( strcmp(key, table[i]) == 0 )
{
ret = i;
break;
}
}
return ret;
}
#define DIM(a) (sizeof(a)/sizeof(*a))
int main()
{
const char* keyword[] = {
"do",
"for",
"if",
"register",
"return",
"switch",
"while",
"case",
"static"
};//char*指向字符串
printf("%d\n", lookup_keyword("return", keyword, DIM(keyword)));
printf("%d\n", lookup_keyword("main", keyword, DIM(keyword)));
}
运行结果:(打印命令行和windows下面的一些信息)
小结:
l 数组指针本质是一个指针
l 数组指针指向的值是数组的地址
l 指针数组本质上是一个数组
l 指针数组中每个元素的类型都是指针