数组与指针的理解

<span style="font-size:18px;">最近被数组,指针搞晕了,查了一些资料,也看了《C专家编程》这本书,对这些有了些了解。
下面写的这些东西时我个人的理解,如有不正确的地方,还望各位大神指正!
<span style="font-size:24px;"><strong>数组与指针的异同点</strong></span>
<strong>1、数组与指针的的不同点</strong>
很多时候数组和指针是一样的,但在C语言中两者确实有区别。
数组名就代表的该数组的第一个元素的地址,而指针存储的值才代表地址。
以下是节选自《C专家编程》中的一段话:</span>

char a[9]="abcdefgh";                    c=a[i];
编译器符号表具有一个地址9980
运行时步骤1:取i的值,将它与9980相加
运行时步骤2:取地址(9980+i)的内容

char *p;   .........      c=*p;
编译器符号表游弋ge符号p,他的地址为4624
运行时步骤1:取地址4624的内容,就是‘5081’
运行时步骤2:取地址5081的内容

char *p="abcdefgh";        c=p[i];
编译器符号表有一个p,地址为4624
运行时步骤1:取地址4624的内容,即‘5081’
运行时步骤2:取得i的值,并将它与5081相加
运行时步骤3:取地址[5081+i]的内容
C语言中“地址X”和“地址X的内容”都是用一个符号来表示的,为左值时,就代表“地址X”,为右值时就代表“地址X的内容”。
每个符号的地址在编译时可知,所以编译器需要一个地址来执行某种操作时,它就可以直接进行操作,并不需要增加指令首先取得具体的地址。相反,对于指针,必须首先在运行时取得它的当前值,然后才能对它进行解引用操作
相比于数组,指针操作多了依次额外的提取。
也就是说数组和指针在c语言中实际上是有区别的,尽管它们很多时候是相同的。所以定义数组后,再声明时也必须声明为数组类型,指针也一样。定义为对象分配内存,声明只是描述其他地方创建的对象。extern对象声明告诉编译器对象的类型和名字,对象的内存分配则在别处进行。由于并未在声明中为数组分配内存,所以并不需要提供关于数组长度的信息。
两者的具体区别为:
 
 
数组与指针的区别
指针数组
保存数据的地址保存数据
简介访问数据,首先取得指针的内容,把它作为地址,然后从这个地址取得数据。如果指针有一个下标【i】,就把指针的内容加上i作为地址,从中提取数据                                                                                                                               直接访问数据,a[i]只是简单地以a+i为地址取得数据                               
通常语用动态数据结构                                            通常用于存储固定数目且数据类型相同的元素
相关的函数为malloc(),free()隐式分配和删除 
通常指向匿名数据 
  

2、数组和指针相同的时候

《C专家编程》给出了解答:
数组和指针在编译器处理时时不同的,在运行时的表示形式也是不一样的,并可能产生不同的代码。对编译器而言,一个数组就是一个地址,一个指针就是一个地址的地址。数组与指针相同的时候主要是以下两种情况:
1、规则1“表达式中的数组名”就是指针
2、规则2下标总是与指针的偏移量相同
3、规则3在函数的声明中,数组名被编译器当做指向该数组第一个元素的指针。
在处理一维数组时,指针并不见得比数组更快。C语言把数组下标改写成指针偏移量的根本原因是指针和偏移量是底层硬件所使用的基本数据类型。
1、用a[i]这样的形式对数组进行访问总是被编译器“改写”或解释为像*(a+i)这样的指针访问。
2、在特定的上下文中,也就是它作为函数的参数(也只有这种情况),一个数组的声明可以看做是一个指针。作为函数参数的数组(就是在一个函数调用中)始终会被编译器修改成为指向数组第一个元素的指针。
3、当把一个数组定义为函数的参数时,可以选择把它定义为数组,也可以定义为指针。不管选择哪种方法,在函数内部事实上获得的都是一个指针

3、字符数组与字符指针

将字符串存于字符数组时应注意的地方:
利用字符串常量给字符数组初始化时,字符数组的大小必须大于字符串中字符的个数,因为字符串存储时结尾还要加'\0'
如:
char a[10]= "abcdefghij"; //编译时会提示错误,因为用字符串常量给字符数组初始化时,系统会自动在结尾加'\0'
char c[10]= {'a','b','c','d','e','f','g','h','i','j'}; //正确,数组大小为10,存储10个字符
char b[10]= {'a',b'','c','d','e','f','g','h','i'}; //正确,初始化了9个,系统会自动将第10个元素赋值为'\0'
//sizeof(b) = 10;
//strlen(b) = 9;
cout<<c<<endl; //不安全,但用g++编译后可以正常输出abcdefghij
cout<<b<<endl; //安全

4、一段测试的代码

 
#include<iostream>
#include<stdio.h>
using namespace std;
void fun1(char ca[])     //数组作为形参,进入函数内部还是当做字符指针处理
{
	cout<<"利用cout:"<<endl;
	cout<<"ca="<<ca<<"  "<<"&ca="<<&ca<<endl;
	cout<<"ca[0]="<<ca[0]<<"  "<<"&(ca[0])="<<&(ca[0])<<endl;
	cout<<"ca[1]="<<ca[1]<<"  "<<"&(ca[1])="<<&(ca[1])<<endl<<endl;
	cout<<"利用printf:"<<endl;
	printf(" addr of array param = %#x \n",&ca);    //此处ca还是相当于字符指针,此处输出的是字符指针本身的地址,而不是其所指向的地址。
	printf(" addr (ca[0]) = %#x \n",&(ca[0]));  //此处输出的是指针所指向的地址,也可以直接用ca输出,即实参数组的地址。
	printf(" addr (ca[1]) = %#x \n",&(ca[1]));
	printf(" ++ca = %#x \n\n\n",++ca);
}

void fun2(char *pa)   //指针作为形参
{
	cout<<"利用cout:"<<endl;
	cout<<"pa="<<pa<<"  "<<"&pa="<<&pa<<endl;
	cout<<"pa[0]="<<pa[0]<<"  "<<"&(pa[0])="<<&(pa[0])<<endl;
	cout<<"pa[1]="<<pa[1]<<"  "<<"&(pa[1])="<<&(pa[1])<<endl<<endl;
	
	cout<<"利用printf:"<<endl;
	printf(" addr of ptr param = %#x \n",&pa);
	printf(" addr (pa[0]) = %#x \n",&(pa[0]));
	printf(" addr (pa[1]) = %#x \n",&(pa[1]));
	printf(" ++pa = %#x \n\n\n",++pa);
}

char ga[10] = "hddufhugf";

int main(int argc,char *argv[])
{
	cout<<"main()函数中:"<<endl<<endl;
	cout<<"利用cout:"<<endl;
	cout<<"ga="<<ga<<"  "<<"&ga="<<&ga<<endl;
	cout<<"ga[0]="<<ga[0]<<"  "<<"&(ga[0])="<<&(ga[0])<<endl;
	cout<<"ga[1]="<<ga[1]<<"  "<<"&(ga[1])="<<&(ga[1])<<endl<<endl;
	
	cout<<"利用printf:"<<endl;
	printf(" addr of global array = %#x \n",&ga);   //此处用直接用ga输出数组的地址也可以,用%x
	printf(" addr (ga[0]) = %#x \n",&(ga[0]));
	printf(" addr (ga[1]) = %#x \n\n\n",&(ga[1]));

	cout<<"fun1(char ca[])函数中:"<<endl<<endl;;
	fun1(ga);

	cout<<"fun2(char *pa)函数中:"<<endl<<endl;
	fun2(ga);

	return 0;
}


该段代码用g++编译后运行结果如下:

main()函数中:


利用cout:
ga=hddufhugf  &ga=0x804b040
ga[0]=h  &(ga[0])=hddufhugf
ga[1]=d  &(ga[1])=ddufhugf

利用printf:
 addr of global array = 0x804b040 
 addr (ga[0]) = 0x804b040 
 addr (ga[1]) = 0x804b041 

fun1(char ca[])函数中:

利用cout:
ca=hddufhugf  &ca=0xbfd543a0
ca[0]=h  &(ca[0])=hddufhugf
ca[1]=d  &(ca[1])=ddufhugf

利用printf:
 addr of array param = 0xbfd543a0 
 addr (ca[0]) = 0x804b040 
 addr (ca[1]) = 0x804b041 
 ++ca = 0x804b041 

fun2(char *pa)函数中:

利用cout:
pa=hddufhugf  &pa=0xbfd543a0
pa[0]=h  &(pa[0])=hddufhugf
pa[1]=d  &(pa[1])=ddufhugf

利用printf:
 addr of ptr param = 0xbfd543a0 
 addr (pa[0]) = 0x804b040 
 addr (pa[1]) = 0x804b041 
 ++pa = 0x804b041 


  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值