指针与数组(1)

说到C语言,指针绝对是c语言的压轴出场,是c语言的重头戏,也是C语言的精华所在,由于指针的存在,我们可以直接对内存空间操作,拿到某个变量的指针(得到它的地址),那么它那块空间就属于我的了,想干什么就干什么!!!!学习C和C++的同学肯定不会对指针感到陌生,这确实是个让我们又爱又恨的东西。

不曾忘记,因为指针操作引起的内存泄露、段错误而彻夜难眠;

也不曾忘记,因为指针的灵活和强大,让我们自由地游刃在内存之中。

就好像c++里由于虚函数的存在,出来一个虚表,那么只要拿到这个虚表的指针(虚表的地址就是该对象的首地址),那么对于父类和子类的无论私有还是保护的成员函数,我们都可以拿来用,因为我们已经越过了private或者protected的防盗网,直接进入了仓库,所以使得累的封装和安全性受到了威胁!所以指针确实是个很强大的东西,这是我的一点儿小体会,可能不太准确,见者海涵!下面来说说指针与一维数组!!!

指针:指针是一个装地址的变量;
内存地址:每一个字节都有唯一的标识符;
地址云算符:&变量名;
间接运算符:*地址;
注意:
1.不要对未初始化的指针操作;
2.对于堆内存分配的空间,在delete或者是free()后,一定要给指针赋空值;防止野指针的产生;

下面上一段代码示例:

#include <stdio.h>
int main()
{
	int a=10;
	int *p=&a;
	int **pp=&p;
	//pp是一个指针,指向的是一个int*(装的是一个指针的地址,该指针指向int);目的是为了能间接对a空间操作;
	//	(&pp)++; //地址不能++;=号左边要求是一个变量; 
	//p++;pp++; //因为p和pp都是变量,所以可以++;
	int *******************************p1;//这个编译都没有问题,p1是一个指针变量;
 	//其实还可以继续定义:
 	int  ***p2=&pp;
 	int ****p3=&p2;
	
	printf("%p\n",&a); //a的地址;
	printf("%p\n",&p); //指针变量p的地址;
	printf("%p\n",p);  //p指向的地址,指向的a的地址;p空间里存的是a的地址;
	printf("%d\n",*p); //p这个空间,里面装的是10;
	printf("%p\n",&pp); //二级指针变量的地址;
	printf("%p\n",pp);  //指向的是p的地址;
	printf("%p\n",*pp); //对p的空间的间接引用;执行读,取,写操作;
	printf("%d\n",**pp);//对p指向的空间,即a所在空间的间接引用,里面装的是10;
	return 0;
}

指针就是一个装着某种类型地址的变量;

注意:指针类型的+-,都是+-指针对应的字节数;
int *p=NULL;p++  +4;
double *p=NULL;p++  +8;

#include <stdio.h>
int main()
{
	int as[4]={1,2,3,4};
	double *p=(double *)as;
	p++;
	printf("%d\n",*p);//3
	return 0;
}

数组其实是一种比较特殊的数据类型,它所分配的内存空间是连续的,查找效率比较高,但是删除和插入较链表就显得比较笨拙低效;

上一段代码示例:

#include <stdio.h>
int main()
{
	int a[3]={11,22,33};
	printf("%p\n",&a);   //0012ff3c
	printf("%p\n",a);    //0012ff3c
	printf("%p\n",&a[0]);//0012ff3c
	/*
	a==&a
	a==&a[0]
	*a==a[0]   *(a+2)==a[3]==*(*(&a+1)-1)
	一定要注意类型的大小;
	*/

	printf("%d\n",sizeof(&a));  //12---内存地址;类型为4*sizeof(int )
	printf("%d\n",sizeof(a));	//12---内存空间名;
	printf("%d\n",sizeof(a[0]));//4
	
	printf("%d\n",*a);  //11
	printf("%d\n",*(a+2)); //33
	printf("%d\n",*(*(&a+1)-1)); //33
	return 0;
}

这里想着重说一下sizeof(&a)和sizeof(a);a是一维数组的名字

代码的实验大部分都是在VC6.0上实现的,由于个人习惯原因,虽然该编译器比较老,但是可能刚接触的就是它,习惯了吧!!!这样也导致了部分实验的结果可能因为编译器的不同而不同,若有错,欢迎指正,望海涵!

因为这两句话我思考了好久,也看了一些资料:

最后发现也许是VC6.0比较老的缘故,它的sizeof(&a),在VS2005上运行的时候结果是:4.而VC6上的结果是12;然后sizeof(a)都是12,没问题!

我们知道a=&a[0]是int *类型的;

&a是int *[n]类型的,n代表的是元素的个数;

因为我在VS2005上运行的结果如下:

#include <iostream>
using namespace std;
int main()
{
	int a[3]={1,2,3};
	int (*p)[3]=&a;
	cout<<**p<<endl;  //1
	cout<<*(*(p+1)-1)<<endl;//3
	cout<<*(*p+1)<<endl; //2
	cout<<*(*(&a+1)-1)<<endl;//3
	
	cout<<sizeof(&a)<<endl; //4
	cout<<sizeof(a)<<endl;  //12
	system("pause");
	return 0;
}
我看过陈正冲的《C语言深度解剖》,这本书还不错,里面第四章指针与数组讲到(*p)[N]=&a;那么p=&a;

sizeof(p)=sizeof(&a)就应该=4;就是一个地址而已,只要是地址,其大小就是4字节(32位)。

BUT

因为VC6中的sizeof(p)=4,sizeof(&a)=12;

可是在VS2005中sizeof(&a)=4,但是其类型还是int (*)[N],类型的,并不是int *类型的,因为上面的代码也有体现:

*(*(&a+1)-1)=*(*(p+1)-1)=3;

和VS6中的一样,这样看来,VS6中的sizeof(&a)又有它一定的道理,应该是整个数组的空间大小12而不是4!可能是因为数组名确实是个比较特殊的东西吧!

因为数组名本质上是个地址,但不能说是指针,它能给指针赋值,是因为,指针本身的数据结构和数组名(地址)是一样的 都是32位的int,所以这里能通过指针来对数组进行操作; 因为它本身是地址的属性,和指针就可以相互赋值,打通了友好往来的桥梁!!用起来也非常方便!


注意:地址不能++;

例如:

int a=10;

a++;//ok;

++a++;//error,a++是个常数11;不能再++了;


int as[3]={1,2,3};

as++;//error;地址不能++;

as=as+1;//error ,错误同上;

as+1;//OK..这个是可以的;它不是赋值,而是一个地址的移动;这是可以的!没有该变地址as的值,它的值是不允许改变的;


本人愚钝,领悟至此,颇有感慨,与己共勉,陋文浅显,见者海涵。












  • 6
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值