数组——参考《C和指针》

简介: 数组——参考《C和指针》

一、单维数组

初印象: 顺序存储(连续空间),一些相同类型值的集合,有一维、二维...多维数组,数组名有讲究,数组做参数传递,下标有讲究。
回顾: 今天重新读了读《C和指针》第8章:数组,发现又有许多新收获,特此写本博文,记录下自己的受过,以防忘记。

二、数组名

①数组名:指向第一个元素的指针常量,(注:不是指针变量)。
程序在编译链接的过程中,直接给数组分配好了固定的空间,数组名就是一个指向这个空间的指针常量。
判断题:数组和指针是相同的。 (X) 理由:只有数组名在表达式中使用时,编译器才会为了它产生一个指针常量。

②有些时候数组名不是指针常量:
1)当数组名作为sizeof操作符的操作数时,返回数组的长度
2)当数组名作&的操作数时候,返回指向数组的指针 而不是指向某个 指针常量 的指针。
&array[0]和array值相等 但是前者是指针变量后者是指针常量(不能改变)。

③疑问: 在刚开始学习数组的时候,我总是存在这样一个疑问:为什么一般的变量直接用=即可赋值,如a=b,但是数组却不能直接int a[10];int b[10]; b=a;直接赋值它不香吗?
④解答: 数组名只是指向第一个元素的常量指针,而不是所有元素。

三、数组下标

①下标引用和间接访问完全相同:array[i]<=>*(array+i)
②扩展: 下标引用可以作用于任意的指针,不仅仅是数组名。
判断题:i[array]这种表达形式对吗? (√)理由:i[array]<=>array[i]
③指针和下标谁谁效率高: 用指针效率>=用下标的效率,但是不能差别不大,收益不高。
④警告: 下标不能越界,有的编译器为了提高效率,不会检查是否下标越界,所以要注意。

四、数组和指针

①区分:int a[5]int* b区分ab
| |相同点|不同点1:被编译器区别对待 |不同点2:间接访问|不同点3:指针运算
|--|--|--|--|--|
|a |具有指针值、都可以间接访问和下标引用操作。 | 为数组声明一大片连续地空间|*a 是数组第一个元素|a++非法 是指针常量
|b| 具有指针值、都可以间接访问和下标引用操作。|只为指针本身保留空间,不为int分配空间|*b访问某个未知空间非法|b++合法 是指针变量
②结合下图理解:
在这里插入图片描述

五、数组名做函数参数。

①回顾: 数组名是一个指向数组第1个元素的指针常量。
②调用形式:int array[10]做函数function的参数。

int function(int *array);    //推荐使用,这里的array是指针,不和真正意义上的数组混淆
int function(int array[]);

③参数如何传递: 实际传递给函数的是指向数组起始位置的指针的一份拷贝,该指针同样指向数组起始位置。在函数内部对指针形参进行间接访问操作,实际访问的是原数组的元素。这个形参(拷贝的指针)不会改变实参,但是能改变它们指向的内容。(毕竟它们操作的都是一块内存)。
④实列: 把第2个参数中的字符串复制到第1个参数指定的缓冲区

void (char* buffer,const char* string)
{
   
   
    while((*buffer++=*string++)!='\0');
}

⑤练习题: 下面代码中的array1array2有区别吗?

void function(int array1[10])
{
   
   
    int array2[10]
}

答案:指针和数组名的区别
array1是一个指针变量,它指向传给它的实参数组,它的值在函数中可以改变。在这个函数中没有为这个数组分配内存空间,并且不能保证传输的这个数组有10个值,指出数组数量是多余的。
aray2是一个 指针常量,它的值不能改变,它指向函数中分配的含有10个整型元素的数组的首元素。

六、多维数组

①存储方式: 行主序列,列主序列。要点:只要坚持使用同一种方法,这两种解释方法都可行。
②数组名: 一维数组名的值是一个指针常量,类型是: 指向元素类型的指针 多维数组的第一维的元素是宁外一个数组,类型是: 指向指针的指针
③下标: 下标应用仍然是一种间接访问表达式的一种伪装形式。下面通过实例来理解:

原数组:int matrix[3][10]
matrix[1][5]<=>*(*(matrix+1)+5)

在这里插入图片描述

matrix<=>matrix[0]

在这里插入图片描述

matrix+1<=>matrix[1]

在这里插入图片描述

*(matrix+1)<=>&matrix[1][0]

在这里插入图片描述

*(matrix+1)+5<=>&matrix[1][5]

在这里插入图片描述
④指向数组的指针

int array1[10],*p1=array1;//正确声明
int array2[3][10],*p2=array2;//错误声明

p1声明是正确的,理由如下:p1array1都指向array1的第一个元素,并且都是指向整型的指针。
p2声明是错误的,理由如下:p2是一个指向整型的指针,但是这里array2是一个指向整型数组的指针,它们类型都不一致。array2是一个由10个整型元素的指针。正确声明如下:

int array2[3][10]int (*p2)[10]=array2;//p2指向了array2的第1行

那么如果要一个指针逐个访问整型元素而不是逐行在数组中移动,该如何声明呢??

int *p=&array[0][0];
int *p=array[0];

⑤多维数组作为函数参数
回顾一维数组做参数:

int function(int *array);    //推荐使用
int function(int array[]);

多维数组和一维数组做参数实质上都是:传递指向数组第1个元素的指针。但是两者还是有区别的:
多维数组的每一个元素本身是宁外一个数组,编译器需要知道它的维数,以便为函数形参的下标表达式进行求值。

int function(int (*array)[10]);
int function(int array[][10]);

疑问: 第1维的长度可以不用填?
解答: 数组的长度是由编译器自动计算的,只有第1维才能根据初始化列表默认提供,剩下的几维必须显示地写出来。具体细节,不详细说明,总之这是编译器的事儿。
警告⚠: 编写1维数组形参的原型时,既可以写成数组形式,也可以写成指针形式。但是对于多维数组,只有第1维才有这两种选择。这种表示第二维数组的写法是不正确的:int function(int ** array);这是指向整形的指针,而并非指向整形数组的指针

七、指针数组

初印象: 首先指针和数组这两个名词组合在一起,那究竟是指针呢?还是数组?显而易见是:数组,其实你发现别的类型的叫法:整形数组、浮点型数组....猛然回头,指针也是一种类型。整形数组用于存整形数据,自然而然,指针数组,用来存指针。
讨论: int *p[10]; 乍一看,有点复杂,我们假设它是个表达式,并对它进行求值。
(下标引用[])优先级高于(间接访问*),所以先执行[],所以它是一个数组,随后执行*得到一个整型值。再对数组的某元素执行间接访问*后得到一个整型,所以p是数组,它的元素类型是指向整形的指针

八、一些实用技能

①计算数组的长度: 整个数组大小/每个元素大小=元素个数 sizeof(array)/sizeof(array[0]);
这里的数组名:array此刻被sizeof操作,所以它不是一个指针常量。

②区分char const* ptrconst char* ptrchar * const ptr : 参考路痴的旅行的博客
char const* ptr<==>const char* ptr 定义一个指向字符常量的指针,这里,ptr是一个指向 char*类型的常量,所以不能用ptr来修改所指向的内容,换句话说,*ptr的值为const,不能修改。但是ptr的声明并不意味着它指向的值实际上就是一个常量,而只是意味着对ptr而言,这个值是常量。

相应技巧: 很多时候为了防止这个指针修改这个形参,我们就把它声明为:char const*类型,让指针指向一个“假”的const类型。
char *const ptr 定义一个指向字符的指针常数,即const指针,不能修改ptr指针,但是可以修改该指针指向的内容。
练习题:
解释void function(int const a,int const b[])中两个const 的区别:
答案:第1个参数是个标量,所以函数得到值的一份拷贝。对这份拷贝的修改并不会影响原先的参数,所以const关键字的作用并不是防止原先的参数被修改。
第2个参数实际上是一个指向整型的指针。传递给函数的是指针的拷贝,对它进行修改并不会影响指针参数本身,但函数可以通过对指针执行间接访问修改调用程序的值。const关键字用于防止这种修改。

③区分sizeofstrlen: 首先根本上来说,他们根本就是牛头不对马嘴,sizeof是操作符而strlen是库函数。在求字符串的长度的时候,strlen不包括\0,而sizeof包括\0。如代码:

    char a[] = "wocao";
    cout<<"strlen求得长度:" << strlen(a) << endl;
    cout << "sizeof求得长度:" << sizeof(a) << endl;

在这里插入图片描述
④数组计算长度: 不管是几维数组,都只能省略第一维。

相关文章
|
17天前
使用指针访问数组元素
【10月更文挑战第30天】使用指针访问数组元素。
30 3
|
16天前
使用指针访问数组元素
【10月更文挑战第31天】使用指针访问数组元素。
29 2
|
25天前
|
算法 索引
单链表题+数组题(快慢指针和左右指针)
单链表题+数组题(快慢指针和左右指针)
29 1
|
1月前
|
存储
如何使用指针数组来实现动态二维数组
指针数组可以用来实现动态二维数组。首先,定义一个指向指针的指针变量,并使用 `malloc` 为它分配内存,然后为每个子数组分配内存。通过这种方式,可以灵活地创建和管理不同大小的二维数组。
|
1月前
|
存储
如何通过指针数组来实现二维数组?
介绍了二维数组和指针数组的概念及其区别,详细讲解了如何使用指针数组模拟二维数组,包括定义与分配内存、访问和赋值元素、以及正确释放内存的步骤,适用于需要动态处理二维数据的场景。
|
1月前
|
存储 算法 C语言
C语言:什么是指针数组,它有什么用
指针数组是C语言中一种特殊的数据结构,每个元素都是一个指针。它用于存储多个内存地址,方便对多个变量或数组进行操作,常用于字符串处理、动态内存分配等场景。
|
1月前
魔法指针 之 二级指针 指针数组
魔法指针 之 二级指针 指针数组
19 1
|
1月前
|
C语言
无头链表二级指针方式实现(C语言描述)
本文介绍了如何在C语言中使用二级指针实现无头链表,并提供了创建节点、插入、删除、查找、销毁链表等操作的函数实现,以及一个示例程序来演示这些操作。
25 0
|
2月前
|
存储 人工智能 C语言
C语言程序设计核心详解 第八章 指针超详细讲解_指针变量_二维数组指针_指向字符串指针
本文详细讲解了C语言中的指针,包括指针变量的定义与引用、指向数组及字符串的指针变量等。首先介绍了指针变量的基本概念和定义格式,随后通过多个示例展示了如何使用指针变量来操作普通变量、数组和字符串。文章还深入探讨了指向函数的指针变量以及指针数组的概念,并解释了空指针的意义和使用场景。通过丰富的代码示例和图形化展示,帮助读者更好地理解和掌握C语言中的指针知识。
|
3月前
|
C语言
【C初阶——指针5】鹏哥C语言系列文章,基本语法知识全面讲解——指针(5)
【C初阶——指针5】鹏哥C语言系列文章,基本语法知识全面讲解——指针(5)