C语言中数组名和指针的区别 及 sizeof用法

  1. #i nclude <iostream.h>   
  2. int  main( int  argc,  char * argv[])   
  3. {   
  4. char  str[10];   
  5.   char  *pStr = str;   
  6.  cout <<  sizeof (str) << endl;   
  7.  cout <<  sizeof (pStr) << endl;   
  8.   return  0;   

 实际情况是:第6行输出10,第7行输出4;

 

先给出三个结论:

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

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

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

 

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

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

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

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

 

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

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

 

下面的程序成立吗?

C++代码
  1. int  intArray[10];   
  2. intArray++;

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

 

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

 

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

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

C++代码
  1. #i nclude <iostream.h>   
  2. void  arrayTest( char  str[])   
  3. {   
  4.  cout <<  sizeof (str) << endl;   
  5. }   
  6. int  main( int  argc,  char * argv[])   
  7. {   
  8.   char  str1[10] =  "I Love U" ;   
  9.  arrayTest(str1);   
  10.   return  0;   
  11. }  


  程序的输出结果为4。不可能吧?

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

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

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

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

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

 

 

一、 sizeof的概念 

  sizeof是C语言的一种单目操作符,如C语言的其他操作符++、--等。它并不是函数。sizeof操作符以字节形式给出了其操作数的存储大小。操作数可以是一个表达式或括在括号内的类型名。操作数的存储大小由操作数的类型决定。

 

二、 sizeof的使用方法 
   1、用于数据类型 
sizeof使用形式: sizeof(type) 
数据类型必须用括号括住 。如 sizeof(int)。 
2、用于变量 
sizeof使用形式: sizeof(var_name)或sizeof var_name  
变量名可以不用括号括住。如 sizeof (var_name),sizeof var_name等都是正确形式。带括号的用法更普遍,大多数程序员采用这种形式。 

三。sizeof用法总结
在 VC中,sizeof有着许多的用法,而且很容易引起一些错误。下面根据sizeof后面的参数对sizeof的用法做个总结。
A. 参数为数据类型或者为一般变量。例如 sizeof(int),sizeof(long)等等。这种情况要注意的是不同系统系统或者不同编译器得到的结果可能是不同的 。例如int类型在16位系统中占2个字节,在32位系统中占4个字节。
B. 参数为数组或指针。下面举例说明 .
int a[50]; //sizeof(a)=4*50=200; 求数组所占的空间大小
#int* a= “hello world”,应该是 12(要注意)
int *a=new int[50];// sizeof(a)=4; a为一个指针, sizeof(a)是求指针
//的大小 ,在32位系统中,当然是占4个字节。
C. 参数为结构或类。 Sizeof应用在类和结构的处理情况是相同的。但有两点需要注意,第一、结构或者类中的静态成员不对结构或者类的大小产生影响,因为静态变量的存储位置与结构或者类的实例地址无关
第二、 没有成员变量的结构或类的大小为1,因为必须保证结构或类的每一 个实例在内存中都有唯一的地址。
下面举例说明,
Class Test{int a;static double c};//sizeof(Test)=4.
Test *s;//sizeof(s)=4,s为一个指针。
Class test1{ };//sizeof(test1)=1;
D. 参数为其他。下面举例说明。
int func(char s[5]);
{
cout<<sizeof(s)<<endl;
//数的参数在传递的时候系统处理为一个指针,所
//以 sizeof(s)实际上为求指针的大小。
return 1;
}
sizeof(func(“ 1234”))=4//因为func的返回类型为int,所以相当于
//求 sizeof(int). 还要注意的是“1234”而不是“12345”)
以上为 sizeof的基本用法,在实际的使用中要注意分析VC的分配变量的分配策略,这样的话可以避免一些错误。


示例
char str[20]="0123456789"; int a=strlen(str); //a=10; >>>> strlen 计算字符串的长度,以结束符 0x00 为字符串结束。
int b=sizeof(str); //而b=20; >>>> sizeof 计算的则是分配的数组 str[20] 所占的内存空间的大小,不受里面存储的内容改变。

上面是对静态数组处理的结果,如果是对指针,结果就不一样了
char* ss = "0123456789";
sizeof(ss) 结果 4 ===》ss是指向字符串常量的字符指针,sizeof 获得的是一个指针的之所占的空间,
应该是长整型的 ,所以是4

sizeof(*ss) 结果 1 ===》*ss是第一个字符 其实就是获得了字符串的第一位'0' 所占的内存空间,
是char类型的, 占了 1 位

 

 

<think>好的,我现在要解决用户的问题:C语言数组指针之间的区别。用户已经提供了一些参考资料,我需要结合这些资料,整理出一个清晰易懂的回答。 首先,我需要回顾一下数组指针的基本概念。数组是相同类型元素的集合,存储在连续的内存中。而指针是一个变量,存储的是另一个变量的内存地址。根据引用[3],数组指针指向整个数组指针,比如定义char (*pOneArray)[3] = &cTestOne,这里的pOneArray指向整个数组,而不是数组的第一个元素。这点需要注意,因为普通指针通常指向单个元素。 接下来,用户提到的参考资料中有几个关键点。引用[1]详细讲解了数组指针的基本概念使用方法,强调数组指针在C语言中的作用。引用[2]展示了如何创建指针数组,每个指针指向二维数组的一行,例如int *ptrArray[3];,这里ptrArray是一个数组,元素是指向整型的指针。而引用[3]则进一步解释了数组指针的定义地址空间的问题,比如数组名代表整个数组的地址,而数组指针可以指向整个数组。 现在需要区分数组指针的不同。首先,内存分配方面,数组在声明时会分配固定大小的连续内存,比如int arr[5]会分配20字节(假设int是4字节)。而指针本身只是一个地址变量,通常占用4或8字节,具体取决于系统。例如,int *p; 这里p是一个指针,需要后续指向某个内存区域,比如动态分配或指向现有数组。 然后是访问方式的不同。数组通过下标直接访问元素,比如arr[0]。而指针需要解引用,比如*p或者*(p+1)。不过,数组名在大多数情况下会被隐式转换为指向首元素的指针,所以arr[i]*(arr+i)是等价的。但需要注意的是,数组名并不是指针变量,而是一个常量指针,不能被重新赋值,比如不能arr = another_arr,而指针变量p可以重新指向其他地方。 类型方面,数组的类型包括元素类型大小,比如int[5]int[3]是不同类型。而指针的类型只涉及所指向的数据类型,比如int *,不管指向的是单个int还是数组中的元素。数组指针则是一个例外,比如int (*p)[5]是一个指向包含5个int元素的数组指针,这时候p的类型是int(*)[5],int(*)[3]不同,这影响指针运算时的步长。 sizeof操作符的结果不同。对于数组sizeof返回整个数组占用的字节数,比如sizeof(arr)是20字节(假设int arr[5])。而对于指针sizeof返回指针变量本身的大小,通常是4或8字节,不管指向的内容有多大。这一点在编程中需要特别注意,避免计算错误的内存大小。 作为函数参数时,数组会被退化为指针。例如,函数void func(int arr[])实际上等同于void func(int *arr),这时候在函数内部无法通过sizeof得到数组的实际大小,只能通过额外参数传递。这也是为什么在函数中处理数组时,通常需要传递数组长度的原因。 初始化方式也有区别数组可以在声明时初始化,比如int arr[] = {1,2,3};。而指针需要指向已存在的内存地址,比如指向数组的首元素int *p = arr;,或者动态分配内存int *p = malloc(5 * sizeof(int));。但要注意,动态分配的内存需要手动释放,否则会导致内存泄漏。 通过引用[3]中的例子,数组指针char (*pOneArray)[3] = &cTestOne,这里的pOneArray指向整个数组,因此对pOneArray进行加减运算时,步长是整个数组的大小。比如pOneArray+1会跳过一个完整的数组长度,而普通指针加1则根据元素类型移动。这可能在实际应用中产生不同的结果,需要特别注意。 总结一下,数组指针在内存分配、访问方式、类型、sizeof结果、函数参数处理、初始化方式等方面存在显著差异。虽然它们在某些情况下可以互换使用,但理解这些区别对于避免错误编写高效代码至关重要。</think>### C语言数组指针区别 #### 1. **本质差异** - **数组**:是**连续内存空间**的集合,存储固定数量的同类型元素。例如,`int arr[5]`会分配5个连续的`int`类型内存单元。数组名`arr`代表整个数组的地址,但**退化为指针**时指向首元素地址[^3]。 - **指针**:是**变量**,存储内存地址。例如,`int *p`仅存储一个地址值,需指向已有内存(如数组或动态分配内存)才能操作数据[^1]。 #### 2. **内存分配方式** - **数组**: 声明时直接分配固定大小内存,例如: ```c int arr[5]; // 分配20字节(假设int为4字节) ``` - **指针**: 需显式指向内存(静态或动态): ```c int *p = arr; // 指向数组首元素 int *p2 = malloc(5 * sizeof(int)); // 动态分配内存 ``` #### 3. **访问方式** - **数组**通过下标直接访问元素: ```c arr[0] = 10; // 直接修改第一个元素 ``` - **指针**需通过解引用操作: ```c *p = 10; // 修改p指向的第一个元素 *(p + 1) = 20; // 修改第二个元素 ``` #### 4. **类型与运算** - **数组类型**包含元素类型长度,例如`int[5]``int[3]`是不同类型。 - **指针类型**仅关注指向的数据类型(如`int *`),指针运算步长由类型决定: ```c int arr[5]; int (*pArr)[5] = &arr; // 步长为整个数组长度(20字节) int *p = arr; // 步长为单个int长度(4字节) ``` #### 5. **sizeof操作结果** - **数组**:`sizeof(arr)`返回整个数组占用的字节数。 - **指针**:`sizeof(p)`返回指针变量本身的大小(4或8字节)。 #### 6. **函数参数传递** - **数组作为参数**时退化为指针: ```c void func(int arr[]) { // 实际等效于int *arr // 无法通过sizeof(arr)获取数组长度 } ``` - **指针作为参数**需额外传递长度信息: ```c void func(int *arr, int size) { ... } ``` #### 7. **初始化方式** - **数组**可在声明时初始化: ```c int arr[] = {1, 2, 3}; // 自动推断长度为3 ``` - **指针**需指向有效内存: ```c int *p = arr; // 指向数组 int *p2 = NULL; // 初始化为空指针 ``` #### 8. **典型场景对比** | **特性** | **数组** | **指针** | |----------------|---------------------------|---------------------------| | 内存分配 | 静态/自动分配 | 需显式指向内存 | | 可重新赋值 | 否(常量地址) | 是 | | 类型信息 | 包含元素类型长度 | 仅包含指向类型 | | 地址运算步长 | 由元素类型决定 | 由指向类型决定 |
评论 10
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值