1. 字符型数组和字符串的传参
1.1 常量和变量的区别(难点)
一般常量不能被修改,变量才能被修改
#include <stdio.h>
int main(void)
{
char str[] = {"hello world"};//定义数组,数组名为指针常量
char *p = "hello world"; //给指针变量p赋值数据区的字符串常量
str = "how are you"; //错 首先,字符串常量默认char *型指针,数组名为指针常量,常量
不能被修改
p = "how are you"; //对 给指针变量p赋值字符串常量的首地址
*str = 'H'; //对 将数组第0个元素改为‘H’
*p = 'H'; //错 指针p指向了数组常量的首地址,*p想要改变常量,所以不能被修改
return 0;
}
#include <stdio.h>
int main(void)
{
char str[] = {"hello world"};//定义一个数组,初始化为hello world\0,数组名为指向数组第一个元素的首地址,数组名为一个常量(数组在定义时,空间已经被开辟好了,所以不能修改数组名)
char *p = "hello world";//定义一个指针,指针指向字符串常量的首地址,只能用字符串常量,不能修改字符串常量(字符串默认char *型)
str = "how are you";//错,(本质是常量赋值给常量,所以错误) 数组名为指向数组首地址的常量,不能被修改,字符串赋值要用strcpy
p = "how are you";//对,p为指针变量,变量能修改,将字符串的首地址赋值给指针p
*str = 'H';//对,将数组的第一个元素'h'修改为'H'
*p = 'H';//错,指针指向字符串常量的首地址,*p的含义是想要修改字符串常量,所以段错误
return 0;
}
1.2 字符串遍历
char str[32] = {"hello world"};
while (*str != '\0')
{
str++;
}
2. 二级指针
int **p;
指向一级指针变量的指针
3. void*指针
void *p —— 所有指针都是八个字节
用来保存地址
void * -> char * 、 double * 、 int * 低精度转高精度,不需要强制类型转换
char * 、 double * 、 int * -> void * 高精度转低精度,需要强制类型转换
注意:
void * 作为函数参数,可以传入char *、double *、int *的指针,实现一个函数原型下的不同类型指针的传参
4. const指针(限制指针为只读,不能被修改)
1. const int *p
2. int const *p
1和2等价,const修饰*p,*p不能改变,但p可以改变
只能使用指针指向的空间数据,但不能修改指向的数据
3. int *const p
1. const修饰p,p不能改变,*p可以改变
2. 一定要初始化,否则为野指针
3. 永远指向某个空间的指针(例如数组的数组名为指向数组首地址的指针常量)
4. const int *const p;
5. int const *const p;
1. const修饰p和*p,p和*p均不能改变
2. 一定要初始化
5. 数组指针和指针数组
5.1 数组指针
int (*p) [5] = NULL;
数组指针是指针,指向整个数组
若有:int a[5] = {1, 2, 3, 4, 5};
1. 对一维数组名取&(&a)中的地址值等价于a,但将a的类型升级为指向整个拥有20个字节空间大小的整形数组的数组指针
2. 对数组指针取* {*(&a)} 中的地址等价于a,但类型降级为指向数组第一个元素的指针
注意:在以下两种情况下,a不能理解为int *型变量
1.sizeof操作——a当作整个数组的大小来计算数组所占内存空间字节数
2.&操作
&int * == int **
&a == int (*)[5] 将a升级为数组指针,指向内存空间大小为20字节的首地址
5.2 指针数组
int *p [5] = {NULL};
指针数组是数组,数组中的每个元素都是指针
例:int *a[5]:定义一个指针数组,数组名为a,有5个元素,每个元素为int*型的指针
注意:
1. 存放字符串用二维数组
2. 操作字符串用指针数组