C++入门:指针和数组

1.单独指针

int main()
{

    cout<<"string:"<<endl;
    string s="Hello World!";
    string *cp0=&s;
    cout<<cp0<<endl;
    cout<<&cp0[0]<<endl;
    cout<<&cp0<<endl;
    cout<<*cp0<<endl;
    cout<<cp0[0]<<endl;
    return 0
}

int main()
{
    cout<<"int:"<<endl;
    int a=1;
    int *cp1=&a;
    cout<<cp1<<endl;
    cout<<&cp1[0]<<endl;
    cout<<&cp1<<endl;
    cout<<*cp1<<endl;
    cout<<cp1[0]<<endl;
    return 0;
}

2.int类型数组和指针

int main()
{
    cout<<"int array:"<<endl;
    int inum[]={1,2,3,4,5,6};
    int *cp2=inum;//相当于char * p = &inum[0]
    cout<<cp2<<endl;
    cout<<&cp2[0]<<endl;
    cout<<&cp2<<endl;
    cout<<*cp2<<endl;
    cout<<cp2[0]<<endl;
    return 0;
}

解释:

  1. int *cp2=inum;相当于int型指针cp2指向了数组的第一个元素,所以,打印出的cp2是第一个元素的地址;
  2. &cp2[0]与cp2等价;
  3. &cp2也仍然是个地址,在数值上也等于数组首元素首地址的值,但是其类型并不是数组首元素首地址类型,表示整个数组,也就是说int *cp2 = &inum是错误的,而且需要知道的是&inum的类型是int (*)[6],因此int (*cp2)[10] = &inum是正确的。
  4. *cp2通过解引用得到了数组的第一个元素;
  5. 只要指针指向的是数组中的元素(或者数组中尾元素的下一位置),都可以执行下标运算,cp2[0]等价于*(cp2+0),故为数组的第一个元素。

总结:在很多情况下,使用数组的名字其实用的是一个指向数组首元素的指针,一个典型的例子是当对数组使用下标运算时编译器会自动执行上述转换操作对数组执行下标运算实际上是对指向数组元素的指针执行下标运算。例如:

int i=inum[2];// inum则转换成指向数组首元素的指针,inum[2]得到(inum+2)所指的元素。

对于a+1,&a+1,&a[0]+1,sizeof(a),sizeof(&a),只要搞清楚指针的类型就可以迎刃而解。

  • 在面对a+1和&a+1的区别时,由于a表示数组首元素首地址,其类型为char *,因此a+1相当于数组首地址值+sizeof(char);而&a的类型为char (*)[3],代表整个数组,因此&a+1相当于数组首地址值+sizeof(a)
  • sizeof(a)代表整个数组大小,总结中第7条说明,但是无论数组大小如何,sizeof(&a)永远等于一个指针变量占用空间的大小,具体与系统平台有关。

3.char类型数组和指针

int main()
{
    cout<<"string:"<<endl;
    char *cp3="Hello World!";
    cout<<cp3<<endl;
    cout<<&cp3[0]<<endl;
    cout<<&cp3<<endl;
    cout<<*cp3<<endl;
    cout<<cp3[0]<<endl;
    return 0;
}

解释:

cp3被定义为指向“Hello World”的char型指针,“Hello World”是string类型,显然与char型不相吻合,可认为编译器做了以下事情:在常量区分配4个字节,分别放上H,e....d,\0这些字符,然后把H的地址返回给cp。(字符串放在了常量区,是不可修改的,试图修改,运行异常。为了兼容才允许这样写,最好写const char *cp3="Hello World",这样的话,试图修改cp的内容时,编译时就会报错。)

int main()
{
    cout<<"char array:"<<endl;
    char str[]={"Hello Word!"};
    char *cp4=str;
    cout<<cp4<<endl;
    cout<<&cp4[0]<<endl;
    cout<<&cp4<<endl;
    cout<<*cp4<<endl;
    cout<<cp4[0]<<endl;
    return 0;
}

解释:

char str[]={"Hello World"},相当于在栈顶分配了12个字节,分别放上H,e....d,\0这些字符,等价于char str[]={'H','e'....'d','\0'},但长度不包括\0。按道理cp0应该是输出的首元素的地址,等价于&cp0[0],但实际却输出整个字符串,这是由cout决定的,若要输出地址,则使用int强制转化为地址即可,即

cout<<(int)cp0<<endl;

4.多维数组和指针

当程序使用多维数组的名字时,也会自动将其转换成指向数组首元素的指针。因为多维数组实际上是数组的数组,所以由多维数组名转换得来的指针实际上是指向第一个内层数组的指针。

int ia[3][4];
int (*p)[4]=ia;//p指向含有四个整数的数组

如上图所示,我们可以将数组分成两个维度来看,首先是第一维,将a[3][2]看成一个具有三个元素的一维数组,元素分别为:a[0]、a[1]、a[2],其中,a[0]、a[1]、a[2]又分别是一个具有两个元素的一维数组(元素类型为char)。从第二个维度看,此处可以将a[0]、a[1]、a[2]看成自己代表”第二维”数组的数组名,以a[0]为例,a[0](数组名)代表的一维数组是一个具有两个char类型元素的数组,而a[0]是这个数组的数组名(代表数组首元素首地址),因此a[0]类型为char *,同理a[1]和a[2]类型都是char *。而a是第一维数组的数组名,代表首元素首地址,而首元素是一个具有两个char类型元素的一维数组,因此a就是一个指向具有两个char类型元素数组的数组指针,也就是char(*)[2]。

也就是说,如下的赋值是正确的:

char (*p)[2]  = a;//a为第一维数组的数组名,类型为char (*)[2]
char * p = a[0];//a[0]维第二维数组的数组名,类型为char *

同样,对a取地址操作代表整个数组的首地址,类型为数组类型(请允许我暂且这么称呼),也就是char (*)[3][2],所以如下赋值是正确的:  

char (*p)[3][2] = &a;

知识点总结:

  1. 实际上并不存在多维数组,所谓的多维数组本质上是用一维数组模拟的。
  2. 数组名是一个常量(意味着不允许对其进行赋值操作),其代表数组首元素的首地址。
  3. 数组与指针的关系是因为数组下标操作符[],比如,int a[3][2]相当于*(*(a+3)+2) 。
  4. 指针是一种变量,也具有类型,其占用内存空间大小和系统有关,一般32位系统下,sizeof(指针变量)=4。
  5. 指针可以进行加减算术运算,加减的基本单位是sizeof(指针所指向的数据类型)。
  6. 对数组的数组名进行取地址(&)操作,其类型为整个数组类型。
  7. 对数组的数组名进行sizeof运算符操作,其值为整个数组的大小(以字节为单位)。
  8. 数组作为函数形参时会退化为指针。
  9. []优先级高于*
int main(){
    
    //a) 一个整型数( An integer)
    int a;
    //b) 一个指向整型数的指针( A pointer to an integer)
    int *b;
    //c) 一个指向指针的的指针,它指向的指针是指向一个整型数( A pointer to a pointer to an integer)
    int **c;
    //d) 一个有 10 个整型数的数组( An array of 10 integers)
    int d[10];
    //e) 指针数组,一个有 10 个指针的数组,该指针是指向一个整型数的( An array of 10 pointers to integers)
    int *e[10]
    //f) 数组指针,一个指向有 10 个整型数数组的指针( A pointer to an array of 10 integers)
    int (*f)[10];
    //g) 函数指针,一个指向函数的指针,该函数有一个整型参数并返回一个整型数( A pointer to a functionthat takes an integer as an argument and returns an integer)
    int *g(int);
    //h) 指针函数,一个有 10 个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数( An array of ten pointers to functions that take an integer argument and return an integer 
    int (*h[10])(int);
    return 0;
}

这里写图片描述

这里写图片描述

    数组参数                 等效的指针参数

   一维数组 char a[30]     ==》            指针 char *a;

   指针数组 char *a[30]         ==》           指针 char **a;

二维数组 char a[10][30]     ==》     数组的指针 char (*a)[30];

 

数组和指针的区别:

  • 数组对应着一块内存区域,而指针是指向一块内存区域。
  • 用sizeof可以计算数组的容量(字节数),而无法计算指针所指内存的容量,用sizeof(p)得到的结果永远是4或者2(即指针变量所占内存单元的字节数)
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值