1. 一维数组的数组名是指向数组第一个元素的指针常量,数组在定义时,已经在内存空间开辟了地址,所以数组名不能进行++操作
注意:一维整形(int)数组名在以下两种情况下不能被视作int *型——int a[5] = {1, 2, 3, 4, 5};
1. sizeof(a)中,a当作整个数组元素大小来计算所占字节数
2. &a,将a升级为指向整个数组的数组指针
2. 在一维字符型数组的定义和赋值中,除了数组的定义之外,对一维字符型数组名赋值字符串常量是不允许的——str = "how are you"; ——此表达式的含义是将字符串常量的地址赋值给数组的首地址,显然字符型数组的数组名也是指针常量,不能被修改。字符串常量存在于数据区,在程序编译时为其开辟空间,程序结束时回收空间,
#include <stdio.h>
int main(void)
{
char str[] = {"hello world"};
char *p = "hello world";
str = "how are you";
p = "how are you";
*str = 'H';
*p = 'H';
return 0;
}
3. 二级指针
3.1 定义
指向一级指针的指针,对二级指针取*后,二级指针降级为一级指针
3.2 使用到二级指针的情况
1. 通过函数传参来传递指针数组,指针数组的数组名是指向数组第一个指针的指针常量
2. 想要在主函数内部修改修改指针变量的值,需要传递二级指针,例子如下
#include <stdio.h>
int fun(char **pptmp)
{
*pptmp = "hello world";
return 0;
}
int main(void)
{
char *p = NULL;
fun(&p);
printf("p = %s\n", p);
return 0;
}
注意:下图与上文的代码做对比,下图中传入函数中的是一个指针值,当指针传入函数fun中被改变后,随着函数的结束,空间被回收,主函数中的指针p没有被修改
4. const指针(限制为只读,不能被修改)
const int *p
5. 数组指针
指向整个数组内存大小的指针
int (*p)[5] = NULL;
1. 对一维数组名取&, 指向一维数组首地址的指针升级成为指向整个数组的数组指针
2. 对数组指针取*,数组指针降级为指向数组首元素的指针
6. 指针数组
存放指针的数组,数组中的每个元素都是一个指针
int *p[5] = {NULL};
注意:存放字符串用二维字符型数组
操作字符串用指针数组
7. 二维数组
7.1 二维数组和指针的关系
二维数组的数组名是指向数组第一行所有元素的一个数组指针——char (*p)[32]
7.2 二维数组的传参(对函数)
传递数组名,即数组指针,函数用数组指针来接收
7.3 指针数组的传参(对函数)
传递数组名,即二级指针
8.指针函数和函数指针
8.1 指针函数——函数返回值为指针的函数(返回局部变量的地址为野指针,无效)
char *fun(char *pdst, const char *psrc)
#include <stdio.h>
char *fun(void)
{
char *p = "Hello World";
return p;
}
int main(void)
{
char *p = NULL;
p = fun();
printf("%s\n", p);
return 0;
}
8.2 函数指针——指向函数的指针
在C语言中,当你使用函数名时,它会被解释为该函数的地址,因此可以被隐式地转换为函数指针。这使得你可以像操作指针一样操作函数,比如将函数作为参数传递给其他函数,或者将函数指针赋值给其他指针变量等。函数名指向函数在内存空间中的首地址
int (*pfun)(int, int)
9. 对字符串操作的函数(传入的均是地址)
1. 输入输出
scanf("%s", str);
printf("%s\n", str);
gets(str);
puts(str);
2. 字符串操作函数
strlen、strcpy、strcat、strcmp
10. 结构体
10.1 结构体元素的访问
. 结构体变量类型访问成员变量
-> 结构体指针类型访问成员变量
注意:整体表达式的数据类型由成员变量的类型决定 .
10.2 结构体作为函数参数的传递
1. 结构体变量传递——值传递
void fun(struct student s)
2. 结构体指针传递——指针传递(能够在主函数外对结构体中数据进行修改)
void fun(struct student *ps)
10.3 结构体数组作为函数参数的传递
void fun(struct student *ps)