【学习笔记】数组的地址分配及指针数组的使用

对于一维数组a[i](a[i]类型不为char),a表示数组的首地址,即a=&a[0]。

int a[10];
cout<<a<<endl;
cout<<&a[0]<<endl;//两者相同,都表示数组a的首地址。
cout<<*a<<endl;
cout<<a[0]<<endl;//两者相同,都表示数组a的首元素a[0]。

对于字符串数组,使用输出数组名称指令则会直接输出整个字符串数组。

char str[10]={'1','2','3','4'};
cout<<str<<endl;//输出整个字符串
cout<<&str[0]<<endl;//输出整个字符串
cout<<*str<<endl;//输出首元素
cout<<(char *)str<<endl;//输出整个字符串
cout<<(int *)str<<endl;//输出字符串首地址
cout<<(void *)str<<endl;//输出字符串首地址
cout<<&str[1]<<endl;//输出234

综上,cout遇到输出字符类型的地址时,不会输出地址,而是输出该地址上的字符。所以如果想输出字符串数组的地址,需要把指针改为其他类型,如void或int。

指针存在类型 ,如int *p,p是int类型的指针,不可以指向double类型的地址

int *p p=p+1 加上了一个int的字节,即加了四个字节。
char *p p=p+1 加上了一个char的字节,即加了一个字节。

int a[10]={1,2,3};
cout<<*a<<endl;//结果为1
cout<<*(a+1)<<endl;//结果为2

指针存在着运算,此处说明一维数组分配的是一段连续的内存,可以通过某种运算公式得到地址。如要求a[5],地址即为a+5。

对于二维数组,以a[10][20]为例,其实分配的内存也是连续的一段,故可以通过某个固定的运算公式来得到地址。
要求a[5][5],地址即为a+5*20+5。其中20为第二维的长度。
对多维数组也是如此。很容易发现,地址的计算与一维的数目无关,这也是为何将数组作为参数被函数调用时不需要写明第一维的长度,但需写明除第一维外所有维度长度的原因。

二维数组的数组名也是表示数组的地址,但与一维数组不同的是,它表示的数组中的每一个元素都是一个数组的地址。

int a[10][20];
a[0][0]=1;
cout<<(*a)<<endl;//输出a[0],即a[0][0]的地址
cout<<*(*a)<<endl;//输出a[0][0]
cout<<*a[0]<<endl;//输出a[0][0]

在数组a中,每一个元素a[i]都代表着一个数组的地址,对应着二维数组的一行。因此,a与一维数组的首地址不同,如果想用一个指针p指向a,不可以运用与一维数组相同的方式。

int a[10][20];
//int *p=a;  编译报错
int (*q)[20]=a;//编译成功
int (*t)[20]=&a[0];//编译成功
int *p=a[0];//编译成功,此时p与q指向的地址相同,都为a[0]

此处的(*q)[20]意在告诉编译器,a所指向的数组中的元素都是一个长度为20的数组。

int a[10][20];
int (*q)[20]=a;
cout<<q<<endl;//0x61faf0
cout<<q+1<<endl;//0x61fb40
cout<<a[0]<<endl;//0x61faf0
cout<<a[0]+1<<endl;//0x61faf4

指针q的移动均是跨行移动,因为a在其指向的数组上,a[1]与a[2]之间分配的内存刚好相差一个第二维的长度,因此q每加1,相当于增加了20*4个字节,在十六进制下为50。而a[0]每移动1,其地址增加4个字节。

指针数组+二重指针

定义:

如果一个数组中的所有元素保存的都是指针,那么我们就称它为指针数组。

指针数组的定义形式一般为:

dataType *arrayName[length];

注意区别指向二维数组的指针(在上文为a)的定义为

dataType (*arrayName)[length]

int a=1,b=2,c=3;
int *p[5]={&a,&b,&c};//相当于p[0]=&a
cout<<*(p[1]);//输出2

对于指针数组,同样是一个数组,如果想要再使用一个指针p指向该数组的首地址,那指针p即是指针数组指针,即是一个二重指针

对二重指针的定义为

dataType **(arrayName);

具体使用举例

int a=1,b=2,c=3;
int *p[5]={&a,&b,&c};//相当于p[0]=&a
int **q=p;
cout<<*(q)<<endl;
cout<<p[0]<<endl;//两者输出结果相同

需要注意的是:
二重指针代表着这个指针指向的数组的类型是一个指针数组,即是数组中的每一个元素都是一个指针。
而二维数组中,数组名a作为地址,对应的数组的每一个元素是二维数组每一行的首地址(可认为是地址数组)。
故不可直接用二重指针指向a所在的地址。

int a[10][20];
int (* q)[20]=a;//正确
int **p=a;//错误

指针数组中的每一个指针指向地址时是相互独立的。

上文中a指向的数组中a[1]、a[2]是对应的二维数组的每一行的地址。我们可以对每一行分别用一个指针指向这一行的首地址,将一个二维数组所用的指针放进一个数组中,就得到了一个指针数组。
如果先定义了二维数组,再用指针数组去指向每一行的首地址,那么指针数组中的指针指向的地址便是连续的。

int *p[3];
int a[3][2]; 
for(register int i=0;i<3;i++){
	p[i]=a[i];//p[i]=&a[i][0];
}
cout<<p[0]<<" "<<p[1]<<" "<<p[2]<<endl;
//输出0x61fe00 0x61fe08 0x61fe10

但如果先定义了指针数组,再让每一个指针去指向一个一维数组从而构成一个二维数组,那么每一个指针的内存分配就不一定连续

int *q[5];
int a[2],b[2],c[2];
q[0]=a;
q[1]=b;
q[2]=c;
cout<<q[0]<<" "<<q[1]<<" "<<q[2]<<endl;
//输出0x61fde8 0x61fde0 0x61fdd8

举一些函数对二维数组调用的例子

void BubbleSort(char a[10][20]);//正确
void Bubble(char a[][20], int n);//正确
void Bubble(char a[10][], int m);//错误,关键在除第一维之外的维度
void Bubble(char * a[10], int m);//正确
void Bubble(char a[][], int n, int m);//错误,理由如上
void Bubble(char ** a, int n, int m);//正确
void Bubble(char * a[], int n, int m);//正确,第一维不需要

上文中第4、6、7种调用方法与第1、2种所用的内存分配方法不同,在调用时有着不同的调用方式。

void dfs(char **a){
    return;
}
void dfs1(char *a[]){
    return;
}
int main(){
    char *p[5];
    dfs(p);
    dfs1(p);
}

指针的内容较为繁杂,故写下这篇文章便于自身理解,也希望各位读者可以对其提出宝贵的意见。

  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
你好!关于学习数据结构的C语言笔记,我可以给你一些基本的指导和概念。数据结构是计算机科学中非常重要的一门课程,它涉及存储和组织数据的方法。C语言是一种常用的编程语言,很适合用于实现各种数据结构。 下面是一些数据结构的基本概念,你可以在学习笔记中包含它们: 1. 数组(Array):一种线性数据结构,可以存储相同类型的元素。在C语言中,数组是通过索引访问的。 2. 链表(Linked List):也是一种线性数据结构,但不需要连续的内存空间。链表由节点组成,每个节点包含数据和指向下一个节点的指针。 3. 栈(Stack):一种后进先出(LIFO)的数据结构,类似于装满物品的箱子。在C语言中,可以使用数组或链表来实现栈。 4. 队列(Queue):一种先进先出(FIFO)的数据结构,类似于排队等候的队伍。同样可以使用数组或链表来实现队列。 5. 树(Tree):一种非线性数据结构,由节点和边组成。每个节点可以有多个子节点。二叉树是一种特殊的树结构,每个节点最多有两个子节点。 6. 图(Graph):另一种非线性数据结构,由节点和边组成。图可以用来表示各种实际问题,如社交网络和地图。 这只是数据结构中的一些基本概念,还有其他更高级的数据结构,如堆、哈希表和二叉搜索树等。在学习笔记中,你可以介绍每个数据结构的定义、操作以及适合使用它们的场景。 希望这些信息对你有所帮助!如果你有任何进一步的问题,请随时提问。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值