牛骨文教育服务平台(让学习变的简单)
博文笔记

关于C++中sizeof()、数组长度和函数传参的一点心得

创建时间:2014-04-13 投稿人: 浏览次数:143

        以前上C++课程的时候老师曾经解释过C++中数组名的意义:一般来说数组名可以看作是这个数组第一个元素的地址。然后后来便一直以为数组名和指针并没有任何不同。直到昨天做了一些题目,才发现其中仍有一些端倪,所以后来上网查了资料,自己也做了一下实验,才把其中的一些差别之处真正弄明白。

        先来看看下面这一小段代码:

int main()
{
    int a[5];
    int *b = new int[5];
    cout<<sizeof(a)<<" "<<sizeof(&a)<<" "<<sizeof(b)<<endl;

    delete b;

    return 0;
}
        输出结果很容易猜到:

20 8 8
        (我的机子是64位系统的,所以指针的大小都是8Byte)

        从sizeof(&a) 我们可以知道,a确实是指向数组首地址的int类型指针,但是对于这种静态数组,sizeof返回的是整个数组的长度,而不是a的大小。对比之下,b就是单纯的指向动态数组的首地址的int指针了,而且sizeof(b)只能获得指针大小,没有办法获得整个数组的大小。如果想要返回数组的大小,需要把数组封装一下,加入长度变量记录才行。

        这样看来,对于sizeof()函数来说,静态数组名和一般的变量指针还是有一点区别的。然而,如果要把一个数组当作参数传入函数中时,又有一些特别的注意事项。再看看一下代码:

void getLength(int arr[5])
{
    cout<<sizeof(arr)<<endl;
}

int main()
{
    int a[5];
    getLength(a);

    return 0;
}
        程序输出:
8

        原因很简单,在函数传参中数组都是以传指针的形式传入函数的,并不会出现传值调用。在函数形参中,int arr[5] 会退化成 int *,那个5就丢失了,所以getLength函数中arr实际上只是单纯的数组a的首地址。也就是说,形参列表中写int arr[5], int arr[] , int *arr 效果都是一样的。但是如果要想同时传入数组的指针和数组的大小,一般可以有两种做法:

        1. 把数组长度作为函数的另一个形参:

void getLength(int arr[], int num);
        2. 使用引用
void getLength(int (&arr)[5]);
        这种方法中数组的长度就能传进函数了。但是使用这种方法的时候,如果外部函数传进来的数组长度不是5,编译器会报错。

        既然讲到了数组引用,我又看到一个关键的点,想拿出来和大家一同分享:对于数组 a[5]来说,a和&a是有不同的含义的。再看看下面的代码:

int main()
{
    int a[4] = {1,2,3,4};
    int * a_ptr =  (int *)(&a +1);
    cout<< *(a+1) << " "<<  *(a_ptr-1) <<endl;

    return 0;
}
        输出结果:
2 4
        原因是这样:a在这里仍然是静态数组 {1,2,3,4}的首个元素的地址,所以*(a+1)就是把a移动到下一个元素,解引用后输出,很好理解;然而&a代表的是整个长度为4个元素的数组。所以 &a +1 并不是单纯地移动到下一个元素,而是根据数组的长度移动数组长度个单位,即此时 &a +1指向的是4后面的元素(溢出),所以最后 *(a_ptr-1)输出的就是最后一个元素4了。

        匆忙之中,写下一些心得记录,使自己能铭记于心。        



声明:该文观点仅代表作者本人,牛骨文系教育信息发布平台,牛骨文仅提供信息存储空间服务。