指针和数组,const int *,sizeof,优先级等的一些坑

指针和数组

先瞅一段code
    char *aa="adbs";
    char *bb="adbs";
    char *cc="adbss";
    cout<<"aa addr: "<<static_cast<const void *>(aa)<<endl;
    cout<<"&aa addr: "<<static_cast<const void *>(&aa)<<endl;
    cout<<"bb addr: "<<static_cast<const void *>(bb)<<endl;
    cout<<"&bb addr: "<<static_cast<const void *>(&bb)<<endl;
    char dd[10]="adbs";
    cout<<"dd addr: "<<static_cast<const void*>(&dd)<<endl;
    cout<<"&dd addr: "<<static_cast<const void*>(dd)<<endl;
    输出如下:
    -- aa addr: 0x40149c
    -- &aa addr: 0x7fff037fe3d0
    -- bb addr: 0x40149c
    -- &bb addr: 0x7fff037fe3c8
    -- dd addr: 0x7fff037fe3b0
    -- &dd addr: 0x7fff037fe3b0
    首先指针的地址和指针指向的地址是不同的,指针是个变量,自身需要占据存储单元,指针的地址就是存放该指针的内存单元所在的地址值,那么在这个内存单元里存的值就是该指针指向的对象所在的地址。
    C++对于同样的字符串值,在栈中只存储一份,所以aa,bb指向的字符串是相同的,该字符串在栈中只存在一份,所以aa和bb 存放的地址是一样的。
    指针和数组的一点区别在于,数组自身的地址就是数组中首元素的地址。

const 的一些坑

const是修饰符,const 指向的常量并不是真正意义的常量
1const int *a
    a 指向一个常量,因此不能通过*a来改变a所指向的对象值。但是a本身可以被赋值。
    const int *a = 0;
    const int b = 1;
    int c = 1;
    a = &b //ok! 注意不能通过a来修改b的值
    a = &c //ok! c本身可以不是一个常量
    *a = 2 //error! 不能通过修改*a来修改c的值
    int *d=&b;
    *d=2;
    printf("%d\n",b);//print 2 ,此时b的值将被改成了2
2int *const a
const 修饰啊,a是个常量,同时a的类型是个指针,并且指针指向一个int,因此a是个指向int的常量指针。
    int m=1,n=2;
    int * const a=&m;
    m=10//ok
    printf("%d\n",*a);//print 10
    a=&n;//error,a是个常量

3int const *a 和 const int *a一个意思 
4const int * const a 
a所指向的对象的值以及它的地址本身都不能被改变

关于const的点滴补充:
1const 对象的地址只能赋值给指向const 对象的指针
2、指向const 对象的指针可以 被赋 以 一个非const 对象的地址 
3、指向const 的指针常被用作函数的形式参数,保证被传递给函数的实际对象在函数得实际对象在函数中不会被修改
4、常量在定义后就不能被修改,所以它必须被初始化。未初始化的常量定义将导致编译错误(上面都是在说明const得问题,所以没有赋值,实际语句中要赋值的)

sizeof 的一些坑

char *s="1234";
    char t[10]="123456";
    printf("%d %d %d %d\n",sizeof(*s),sizeof(s),strlen(s),sizeof(t));//1 8 4 10
    int *sss=&a;
    int q=10 *sizeof(*sss);
    int q2=10 *sizeof(sss);
    int mm=sizeof(int)*q;
    printf("%d %d  %d\n",q,q2,mm);//40 80 160

指针数组和数组指针的一些坑


--------------指针数组(首先是个数组)--------------------
int *p[10];//指针数组,含有10个指针元素 
也就是说每一个元素都是指针。先是解析[]表示它是一个数组,然后*表示指针,int表示为int型指针,即表示定义一个指针数组,含有10int类型指针元素。
--------------数组指针(首先是个指针)--------------------
int (*p)[10];//数组指针,这个指针能够用来指向含有10个元素的整数数组。
先是解析(),括号里表示这个是个指针,然后[]表示数组,即表示定义了一个指向数组的指针。数组指针。

声明和定义的一些坑

同一变量定义只有一个,但是可以声明多次
int a; 是个声明 也是个定义
extern int a; 只是声明
有足够的信息让编译器建立变量的声明 就是一个定义
extern int a=10//error

优先级的一些坑

1、.的优先级高于*
    *p.f 对p 取f 偏移,作为指针,然后进行解除引用操作 ,相当于*(p.f)
2、[] 的优先级高于*
    int *ap[]   代表ap是个元素为int指针的数组相当于int*(ap[]),而不是指向int数组的指针(int(*ap)[])。 
3、函数()的优先级高于*
    int*fp() fp是个函数,返回int* 相当于int*(fp())
    int(*fp)() fp是个指针,指向的函数返回int
4、==和!=高于位运算符
    (val & mask !=0) 实际上是(val & (mask!=0))
5、== 高于赋值符号
    c=getchar()!=EOF 相当于 c=(getchar()!=EOF)
6、算数运算符高于移位运算符
    msb<<4+lsb相当于 msb<<(4+lsb)
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
指针数组数组指针的区别 数组指针(也称行指针) 定义 int (*p)[n]; ()优先级高,首先说明p是一个指针,指向一个整型的一维数组,这个一维数组的长度是n,也可以说是p的步长。也就是说执行p+1时,p要跨过n个整型数据的长度。 如要将二维数组赋给一指针,应这样赋值: int a[3][4]; int (*p)[4]; //该语句是定义一个数组指针,指向含4个元素的一维数组。 p=a; //将该二维数组的首地址赋给p,也就是a[0]或&a[0][0] p++; //该语句执行过后,也就是p=p+1;p跨过行a[0][]指向了行a[1][] 所以数组指针也称指向一维数组指针,亦称行指针指针数组 定义 int *p[n]; []优先级高,先与p结合成为一个数组,再由int*说明这是一个整型指针数组,它有n个指针类型的数组元素。这里执行p+1是错误的,这样赋值也是错误的:p=a;因为p是个不可知的表示,只存在p[0]、p[1]、p[2]...p[n-1],而且它们分别是指针变量可以用来存放变量地址。但可以这样 *p=a; 这里*p表示指针数组第一个元素的值,a的首地址的值。 如要将二维数组赋给一指针数组: int *p[3]; int a[3][4]; for(i=0;i<3;i++) p[i]=a[i]; 这里int *p[3] 表示一个一维数组内存放着三个指针变量,分别是p[0]、p[1]、p[2] 所以要分别赋值。 这样两者的区别就豁然开朗了,数组指针只是一个指针变量,似乎是C语言里专门用来指向二维数组的,它占有内存中一个指针的存储空间。指针数组是多个指针变量,以数组形式存在内存当中,占有多个指针的存储空间。 还需要说明的一点就是,同时用来指向二维数组时,其引用和用数组名引用都是一样的。 比如要表示数组中i行j列一个元素: *(p[i]+j)、*(*(p+i)+j)、(*(p+i))[j]、p[i][j] 就指向指针指针,很早以前在说指针的时候说过,但后来发现很多人还是比较难以理解,这一次我们再次仔细说一说指向指针指针。  先看下面的代码,注意看代码中的注解: #include <iostream>  #include <string>  using namespace std;    void print_char(char* array[],int len);//函数原形声明    void main(void)    {  //-----------------------------段1-----------------------------------------      char *a[]={"abc","cde","fgh"};//字符指针数组      char* *b=a;//定义一个指向指针指针,并赋予指针数组首地址所指向的第一个字符串的地址也就是abc\0字符串的首地址      cout<<*b<<"|"<<*(b+1)<<"|"<<*(b+2)<<endl;  //-------------------------------------------------------------------------    //-----------------------------段2-----------------------------------------      char* test[]={"abc","cde","fgh"};//注意这里是引号,表示是字符串,以后的地址每加1就是加4位(在32位系统上)      int num=sizeof(test)/sizeof(char*);//计算字符串个数      print_char(test,num);      cin.get();  //-------------------------------------------------------------------------  }    void print_char(char* array[],int len)//当调用的时候传递进来的不是数组,而是字符指针他每加1也就是加上sizeof(char*)的长度  {      for(int i=0;i<len;i++)      {          cout<<*array++<<endl;      }  }   下面我们来仔细说明一下字符指针数组和指向指针指针,段1中的程序是下面的样子: char *a[]={"abc","cde","fgh"};  char* *b=a;  cout<<*b<<"|"<<*(b+1)<<"|"<<*(b+2)<<endl;   char *a[]定义了一个指针数组,注意不是char[], char[]是不能同时初始化为三个字符的,定义以后的a[]其实内部有三个内存位置,分别存储了abc\0,cde\0,fgh\0,三个字符串的起始地址,而这三个位置的内存地址却不是这三个字符串的起始地址,在这个例子中a[]是存储在栈空间内的,而三个字符串却是存储在静态内存空间内的const区域中的,接下去我们看到了char* *b=a;这里是定义了一个指向指针指针,如果你写成char *b=a;那么是错误的,因为编译器会返回一个无法将char* *[3]转换给char *的错误,b=a的赋值,实际上是把a的首地址赋给了b,由于b是一个指向指针指针,程序的输出cout<<*b<<"|"<<*(b+1)<<"|"<<*(b+2)<<endl;   结果是 abc cde fgh   可以看出每一次内存地址的+1操作事实上是一次加sizeof(char*)的操作,我们在32位的系统中sizeof(char*)的长度是4,所以每加1也就是+4,实际上是*a[]内部三个位置的+1,所以*(b+1)的结果自然就是cde了,我们这时候可能会问,为什么输出是cde而不是c一个呢?答案是这样的,在c++中,输出字符指针就是输出字符串,程序会自动在遇到\0后停止.   我们最后分析一下段2中的代码,段2中我们调用了print_array()这个函数,这个函数中形式参数是char *array[]和代码中的char *test[]一样,同为字符指针,当你把参数传递过来的时候,事实上不是把数组内容传递过来,test的首地址传递了进来,由于array是指针,所以在内存中它在栈区,具有变量一样的性质,可以为左值,所以我们输出写成了,cout<<*array++<<endl;当然我们也可以改写为cout<<array[i]<<endl,这里在循环中的每次加1操作和段1代码总的道理是一样的,注意看下面的图!   到这里这两个非常重要的知识点我们都说完了,说归说,要想透彻理解希望读者多动手,多观察,熟能生巧。   下面是内存结构示意图:

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值