数组和指针

18 篇文章 0 订阅

一.数组和指针
int arr[5];
int *p;
首先要搞清楚数组是什么?数组表示相同数据类型的数的集合,arr[5]表示有5个整形元素的集合。
p是变量,对于变量可以理解为左值,编译器会开辟一块内存空间,然后在这个空间存上其所指的内容。
*表示解应用。可以形象理解为:如果你回家开门,需要钥匙打开,此时”*“就充当钥匙的功能,同样在指针中有了*,才会读取其所指向地址的内容。
数组在表达式中使用时,编译器会为其产生一个指针常量,指针常量所指向的是数组起始出的地址,只有在数组名作为sizeof和&的操作数时,才不会被认为是指针常量,如sizeof(arr)表示的是数组的长度,而不是指针的长度。
二.
int *p;
*p =NULL;
第一行代码这里可以理解为定义了一个指针变量p;其指向的内存里保存了整形int的数据。而p本身的值我们无从得知;p可能是一个非法地址,第二行代码理解为,给*p赋值为NULL;其所指向的内存赋值为NULL;但是由于所指向的内存可能非法,系统会出现内存访问错误。
指针怎么访问数据呢?
如:
int *p;
int a =10;
p = &a;
这里理解为定义一个指针变量p,编译器并为这个变量开辟一块内存,用来存放其所指的内容是&a。
 三.数组
int a[5]
定义数组时,编译器会根据其元素的类型和个数为分配空间。如上例,定义整形数组a,为其开辟20字节的空间,存放其数据元素,如:a[0],a[1];四.a和&a的区别
int main()
{
int a[5] = { 1, 2, 3, 4, 5 };
printf("%d\n", sizeof(a));
printf("%d\n", sizeof(a + 0));
printf("%d\n", sizeof(*a));
printf("%d\n", sizeof(a + 1));
printf("%d\n", sizeof(a[1]));
printf("%d\n", sizeof(&a));
printf("%d\n", sizeof(&a + 1));
printf("%d\n", sizeof(&a[0]));
printf("%d\n", sizeof(&a[0] + 1));
printf("%d\n", sizeof(*&a));
system("pause");
return 0;
}
结果是多少呢?
a表示取整个数组的地址,而&a表示首元素的首地址相当于&a[0],*a对数组进行解应用退化为指针,其表示指向数组的首地址:取&a+1表示指向当前元素的下一个元素的首地址,而*&a表示先取整个数组的地址,然后对其解应用读取其地址的内容。
1.a+1表示指向下一个数组的首地址

2.&a+1表示指向下一个数组的首地址,我们可以理解为取首元素的地址,然后加上1表示移动的长度,指向下一个地址,可以理解为&a[1]
五.左值和右值
首先弄明白左值的概念一般是赋值符=左边的值,表示空间,右值是赋值符=的值一般表示内容。
数组a 作为左值是非法的,编译器会认为数组名a表示首元素的首地址,a作为右值与&a相同表示首元素的首地址。
int a[5]
六.数组和指针的关系?
他们的关系?事实上是没有任何关系的,数组是数组,指针是指针。他们是两个不同的概念,只是他们的访问元素的方式比较类似而已。那么问题来了?他们是怎样访问元素的?
数组访问是“具名+匿名”的形式。具名表示数组名a已知,可以通过“指针”的形式访问其某个元素,如*(a+3),此时a表示的是数组的首地址,3表示长度选择,结果是只想要访问元素的地址,即为&a[3]也可以通过“下标”索引的方式方式访问某个元素,如a[i],但其本质都是通过数组的首地址加上i*(a+1)作为真正的地址;
指针访问是“匿名”,先取出p里存储的首地址值,加上偏移量(i*sizeof),得到正真的地址。确切的说数组访问和指针访问都是以指针的访问元素。如下:
int main()
{
int a[5] = { 1, 2, 3, 4, 5 };
int *ptr = (int *)(&a + 1);
printf("%d,%d", *(a + 1), *(ptr - 1));
system("pause");
return 0;
}
*(a+1)根据前面的理解,表示先取其首元素的首地址&a[0],然后加上偏移量,得到下一个元素的地址即为&a[1]值为2,&a+1表示取下一次数组得到首地址,&a表示数组的地址,此时+1表示下一个数组。*(p-1)表示访问&a[5]值为5我们在用图分析下
六.数组指针和指针数组
int *p1[5];
int(*p2)[5];
p1和p2各是什么呢?
p1是指针数组,首先它是一个数组,不过数组里元素都是指针,表示储存指针的数组。
p2是数组指针,它还是一个指针,不过指针指向了一个数组,表示为指向数组的指针。
当然有很多人还是弄不清楚,我们可以从操作符的优先级来判断,()的优先级高于 []的优先级高于 *。这样就可以很好的判断了。
七.二维数组,二级指针
二维数组还是数组,可以看成一个一维数组,不过里面元素也是一维数组。
如arr[3][3]
这样访问二维数组的某个元素可以按照一维数组的方法来访问
int main()
{
        int arr[2][5] = { 1, 2, 3, 4, 5, 6, 7, 8, 9, 10 };
        int *ptr1 = (int *)(&arr + 1);
        int *ptr2 = (int *)(*(arr + 1));
        printf("%d,%d", *(ptr1 - 1), *(ptr2 - 1));
        system("pause");
        return 0;
}
首先弄明白&arr+1表示整个二维数组的下一个数组的首地址,*(arr+1)指向数组元素的下一个元素(一维数组)的首地址相当于&[6]值6。这样就可以很容易得到*(ptr1-1)和*(ptr2-2)的值了。
二级指针,还是指针,我们可以看成一级指针,不过它指向的还是一个一级指针如:
nt a =10;
int *b = &a;
int c = &b
此时c表示的是一个二级指针。
八.函数指针
可以理解为指针,不过指针所指向的是一个函数。如:
char *fun(char *p1,char *p2);
表示为参数类型为char *的变量p1,p2,fun表示函数,char *为其返回值的类型。
函数指针的使用:
int*swap(int*a, int*b)
{
        *a ^= *b;
        *b ^= *a;
        *a ^= *b;
}
int main()
{
        int (*p)(int, int);
        int a = 10;
        int b = 20;
        p = &swap;
        (*p)(&a, &b);
        printf("%d\n%d\n",a, b);
        system("pause");
        return 0;
}
九.函数指针数组
它实际就是一个数组,不过它里面的元素是函数指针;
char*(*pf[5]])(char*p)
它表示的是函数指针数组,数组名为pf,数组内存储5个指向函数的指针。函数返回值类型为指向字符的指针。
( * (  void ( * ) ( ) )  0 ) ( )
怎么理解呢?
可以从里到外来分析,
先分析void (*)()是一个函数指针,没有参数,返回值的类型为空。
其次分析:(void(*)())0表示对0按照函数指针类型实行强制转换。
( * ( void ( * ) ( ) ) 0 )解应用读取0地址里面的内容。
( * ( void ( * ) ( ) ) 0 ) ( )最后对这个函数进行调用。
当然可能由于理解的不够,有错误的还请小伙伴指出。微笑











  • 0
    点赞
  • 3
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值