zoukankan      html  css  js  c++  java
  • C++指针与数组

    对数组地址的理解,如

    int c[2] = {2,3};
    int(*cp)[2] = &c;
    cout << &c[0] << c << cp << endl;

    输出都是一样的。。结论:当对数组用&比如&c,那么意思就是“对数组取地址或者取得数组的地址”,而数组的地址返回的就是第一个元素的地址,加上数组名本身也是一个指针,故c与&c会有一样的结果。

    本版讨论很多对于C语言中指针和数组的认识和看法,
    下面是我自己对指针的一些粗浅认识,写的有点乱, 希望对新手有所帮助
    请大家批评指正。也欢迎大家积极讨论。

    1. 指针变量也只是普通的变量

    很多C语言的初学者都将指针变量看的很神秘,实际上,就像其他的普通变量(比如int类型的),指针变量也是一种普通变量,他具有其他变量的一切特征。

    例如:
    int main()
    {
    int q=10;
    int *pi=0;
    pi = &q;
    printf ("%d ", *pi);
    }

    main中声明并定义了一个自动变量p,他的类型是pointer-to-int.一旦定义了p,编译器就要给p分配内存空间。main结束后,p被自动释放。pi和q在这些方面没有丝毫不同。

    结论:指针变量没有那么神秘,指针变量只是一个普通变量

    2. 指针变量与其他变量的关系

    那么,指针的特殊性表现在什么地方呢?

    指针特殊就特殊在对他所存储的值的解释上和对他的使用上。

    在上例中,pi的值会被解释成内存中的一个地址,以这个地址开始的一块内存则表示一个int型的数.

    但是,即使在执行了pi = &q之后,pi和q也没有什么直接的关系:改变pi的值不会影响q,改变q的值也不会影响pi,他俩是两个独立的变量,有各自的存储空间。

    C语言赋予了指针特殊的本领就是:可以存储别的变量的内存地址,也可以利用指针变量本身的值去间接的操作别的变量.这两种能力是通过两个操作符来完成的 : &和*。

    pi = &q;                        //利用q的内存地址对pi进行赋值
    printf ("%d ", *pi);     //利用pi的值去间接的读q的值

    sizeof(pi)跟sizeof(q)根本就是两码事. pi不会自动根据自己去寻找q的,只有你显示的使用*pi才可以.

    结论:假设指针pi存储的是q的地址。pi和q没有任何直接的关系。只有*pi才和q有直接的关系。


    3. C语言中的函数参数传递方式

    很多人的另外一种误解是,C语言中有两种函数传递方式:按值传递和按地址传递。

    造成这种误解的原因就是对上面所说的两点理解的不够。

    void swap1( int a, int b)
    {
    int temp;
    temp = a;
    a = b;
    b = temp;
    }

    void swap2( int* pa, int* pb)
    {
    int temp;
    temp = *pa;
    *pa = *pb;
    *pb = temp;
    }

    int main()
    {
    int i=10, j=5;
    int *pi, *pj;
    pi = &i;
    pj = &j;
    swap1(i, j);
    printf("i=%d, j=%d ", i, j);
    swap2(pi, pj);
    printf("i=%d, j=%d ", i, j);
    }

    很多人会认为swap1是按值传递,而swap2是按指针传递。其实,C语言只有一种函数参数传递方式:按值传递。

    swap1大家都明白,我说一下swap2。

    实际上,我在第一点中已经指出,指针只是一个普通变量而已。在对swap2的调用swap2(pi, pj)中, pi和pj的值分别被copy到swap2中的pa和pb中。现在,i,pi和pa是3个完全不同的变量,但pi和pa的值相同,他们存的都是i的地址。在swap2中,利用*pa就可以读写i了,同样利用*pb就可以读写j了,所以swap2就可以完成i和j的交换了。但是,pi和pj的值通过swap2是无法改变的。

    也就是说, swap2使用的参数传递方式仍然是按值传递,只不过传递的是指针的值,然后利用指针有可以间接访问其他变量而已.

    结论:C语言只有一种函数参数传递方式:按值传递.

    4. 指针与数组

    4.1 数组名的类型

    在C语言中,指针与数组千丝万缕的联系.看下面的例子:

    int a[5];
    int b[3][5];
    int *pa1[5];
    int (*pa2)[5];

    那么a,b,pa1,pa2的类型到底是什么呢?

    很多人将a的类型误解成为一级指针,即const pointer to int,

    而将b的类型误解成为二级指针,即const pointer to the pointer to int;

    a不是const pointer to int类型的,我们是可以从下面这个事实推出来的:
    sizeof(a)跟sizeof(int*)是不同的.

    只能说,a是array of 5 ints类型的

    而b则是array of 3 arrays of 5 ints类型的

    这里之所以把pa1和pa2列出来,主要是给大家区别一下:
    pa1是array of 5 int pointers类型的,
    而pa2是pointer to array of 5 ints类型的

    4.2 数组名的运算

    大家经常会遇到关于数组名的运算问题,比如

    int a[5]={1, 2, 3, 4, 5};
    int b[3][5]={{1,2,3,4,5}, {6,7,8,9,10}, {11,12,13,14,15}};
    printf("%d", *(a+2));
    printf("%d, %d ", **(b+2), *(*b+2));


    在进行上面的运算时,有下面的似非而是的结论:

    &a可以看作是pointer to array of 5 ints类型的
    所以&a+1,这里的“1”是指5*sizeof(int)

    a是array of 5 ints类型的,但是a的值是什么呢?a的值其实是一个
    pointer to int

    *a的值则是一个int,即a[0];

    &b可以看作是pointer to array of 3 arrays of 5 ints类型的
    所以&b+1,这里的“1”是指3*5*sizeof(int)

    b是array of 3 arrays of 5 ints类型的,但是b的值却是一个
    pointer to array of 5 ints

    *b是array of 5 ints类型的,但是*b的值却是pointer to int类型的

    **b的值则是int类型的,即b[0][0];

    推而广之,则对于 int c[n1][n2]...[nm]的m维数组(m后面的数字为下标),有下面的结论(或者说计算方法):
    先将c扩展为int c[n1][n2]...[nm][1]; (最后一个是数字1,不是字母l)

    1.&c的单位“1”为n1*n2*...*nm*1*sizeof(int)
    sizeof(&c)等于存储一个指针的大小,其值与sizeof(int*)相同;

    2.令c1代表*...*c,共有i(0<i<=m-1)个*,则他的单位“1”为n(i+2)*...*nm*1*sizeof(int),其中(i+2)等是下标
    sizeof(c1)=n(i+1)*...*nm*sizeof(int)

    3.令c2代表*...*c,共有m个*,表示数组中第一个整数
    sizeof(c2)=sizeof(int)


    例如:int c[3][4][5][6];
    先转换成int c[3][4][5][6][1];
    &c+1相当于地址加3*4*5*6*1*sizeof(int), sizeof(&c)的值等于sizeof(int*);
    c+1相当于地址加4*5*6*1*sizeof(int), sizeof(c)=3*4*5*6*1*sizeof(int);
    **c+1相当于地址加6*sizeof(int), sizeof(**c)=5*6*1*sizeof(int);
    ****c就是数组中第一个整数

    4.3 一种常见错误

    int b[3][5];
    int **p=b;

    有些人误认为p+1的值和b+1是相同的,其实不然

    类似于

    T1 b1;
    T2* b2=(T2*)(&b1); //T1,T2为两种不同的类型

    这样的话,b2+1是按sizeof(T2)进行增加的
    而&b1+1是按照sizeof(T1)进行增加的
    指针进行类型转换后,其运算跟他自身的类型有关,而与他指向的东东无关
  • 相关阅读:
    交换函数作业
    对本课程的期望及对老师的建议
    前一半元素与后一半元素交换
    使用多线程(newSingleThreadScheduledExecutor)创建一个定时任务
    js判断是否为整数
    kafka入门及使用(不用集成spring)
    Eclipse 必须安装的几个插件
    mybatis 批量插入/批量修改的写法
    maven pom.xml中出现错误failOnMissingWebXml Dynamic Web Module 3.1 requires Java 1.7 or newer,每次update后都会回滚到1.5解决方案
    Eclipse 插件安装及相关问题解决方案(svn、spring、gradle、git)
  • 原文地址:https://www.cnblogs.com/bdbw2012/p/3978462.html
Copyright © 2011-2022 走看看