数组名和指针的深入理解(C++)

指针是C/C++语言的特色,而数组名与指针有太多的相似,甚至很多时候,数组名可以作为指针使用。于是乎,很多程序设计者就被搞糊涂了。

魔幻数组名

请看程序(本文程序在WIN32平台下编译):

#include <iostream>
using namespace std;

int main()
{
    char str[10];
    char* pStr = str;
    cout << "sizeof(str): \t" << sizeof(str) << endl;
    cout << "sizeof(pStr): \t" << sizeof(pStr) << endl;

    system("pause");
    return 0;
} 

1、数组名不是指针

我们先来推翻"数组名就是指针"的说法,用反证法。

证明 数组名不是指针

假设:数组名是指针;

则:pStr和str都是指针;

因为:在WIN32平台下,指针长度为4;

所以:sizeof(str)和sizeof(pStr)的输出都应该为4;

实际情况是:

所以:假设不成立,数组名不是指针

2、数组名神似指针

上面我们已经证明了数组名的确不是指针,但是我们再看看程序的这一:char* pStr = str;。该行程序将数组名直接赋值给指针,这显得数组名又的确是个指针!

我们还可以发现数组名显得像指针的例子:

#include <iostream>
using std::cout;
using std::endl;

int main()
{
    char str1[10] = "I love U.";
    char str2[10];

    strcpy(str2, str1);

    cout << "string array 1: " << str1 << endl;
    cout << "string array 2: " << str2 << endl;

    system("pause");
    return 0;
}

标准C库函数strcpy的函数原形中能接纳的两个参数都为char型指针,而我们在调用中传给它的却是两个数组名!

函数输出:

数组名再一次显得像指针!

既然数组名不是指针,而为什么到处都把数组名当指针用?

揭密数组名

现在到揭露数组名本质的时候了,先给出三个结论:

(1)数组名的内涵在于其指代实体是一种数据结构,这种数据结构就是数组;

(2)数组名的外延在于其可以转换为指向其指代实体的指针,而且是一个指针常量;

(3)指向数组的指针则是另外一种变量类型(在WIN32平台下,长度为4),仅仅意味着数组的存放地址!

1、数组名指代一种数据结构:数组

现在可以解释为什么第1个程序的这一行:sizeof(str);的输出为10的问题,根据结论1,数组名str的内涵为一种数据结构,即一个长度为10的char型数组,所以sizeof(str)的结果为这个数据结构占据的内存大小:10字节。

再看:

1. int intArray[10];
2. cout << sizeof(intArray) ;

第2行的输出结果为40(整型数组占据的内存空间大小)。

如果C/C++程序可以这样写:

1. int[10] intArray;
2. cout << sizeof(intArray) ;

我们就都明白了,intArray定义为int[10]这种数据结构的一个实例,可惜啊,C/C++目前并不支持这种定义方式。

2、数组名可作为指针常量

根据结论2,数组名可以转换为指向其指代实体的指针,所以程序1中的第5行数组名直接赋值给指针,程序2第7行直接将数组名作为指针形参都可成立。

下面的程序成立吗?

1. int intArray[10];
2. intArray++;

读者可以编译之,发现编译出错。原因在于,虽然数组名可以转换为指向其指代实体的指针,但是它只能被看作一个指针常量,不能被修改。

而指针,不管是指向结构体、数组还是基本数据类型的指针,都不包含原始数据结构的内涵,在WIN32平台下,sizeof操作的结果都是4。
顺 便纠正一下许多程序员的另一个误解。许多程序员以为sizeof是一个函数,而实际上,它是一个操作符,不过其使用方式看起来的确太像一个函数了。语句 sizeof(int)就可以说明sizeof的确不是一个函数,因为函数接纳形参(一个变量),世界上没有一个C/C++函数接纳一个数据类型(如 int)为"形参"。

3、数组名可能失去其数据结构内涵

到这里似乎数组名魔幻问题已经宣告圆满解决,但是平静的湖面上却再次掀起波浪。请看下面一段程序:

#include <iostream>
using std::cout;
using std::endl;

void arrayTest(char str[])
{
     cout << "sizeof(str):" << sizeof(str) << endl;
}

int main()
{
    char str1[10] = "I love U.";
    arrayTest(str1);

    system("pause");
    return 0;
}

程序的输出结果为:

一个可怕的数字,前面已经提到其为指针的长度!

结论1指出,数组名内涵为数组这种数据结构,在arrayTest函数体内,str1是数组名,那为什么sizeof的结果却是指针的长度?这是因为:

(1)数组名作为函数形参时,在函数体内,其失去了本身的内涵,仅仅只是一个指针;

(2)很遗憾,在失去其内涵的同时,它还失去了其常量特性,可以作自增、自减等操作,可以被修改。

所以,数组名作为函数形参时,其全面沦落为一个普通指针!它的贵族身份被剥夺,成了一个地地道道的只拥有4个字节的平民。

以上就是结论4。

时间: 2024-12-18 21:55:15

数组名和指针的深入理解(C++)的相关文章

对于C语言中数组名是指针的理解

我们都知道,c语言中数组名是一个指针,比如下面这段代码 #include<iostream>using namespace std;int main(){ int a[4]={1,2,3,4}; for(int i=0;i<4;i++) {  cout<<*(a+i);//*(a+i)和a[i]是等价的.  cout<<endl; } return 0;} 但是看下面这个代码 #include<iostream>using namespace std;

C 语言中的左值和右值。以及对比数组名和指针取数组元素的区别。

左值:出现在赋值符左边的符号有时称为左值. 右值:出现在赋值符右边的符号有时称为右值. 编译器为每个变量分配一个地址(左值),这个地址在编译时可知,而且该变量在运行时一直保存于这个地址.相反,存储于变量中的值(它的右值)只有在运行时才可知.如果需要用到变量中存储的值,编译器就发出指令从指定地址读入变量值并将它存于寄存器. 可以看到,每个符号的地址在编译时可知. 对比一下几个式子: //常规变量 int a=1;//这里a作为左值出现,代表的是地址,即在a表示的这个内存地址存入数值1.即a代表的内

C语言,数组名,指针常量和常量指针

自己给自己劝退一波~ 先介绍指针常量和常量指针 const int *p; //这是个指针常量 int const* p; //这是个常量指针 const是常量修饰符,被修饰的就是一个常量,常量的特性就是不能改变. 先介绍指针常量, const int *p; int i=2; p=&i; 这里*p就是一个常量,他的值不能改变,也就是不能再通过*p=1; 这样赋值而去改变 i 的值,但可以通过直接i=1;这样改变i的值,此时*p的值也相应变为了1 int const* p=NULL; int i

c/c++数组名和指针区别深入探索

指针是C/C++语言的特色,而数组名与指针有太多的相似,甚至很多时候,数组名可以作为指针使用.于是乎,很多程序设计者就被搞糊涂了.而许多的大学老师,他们在C语言的教学过程中也错误得给学生讲解:"数组名就是指针".很幸运,我的大学老师就是其中之一.时至今日,我日复一日地进行着C/C++项目的开发,而身边还一直充满这样的程序员,他们保留着"数组名就是指针"的误解. 想必这种误解的根源在于国内某著名的C程序设计教程.如果这篇文章能够纠正许多中国程序员对数组名和指针的误解,

【转】C语言-&gt;数组名与指针

以下内容转自: http://bbs.csdn.net/topics/390733584 感觉对自己有用,收藏了.如果转帖,请注明如上出处.多谢! 看到一篇关于C语言指针的文章,正好最近在看<C和指针>就去看了一下.<一道 C 语言指针访存题目的引申>,里面的第一个题目就把我难住了. 帮助123456789 #include <stdio.h>   int main() {     int a[5] = {1, 2, 3, 4, 5};     int *pa = (i

二维数组中数组名与其指针的关系

大多数初学者不是很清楚二维数组是个怎样的存在,今天我就来说说这个二维数组,计算机内存是一连串的存储单元,我们可以把它理解成一条线,没错就是一条线,那么问题来了,二维是个怎样的存在呢???说白了,二维数组并不真是二维,只是人们主观的将它变成二维,举个例子吧!比如楼梯,我们都知道楼梯说白了就是一条路,但是我们刻意将楼梯来回上升的方式,这都是我们主观的改变,实际上我们可以看成是一个直路,只是被工人弄弯了.好了,不扯了,进入主题.... 二维数组名a是数组第一行的指针,它指向的是一整行,*a才是a[0]

二维数组名和指针

#include <iostream> using namespace std; #define M 2 #define N 3 int main() { int a[M][N] = {1,2,3,4,5,4}; cout<<&(a[0])<<endl; //00DCFA64 cout<<&(a[0])+1<<endl; //00DCFA70,offest:12 cout<<a<<endl; //00DCF

第六章 数组名与指针

指针的算术运算符是指针和数组之间的一种关联,但不是唯一关联: 可以使用数组名作为指向数组第一个元素的指针,但是不可以给数组名赋新的值. //如下声明a int a[10]; //用a作为指向数组第一个元素的指针,可以修改a[0]; *a = 11; //通过a + 1来访问a[1]; *(a + 1) = 22; 但是试图使数组名指向其他地方是错误的: #include <stdio.h> int main() { char arr[] = "yangxunwu"; whi

数组名和指针能够等价的情况

摘自<c专家编程>c语言中,数组和指针不能够等价,在下面情况下,数组和指针能够等价使用. 规则 1. 表达式中的数组名被编译器当做一个指向该数组第一个元素的指针.char *p = array_name; 规则 2. 下标总是与指针的偏移量相同.array_name[index]与 *(p+index) 规则 3. 在函数参数的声明中,数组名被编译器当做指向该数组第一个元素的指针 void func(char *p)与void func(char p[])两种函数声明,函数调用时,func(a