数组和指针(复习详解)

 数组指针和指针数组

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
}

评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值