数组指针和指针数组
1 数组指针和指针数组的不同
2 &数组名和数组名的不同
3 指针数组的使用
4 检验
函数指针
const和指针
1 const在C和C++中
2 const修饰指针
2.1 const修饰指针指向内容
2.2 const修饰指针指向
sizeof和指针和数组
数组指针和指针数组
数组指针是指针!!!数组指针是指针!!!数组指针是指针!!!
指针数组是数组!!!指针数组是数组!!!指针数组是数组!!!
跟就最后的词来判断也可以,哈哈哈哈,只在文字上有用
下面就根据代码来判断吧
1 数组指针和指针数组的不同
int (*p)[10];
p和*首先结合,p就成了一个指针变量,指向一个大小是10个整形的数组,这个指针指向这个数组,叫数组指针,它的根本是指针,只是确定的指向是数组
注意:[ ]的优先级>*所以要加()保证p和*的先结合
指针数组
int *p[10];
[ ]优先级最高,首先就形成了一个存储10个未知类型的数组,然后我们再看,int * p,int *修饰p,表示 p 是一个指向整数的指针,最后int* p修饰了这个数组,表明这个数组是一个存放10个整形指针的数组
简单一点来说,可以看优先级来判断类型,优先级高的被其他来描述
2 &数组名和数组名的不同
#include <stdio.h>
int main()
{
int arr[10] = { 0 };
printf("arr = %p\n", arr);
printf("&arr= %p\n", &arr);
printf("arr+1 = %p\n", arr+1);
printf("&arr+1= %p\n", &arr+1);
return 0;
}
感兴趣的可以去运行一下这段代码
结果就是:arr和&arr取的地址相同,但各自+1后,arr增加4个字节,而&arr增加的是40跟子杰,就是这个数组的大小
解析:arr是数组首元素的地址,arr+1也是指针向后移动一位,&arr表示整个数组的地址,&arr+1是指针移动整个数组的大小,细心的人会发现了&arr就是一个数组指针,类型是int(*)[10]
3 指针数组的使用
纸上得来终觉浅,绝知此事要躬行
//void print_arr(int arr[3][5],int row,int col)
void print_arr(int (*arr)[5], int row, int col)
{
int i = 0;
for(i=0; i<row; i++)
{
for(int j=0; j<col; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
}
int main()
{
int arr[3][5] = {1,2,3,4,5,6,7,8,9,10};
print_arr(arr, 3, 5);
//数组名arr,表示首元素的地址
//但是二维数组的首元素是二维数组的第一行
//所以这里传递的arr,其实相当于第一行的地址,是一维数组的地址
//可以数组指针来接收
return 0;
}
这里的(*arr)是接收二维数组的第一行的地址,是一个一维数组地址,既然是数组的地址当然可以用数组指针来接收, int (*arr)[3],当然就效果来说,我注释那个传参是一样的也是
4 检验
int arr[5];
int *parr1[10];
int (*parr2)[10];
int (*parr3[10])[5];
存储了5个整形元素的整形数组
指针数组,存储了10个整形指针
数组指针,parr2是指针变量,指向了一个存储了10个整形元素的整形数组
*优先级<[ ],parr3首先是一个数组,*parr[10]是一个指针数组,包含了10个指针,每个指针被修饰,指向了存储了5个整形元素的整形数组,是每一个指针都指向,注意这里
函数指针
顾名思义了,存放函数地址的指针叫函数指针
先看一段代码,哪一个是函数指针
void (*pfun1)();
void *pfun2();
*pfun1先结合是指针,指针指向一个无参返回值为void的函数 ✓
一个叫pfun2的函数,无参,返回值是void* ×
再上点难度,这里的(int)表示函数必须一个接受int类型的参数
void (*signal(int , void(*)(int)))(int);
singnal()是一个函数接收两个参数,第一个参数类型是int,第二个参数类型是一个函数指针,这个函数接受一个int的参数,返回值void,singnal类型是void(*)int,哈哈哈,跟他的第二个参数一样的
还是太麻烦了看起来,所以可以简化一下代码
typedef void(*pfun_t)(int);
pfun_t signal(int, pfun_t);
后面还有什么函数指针数组,回调函数啊,了解就好,这里不论述了
const和指针
1 const在C和C++中
如果是C和C++都学了的朋友应该了解const在这两个语言中是有不同的
// C const
const int n = 10; // C语言中const修饰变量时,以变量为主,也就是说,const针对的是变量
int arr[n] = { 1,2 }; // C语言中此定义错误,因为其会认为n就是一个变量,虽然加了const修饰,仍然是变量,定义数组时数组大小是一个大于零的整形常量,
// 上述定义会出现类型错误,
// C++ const
const int n = 10; // C++在修饰变量的时候,是以“常性”为主
int arr[n] = { 1,2 }; // 在C++中此定义合法,会用整数值10取替换n,等价于:int arr[10] = { 1,2 };
这么说吧,被const修饰的变量叫常变量,变量不能再作为左值了,所以const修饰的变量无论C还是C++都必须初始化!但是在C当中,变量被强转取地址还是可以修改数据,但是,注意了,C++和C在编译上有不同C++中,所有出现const常量名字的地方,都被常量的初始化替换了!相当于#define n 10
2 const修饰指针
先要明确一写概念啊关于指针
int a=1;
int* b=&a;
b==&a *b==a *是解引用,应该都了解,const遵守就近原则
我们前面说啊C当中可以强转取地址来改变已经被const修饰了的变量的值,这不是违背初衷吗?会引发内存泄漏问题可能,所以为了安全,我们不能让数据被修改,还是const
2.1 const修饰指针指向内容
int a=10;
const int* p1=&a;
int const *p2=&a;
这两个const修饰的都是指针内容,因为是修饰的*p1和*p2
2.2 const修饰指针指向
int a=10;
int* const p=&a;
这个const修饰的就是p了,就是指针指向,保证p只能取a的地址
结合一下两个也可以,就是 const int* const p=&a; 就是既不能改变指针指向也不能改变指针指向内容
sizeof和指针和数组
这里大概就是计算字节数,我后面的sizeof计算是在x86下的
void Test1()
{
//数组名的理解
//数组名是数组首元素的地址
//但是有2个例外:
//1. sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小,单位是字节
//2. &数组名,这里的数组名表示整个数组,取出的是整个数组的地址
//一维数组
int a[] = { 1,2,3,4 };
printf("%d\n", sizeof(a));//4*4=16
printf("%d\n", sizeof(a + 0));//数组名a是首元素地址,a+0=a 4
printf("%d\n", sizeof(*a));//数组名a是首元素地址,*a是首元素 4
printf("%d\n", sizeof(a + 1));//数组名a是首元素地址,a+2是第二个元素地址 4
printf("%d\n", sizeof(a[1]));//第二个元素大小 4
printf("%d\n", sizeof(&a));//&a是数组地址 4
printf("%d\n", sizeof(*&a));//取地址后又解引用相当于a即整个数组 16
printf("%d\n", sizeof(&a + 1));//&a是数组地址 &a+1是跳过整个数组的地址的地址 4
printf("%d\n", sizeof(&a[0]));//首元素的地址 4
printf("%d\n", sizeof(&a[0] + 1));//第二个元素的地址 4
//字符数组
char arr[] = { 'a','b','c','d','e','f' };
printf("%d\n", sizeof(arr));//6个char类型的元素 6
printf("%d\n", sizeof(arr + 0));//首元素地址 4
printf("%d\n", sizeof(*arr));//首元素 1
printf("%d\n", sizeof(arr[1]));//第二个元素 1
printf("%d\n", sizeof(&arr));//整个数组地址 4
printf("%d\n", sizeof(&arr + 1));//跳过整个数组地址的地址 4
printf("%d\n", sizeof(&arr[0] + 1));//第二个元素地址 4
char arr2[] = "abcdef";
//[a b c d e f \0]
printf("%d\n", sizeof(arr2));//7个char类型的元素 7
printf("%d\n", sizeof(arr2 + 0));//首元素地址 4
printf("%d\n", sizeof(*arr2));//首元素 1
printf("%d\n", sizeof(arr2[1]));//第二个元素 1
printf("%d\n", sizeof(&arr2));//整个数组地址 4
printf("%d\n", sizeof(&arr2 + 1));//跳过整个数组地址的地址 4
printf("%d\n", sizeof(&arr2[0] + 1));//第二个元素地址 4
char* p = "abcdef";
printf("%d\n", sizeof(p));//p是一个指针变量 4
printf("%d\n", sizeof(p + 1));//p是一个指针变量+1是‘b’ 4
printf("%d\n", sizeof(*p));//*p 就是'a' 1
printf("%d\n", sizeof(p[0]));//p[0]--> *(p+0) --> *p 1
printf("%d\n", sizeof(&p));//char** 4
printf("%d\n", sizeof(&p + 1));//p[1]‘b’地址 4
printf("%d\n", sizeof(&p[0] + 1));//'b'地址 4/
//二维数组
int a2[3][4] = { 0 };
printf("%d\n", sizeof(a2));//3*4*4=48
printf("%d\n", sizeof(a2[0][0]));//大小 4
printf("%d\n", sizeof(a2[0]));//a[0]是第一行这个一维数组的数组名代表一维数组 16
printf("%d\n", sizeof(a2[0] + 1));//a[0]+1是第一行第二个元素的地址 4
printf("%d\n", sizeof(*(a2[0] + 1)));//计算的是就是第一行第2个元素的大小 4
printf("%d\n", sizeof(a2 + 1));//a是数组首元素的地址,是第一行的地址 int(*)[4]
//a+1 就是第二行的地址
printf("%d\n", sizeof(*(a2 + 1)));//*(a+1) 访问的第二行的数组 16
printf("%d\n", sizeof(&a2[0] + 1));//&a[0]+1 是第二行的地址 int(*)[4] 4
printf("%d\n", sizeof(*(&a2[0] + 1)));//16 计算的是第二行的大小
printf("%d\n", sizeof(*a2));//计算的是第一行的大小-16
printf("%d\n", sizeof(a2[3]));//a[3]--> int [4] 16
}