C语言指针和数组
指针和地址
指针是编程语言中的一类数据类型及其对象或变量,用来表示或存储一个内存地址,这个地址的值直接指向(points to)存在该地址的对象的值。
取值运算*p
返回保存在内存地址为p的内存空间中的值。取地址&p
运算则返回操作数p的内存地址
C语言是以传值的方式将参数值传递给被调用函数,被调用函数不能直接修改主调函数中的值,需要修改主调函数中的值就需要利用指针
指针和数组
数组名代表的是该数组的第一个元素的地址,对于
a[i]
的引用可以写成*(a+i)
或者*(pin + i)
或者pin[i]
,通过数组名和下标实现的表达式可等价通过指针和偏移量实现
int a[10];
int *pin;
pin = &a[0];
pin = a;
pin = pin + 1;
pin = &a[1];
pin = a + 1;
不同的是数组名和指针之间,数组名代表的是一个常量,相反指针代表的是一个变量,因此
pin = a
和pin++
是合法的,而a = pa
和a++
是错误的
地址算术运算
指针可以进行比较运算:指向同一个数组的指针可以进行
==
<=
>=
!=
等
同样指针可以进行与整数相加或相减运算,如p+n
其中n
的长度不是固定的,会随着指针等比例的缩放,减法也是相同的
指向同个数组的两个指针可以相减或者比较运算如p-q+1
代表两指针之间的元素个数
指针不可进行上述以外的其他运算,如两指针之间的相加运算、乘除运算等,同double或者float之间的加减运算,以及强制转换运算
字符指针和函数
字符串常量就是一个字符数组:"I am a string"
,在内部表示中字符和\0
组成
char amessage[] = "now is the time"; //定义一个数组
char *message = "now is the time"; //定义一个指针
对于第一种情况,定义了一个数组,其中amessage
指向这个字符数组的第一个字符,固定不变,数组中的单个字符可以进行修改。而对于第二种情况,message
指向一个字符串常量,只是将一个指向该字符串常量的指针赋值给了message
,并没有进行字符串的复制,只是涉及到指针的操作,C语言没有提供处理整个字符串的运算符。
指针数组以及指向指针的指针
指针数组和数组指针的区别,指针数组就是一个数组,而这个数组的每一个元素都是一个指针;数组指针是一个指针,而这个指针指向一个数组
int a[10];
int *p[10];
int (*p)[10] = &a; //数组指针的使用
a
和&a
的区别,对于a
数组名的值就是一个指针常量,也就是指向数组的第一个元素(代表第一个元素的地址),&a
指向的是整个数组,然而&a
和a
的值相同,不同的是&a+1
和a+1
代表的含义不同,&a+1
增加了整个数组的长度,a+1
增加了一个元素的长度(a[1]
)
多维数组
daytab[i][j]
表示一个二维数组,如果要将一个二维数组作为一个参数传递给函数,那么必须在函数声明中指明数组的列数(与数组的行数没有多大的关系)。怎么解释啦?向函数传递的是一个指针,这时就是传递的就是一个具有j
个元素的行向量,也就是前面所说的数组指针
可以从上面的多维数组可以得出:数组指针的每一行的长度相同。这也是和指针数组不同的地方,指针数组的每个指针指向的长度可以不一样
char *name[] = {
"illegal month", "January", "February", "March", "April", "May", "June", "July", "August", "September", "October", "November", "December"
}
上面定义的就是一个指针数组的初始化,每个元素的长度都不一样,name[0](或者name)
指向的就是第一个元素
命令行参数
在支持C语言的环境中,可以在程序开始时将命令行参数传递给程序。调用主函数main时,它带有两个参数,第一个参数(习惯为
argc
,用于参数计数)表示命令行中参数的数目,第二个参数(习惯为argv
,用于参数向量)是一个指向字符串数组的指针,其中每个字符串对应一个参数int main(int argc, char *argv[])
argv[0]
表示函数名,因此argc
的值至少为1,第一个可选参数为argv[1]
,最后一个可选参数为argv[argc - 1]