一、指针与地址
一元运算符&可用于取一个对象的地址
一元运算符*是间接寻址运算符。当它作用于指针时,将访问指针所指向的对象
实现指针指向的内容加1:(ptr)++ ,因为类似和++这样的一元运算符遵循从右至左的结合顺序。
二、指针与函数参数
c语言的函数参数是值传递,所以要修改原变量就要用到指针
三、指针与数组
通过数组下标所能完成的任何操作都可以通过指针完成,而且一般来说,用指针比用下标运行更快
int arr[10];
int *ptr;
如果ptr指向数组的某个特定元素比如赋值ptr = &arr[1]
,那么根据指针运算的定义,ptr+1将指向下一个元素,ptr+i将指向下i个元素,ptr-i将指向之前的第i个元素。无论数组的类型和长度是什么,上述结论都成立。
数组名就代表该数组第一个元素的地址。对数组元素arr[i]
的引用同样可以写成*(arr+i)
。
数组名虽然可以当作地址用,但数组名和指针有一个不同之处。即指针是变量,所以可以做赋值或自增等运算,而数组名不是变量,尝试向数组名赋值或自增数组名会报错。
四、字符指针与函数
"I am a string"
字符串常量在c语言内部是用字符数组存储的,而编译器会在这个字符数组的最后加上\0
标志字符串的结束。因此字符串常量占据的存储单元也因此比双引号内的字符数大1。
语句char *pmessage="Hello" 将一个指向字符串的指针赋值给pmessage,本质上只进行了指针的操作。
区分以下两条定义
char amessage[] = "Hello";
char *pmessage = "Hello!";
这两个定义有很大的差别,第一条声明了一个字符数组用以存放字符串和结尾的\0,数组中的字符可以修改,但根据3.4所述,amessage不能被赋值,即不能将amessage指向其他地方。但第二条,定义了一个指向字符的指针,让它指向一个字符串常量,所以在这里不能修改字符串的内容,但可以让这个字符指针pmessage指向其他地方。
而当这两种定义方式用在函数的形参时,又会有不一样的问题。
void fun(char* s);
void fun(char s[]);
这两种函数的定义方式其实没有任何区别。由于c语言的函数传参是值传递,所以不论fun函数的实参是数组名还是指针,最终传递的都是地址,所以不论形参的定义是char* s 还是char s[] ,s其实都是指针,所以两种定义方式没有区别。
运用所学的知识实现strcpy函数:
// strcpy: copy t to s
void strcpy(char *t, char *s) {
while((*s = *t) != '\0') {
s++;
t++;
}
}
简化版:
// strcpy: copy t to s; version 2
void strcpy(char *t, char *s) {
while(*s++ = *t++);
}
五、指针数组以及指向指针的指针
初始化一个字符指针数组,每个指针指向下标对应的月份的名字的字符串。
char* arr[] = {
"Illegal month", "January", "February", "March",
"April", "May", "June", "July", "August",
"September", "October", "November", "December"
};
六、指针与多维数组
区分多维数组与指针数组
有如下定义:
int a[10][20];
int* b[10];
从语法角度讲,a[3][4]
和b[3][4]
都是对一个int对象的合法引用。但a真真切切的分配了200个int的空间,而b只分配了10个指针的空间,如果b里的每个指针都指向一个20个元素的int数组,则a和b就几乎一样了。用指针数组完成多维数组的功能有一个好处,就是数组的每一行可以是长度不同的,就像第5节的月份字符数组一样,每一行都是不同长度的月份名字符数组。
七、命令行参数
main函数的完整声明如下:
int main(int argc, char const *argv[])
在支持c语言的环境中,可以在程序开始执行时将命令行参数传递给程序。调用主函数main时,它带有两个参数。第一个参数argc的值表示运行程序时命令行中参数的数目;第二个参数argv称为参数向量,它是一个指向字符指针的数组,其中每一个指针指向的字符串对应一个参数。
按照c语言的约定,argv[0]的值是启动该程序的程序名,因此argc的值至少为1。
八、Tips
const修饰指针
int const * ptr;
int * const ptr1;
两种情况,const在左边和const在右边。
当const在*左边时,表示不能通过ptr修改所指向变量的值。
当const在*右边时,表示ptr不能再指向其他变量。
const修饰二级指针
int a = 10;
int *ptr = &a;
int const * const * const ptrr = &ptr; // 二级指针的const
第一个const使得不能通过ptrr两次解引用改变a的值
第二个const使得不能通过ptrr一次解引用改变ptr的指向
第三个const使得ptrr不能再指向其他int*