C/C++中数组名的含义

原创 2004年11月03日 01:29:00

    C/C++中的数组名是个很奇怪的东西,它到底代表什么呢?
   
    对于char array[n](n是一个常数),大概有这么几种语义:
    <1> char* const(注意不是const char*)   <2> char [n]

    举例如下(WIN2000 PRO平台,VC.NET 7.1下编译):

<1> char *p = array; //array表示char* const,p得到的是数组的首地址

    size_t size = sizeof(char [n]); // size等于n

<2> char (*p)[n] = &array; // array表示char [n],
                           // p得到的仍然是数组的首地

        
    char (*q)[n] = array;  // 编译错误

    char (*r)[n] = (char (*)[n])array; // r得到的是array数组的首地址

<3> char (&p)[n] = array;  // array表示 char [n]

<4> void foo(char a[n])
    {
      int size = sizeof(a); 
// size == 4(32位系统),
                             // 因为a实际上表示的是char
*
    };

    foo(array);            // array表示char* const

<5> void foo(char (&a)[n]);
    {
       int size = sizeof(a);  
// size == n
    };

    foo(array);           // array表示char [n]

<6> void foo(char (*a)[n]);
    {
       int size = sizeof(*a);   // size == n
    };

    foo(&array);           // array表示 char [n]

<7> char *p;
    array = p; 
// 编译错误"error C2440,无法从char*转化为char [n]",
                // 因此array表示char [n]

<8> char other[n];
    array = other;  
// 编译错误"error C2106, '='左操作数必须为L值", 
                     // 因此array表示char [n]

    (char (&)[n])array = other; 
   
// 执行完后array的头4个元素表示的32位数与other代表的数组首地址相同,
    // 在这里other被解释成char* const

    (char (&)[n])array = (char [n])other;
    // 执行完后array的头4个元素表示的32位数与other代表的数组首地址相同

    (char (&)[n])array = (char (&)[n])other;
    // 执行完后array数组与other数组的头四个元素相等

    (char (*&)[n])array = (char (*)[n])other;
   
// (char (*&)[n])表示的是一个引用类型,
    // 这个引用关联到一个指向char[n]数组的指针,
    // 执行完后array的头4个元素表示的32位数与other代表的数组首地址相同

    (__int64&)array = (__int64&)other;
    // 执行完后array数组与other数组的头8个元素相等

<9> long i = 0;
    (long &)array = i;  
// 实际改变的不是array本身的值,
                        // 而是它代表的数组中的头4个元素(32位),
                        // 因此array代表的是char [n]

<10> long i = 0;
     (char (&)[n])i = array;
// 假设array数组首地址为0x0012feac,
                             // 则指令执行后i == 0x0012feac

<11> long i = 0;
     (char (&)[n])i = (char (&)[n])array;   
     // 执行后i的值等于array头4个元素代表的32位数(32位系统)
   
<12> (char *&)array = "string";     
     
// 执行后array头4个元素代表的32位数与
      // "string"常量字符串在内存中的地址相同

<13> (char (&)[n])array = (char (&)[n])"string";
     // array数组的头4个元素依次为's','t','r','i'

    当我们进行(char [n])array这样的强制转换时,效果与(char* const)array转换相当,都被解释成表示数组首地址的指针。但是两者还是有微妙区别的:sizeof(char [n])等于n,sizeof(char* const)等于4(32位系统),而且象(char [m])array这样的转换就不允许,其中m不等于n。如果我们用某种引用类型强制转换数组名时,编译系统会将转换结果(引用类型)自动关联到从数组首地址开始的内存区,而非数组名本身所在的内存区(它是否真的存在于内存中都是个未知数)。当我们用这样强制转换过的数组名做赋值操作的左操作数时,改变的就是数组名代表的数组内存区了,而被改变的内存区的大小就要视引用类型而定,比如__int64&,那么大小就是8字节,其余类推。因为(char [n])(char* const)效果基本相当,结果都被解释成指针,所以(char (&)[n])(char* const &)也基本相当,结果就被解释成关联到指针的引用。当用(char (&)[n])array做赋值操作的右操作数时,实际上会从array数组首地址开始的内存区读sizeof(char* const)大小的数据,然后赋值给左操作数。这就可以解释为什么(char (&)[n])array = (char (&)[n])other执行后array与other的头4个元素相等了。

 

    补充于2004年12月19日:
    我总结的语义恐怕还不够准确,现在把ANSI C标准中的说法摘录如下: (1)当一个数组标识符出现在表达式中,这个标识符的类型就从“某种类型T的数组”转换成“指向类型T的指针”,而且它的值就等于数组第一个元素的地址。但是当数组标识符被用作sizeof和取址(&)操作的操作数时,sizeof返回的是整个数组的大小,而取址操作返回的是指向数组的指针(而不是指向一个值为数组头元素地址的指针的指针)。(2)下列表达式不能产生lvalue: 数组名,函数,枚举常量,赋值表达式,强制类型转换,函数调用。

    根据以上说法基本可以推断C程序中数组名的语义,但是这并没有涵盖C++,我手头没有ISO C++标准,所以自己也很不确定。不过可以肯定,C++因为有引用类型,所以情况要复杂。比如对于C中不会产生lvalue的赋值表达式,C++就有不同的解释。

int a;
(a = 10) = 1000;

这两行代码在C中非法,但是在C++中完全合法。

    另外,有人说gcc对(5)也会编译报错,经作者用MinGW3.1.0(g++ 3.2.3)测试发现不会。因为(5)中不会产生临时变量,仅仅是用了array来初始化函数中的局部引用类型变量a,这是完全合法的动作。

    补充于2005年7月1日: 用MinGW3.1.0(g++ 3.2.3)编译,只要涉及到(char (&)[n])array的强制转换均通不过,错误信息为: cannot convert `char*' to `char[n]' in converting。同样,(char* &)array也出错,因为array是一个类型为char*的rvalue,不允许转换为non-const引用类型,而改成(char* const &)array便可行,但相应的 (char* const &)array = "string" 则对array数组没有任何影响(为什么?估计是因为产生了一个(char * const &)类型的临时变量,对这个变量做初始化,所以对array没有任何影响)。

C++学习之数组名a与&a的区别

在C++中定义一个数组: int a[5]={1,2,3,4,5}那么a到底代表什么含义呢?首先想到的是a代表的是数组的首元素地址。那么如果问你a的类型是什么呢?估计很多人就不太确定了,看下面程序,...
  • softmanfly
  • softmanfly
  • 2015年04月06日 17:58
  • 1128

C++数组到底可以开多大?

一个由C/C++编译的程序占用的内存分为以下几个部分     1、栈区(stack)—   由编译器自动分配释放   ,存放函数的参数值,局部变量的值等。其     操作方式类似于数据结构中的栈。  ...
  • a479778594
  • a479778594
  • 2017年04月13日 13:34
  • 2852

C++数组--详细分析

1、数组下标:    (1)在定义时必须明确。            ①只能用正整数或const常量,静态或全局变量不可以;例如:const int length=5; int array[lengt...
  • piaojun_pj
  • piaojun_pj
  • 2010年10月03日 13:19
  • 9847

C/C++如何解决大数组问题?

编了一晚上的程序,结果因为数组太大不能运行:segmentation…… 取找解决方法:这个比较适用!赞     方法一:     在VC的Proj...
  • ysuncn
  • ysuncn
  • 2007年09月23日 05:52
  • 7000

C++内置数组和array的比较

array是C++11中新提出来的容器类型,与内置数组相比,array是一种更容易使用,更加安全的数组类型,可以用来替代内置数组。作为数组的升级版,继承了数组最基本的特性,也融入了很多容器操作,下面介...
  • u011405218
  • u011405218
  • 2017年04月24日 19:40
  • 2589

c++ 数组排序(选择, 冒泡, 插入,快速)

#include using namespace std; //冒泡排序 void bubbleSort(int arr[], int n) { for(int i = 0;i < n;i++){ ...
  • ybhjx
  • ybhjx
  • 2016年09月03日 12:18
  • 5679

C++中数组的基础知识

》数组            数组(Array)是由固定数目元素组成的数据结构,同一数组的所有元素的类型都相同。数组元素是通过下标进行访问的。数组可以是一维的,也可以是多维的,许多重要应用的数据结构...
  • darkxiaoming
  • darkxiaoming
  • 2017年04月17日 12:35
  • 480

C++数组的引用—防止数组退化

在c语言中,数组作为函数参数时,实际上数组已经退化为指针使用。 下面这三种用法是等价的:int f1(int apples[]); int f1(int apples[10]); int f1(in...
  • lanyang123456
  • lanyang123456
  • 2017年03月05日 17:51
  • 693

C++中如何定义动态数组

首先:为什么需要动态定义数组呢?   这是因为,很多情况下,在预编译过程阶段,数组的长度是不能预先知道的,必须在程序运行时动态的给出   但是问题是,c++要求定义数组时,必须明确给定数组的大小,...
  • bzhxuexi
  • bzhxuexi
  • 2013年12月09日 21:27
  • 30161

【C++】用指针定义多维可变长数组

我们都知道c++中的vector容器可以定义不定长数组,通过vector的嵌套可以实现多维,但显然vector对于空间和时间的消耗过大,而且代码将因此变得复杂。 本文介绍一种定义类似普通的数组,但允许...
  • icykitty
  • icykitty
  • 2016年11月04日 17:17
  • 543
内容举报
返回顶部
收藏助手
不良信息举报
您举报文章:C/C++中数组名的含义
举报原因:
原因补充:

(最多只允许输入30个字)