Download presentation
Presentation is loading. Please wait.
Published byVera Indradjaja Modified 5年之前
1
第五章 数组与指针 1 数组的简单操作 2 数组与指针 3 字符数组与字符串 4 字符串处理函数 5 数组应用举例
2
什么是数组 所谓数组是指具有相同类型的数据组成的序列,是有序集合。
第五章 数组与指针 什么是数组 所谓数组是指具有相同类型的数据组成的序列,是有序集合。 用统一的数组名来标识数组,序列中的一个数据称为数组的一个元素,数组元素通过其所在位置的序号(称为数组的下标)来区分。利用数组名和下标,就可以用统一的方式来处理数组中的每个元素。 C语言规定,数组元素的最小下标是0。 下标必须是非负整数。 第1节 数组的简单操作
3
一维数组的声明 一维数组声明的一般格式是: 类型名 数组名[ 常量表达式 ];
第五章 数组与指针 一维数组的声明 一维数组声明的一般格式是: 类型名 数组名[ 常量表达式 ]; 譬如: int Arr1[ 100 ]; 即:声明了一个名称为Arr1、类型是整型、容量是100的数组。 一个数组声明之后,应该能明确其元素的类型、名称和最大个数(即容量)。 第1节 数组的简单操作
4
一维数组的定义1 一维数组的定义包含两个操作:声明数组、对数组元素赋初值。 数组的定义有2种方式:
第五章 数组与指针 一维数组的定义1 一维数组的定义包含两个操作:声明数组、对数组元素赋初值。 声明仅是指定数组元素的类型、名称和数组元素个数(该数组的容量,一经声明不许更改)。 数组的定义有2种方式: 1 先声明后赋值 int data[10]; 若对数组仅进行了声明、没有对元素赋值,每个元素的值一般是任意的。 如果仅声明数组,那么以后就只能一个一个地赋值了。 如 int a[6]; 仅声明了一个数组,没赋初值 a[0]=1; a[2]=2; a[1]=1; a[4]=4; 这里,声明和赋值分2步进行的; a[3]、a[5]没有赋值,它的值就是任意的。 第1节 数组的简单操作
5
一维数组的定义2 2 声明的同时指定值(声明并初始化,即定义) 可以在声明的同时指定所有元素的值;如:
第五章 数组与指针 一维数组的定义2 2 声明的同时指定值(声明并初始化,即定义) 可以在声明的同时指定所有元素的值;如: int b[6]={1,3,7,2,0,8}; 此时,容量可以省略。因为通过元素值的个数可以确定其容量。如: int b[ ]={1,3,7,2,0,8}; 可以在声明的同时只指定部分元素的值,此时,容量绝对不能省略;如: int c[6]={1,3,7,2}; 数组的容量是6,仅指定4个元素的值;还有2个元素其默认值是0(只能是最后2个元素)。 第1节 数组的简单操作
6
一维数组的访问 数组元素只能一个一个地单独访问,不能整体访问。因此,一般与循环配合来进行数组元素的操作。 例:一维数组的声明、赋值及访问。
第五章 数组与指针 一维数组的访问 数组元素只能一个一个地单独访问,不能整体访问。因此,一般与循环配合来进行数组元素的操作。 例:一维数组的声明、赋值及访问。 第1节 数组的简单操作
7
二维数组 数组名后跟有2个方括号的叫二维数组。在形式上,二维数组与数学上的矩阵类似。
第五章 数组与指针 二维数组 数组名后跟有2个方括号的叫二维数组。在形式上,二维数组与数学上的矩阵类似。 由于二维数组有2个下标,必须在声明后能确定2个容量,即确定二维数组的行数和列数。第一个值是行数,第二个值是列数。行数*列数就是二维数组的容量(元素总数)。 通过二维数组的行号和列号来确定对应的唯一元素。 第1节 数组的简单操作
8
二维数组的声明 二维数组的声明: int arrB[3][4]; 由于此时对数组arrA的元素未赋值,所以它的12个元素的值是不确定的。
第五章 数组与指针 二维数组的声明 二维数组的声明: int arrB[3][4]; 由于此时对数组arrA的元素未赋值,所以它的12个元素的值是不确定的。 维数组的元素一般是按行顺序存储的。 int arrB[3][4]; 声明了一个3*4的二维数组。这些元素依次是: arrA[0][0]、arrA[0][1]、arrA[0][2]、arrA[0][3]、 arrA[1][0]、arrA[1][1]、arrA[1][2]、arrA[1][3]、 arrA[2][0]、arrA[2][1]、arrA[2][2]、arrA[2][3]。 该数组中任意元素arrA[ i ] [ j ]的存储地址等于 &arrA[0][0]+(i*4+j)*sizeof(int)。 第1节 数组的简单操作
9
二维数组的定义 若声明数组的同时进行初始化,则可以写成下面几种形式:
第五章 数组与指针 二维数组的定义 若声明数组的同时进行初始化,则可以写成下面几种形式: int arrB1[3][4]={1,2,3,4, 5,6,7,8, 9 ,10,11,12}; //① int arrB2[3][4]={ {1,2,3,4}, {5,6,7,8}, {9,10,11,12} }; //② int arrB3[ ][4]={1,2,3,4, ,6,7,8, 9,10}; //③ arrB3可通过值的个数计算出行数为3(即10除以4向上取整,等于3;只允许第一维的容量省略),数组总共有12个元素,前10个元素已明确指定值,最后2个元素的值缺省,均为0。 int arrB4[3][4]={ {1,2,3,4} , {5,6}, //该行后2个元素的值均为0 {7} //该行后3个元素的值均为0 }; //这样按行书写,清晰。 第1节 数组的简单操作
10
二维数组的访问 一般使用二重循环来对二维数组中的每个元素进行访问。
第五章 数组与指针 二维数组的访问 一般使用二重循环来对二维数组中的每个元素进行访问。 二维数组的元素是按行序依次连续存储的。可以把二维数组可以看作是一个一维数组,这个一维数组的每个元素又是一个一维数组。 int arrB4[3][4]={ {1,2,3,4} , {5,6}, {7} }; 第1节 数组的简单操作
11
第五章 数组与指针 第2节 指针
12
变量的地址 任意类型的变量,一经声明,它本身的存储地址就确定下来了。 通过地址可以直接操作内存单元,直接且高效。 如:int x;
第五章 数组与指针 变量的地址 任意类型的变量,一经声明,它本身的存储地址就确定下来了。 如:int x; x的值虽然未指定,但其存储地址是确定的,使用&x来获得。一般我们只关心x的值是多少,至于x的存储地址是多少,我们不关心、一般也不知道它是多少,更不能指定它等于多少。因为内存的管理是由操作系统负责的。 通过地址可以直接操作内存单元,直接且高效。 第2节 指针
13
指针的概念 指针是一个动态的概念,它是一种构造的类型。 声明指针
第五章 数组与指针 指针的概念 指针是一个动态的概念,它是一种构造的类型。 声明指针 如:int *p; //这样的变量声明写成 int*p;或int* p; 都是可以的 这里p的值是一个地址,且必须是一个整型数据(如整型变量)的地址。注意&p与p的差异,&p是变量p的存储地址,是确定的。 若有int x; int *p;之后,再p=&x; 则p的值就确定了,是x的存储地址,通常称:指针p指向变量x; 通过p来访问x。获取x 的值,使用*p;使用*p就是使用x。 指针的本质就是内存单元的存储地址。通过指针处理数据就是通过数据的存储地址来处理它的值。 第2节 指针
14
指针的运算 赋值:要求基类型一致。 指针的加减运算、比较运算 &、*运算 若:int i; int *pi=&i; char *pc;
第五章 数组与指针 指针的运算 赋值:要求基类型一致。 若:int i; int *pi=&i; char *pc; 则,pc=&i; 是错误的。 pc=pi;或pi=pc; 是错误的。 *pc=i; 是错误的。因为此时pc还没有确定的指向,不能对*pc赋值; pc=(char *)&i; 强制类型转换,赋值号两边的类型一致了; pi=(int*)pc; 强制类型转换,赋值号两边的类型一致了。 指针的加减运算、比较运算 int x; int *p=&x, *q ; 之后 p++; p+5; q=p; p-10; p==q;都是有意义的。 但是 p+q; p+&x; 没有意义。 &、*运算 &是取地址,*是取存储单元中的值。 第2节 指针
15
数组的物理特性 数组是一种静态的顺序存储结构。在内存中,数组的元素是按下标由小到大依次存储的。
第五章 数组与指针 数组的物理特性 数组是一种静态的顺序存储结构。在内存中,数组的元素是按下标由小到大依次存储的。 数组名是一个指针,代表数组的首地址(即开始地址),且数组一经声明,这个地址就确定下来了,不能改变(相当于一个地址常量);根据首地址、类型、下标可以计算出数组中任意一个元素的存储地址。 第2节 指针
16
第五章 数组与指针 一维数组与指针 数组名是一个地址常量。 数组一经声明后,这个地址常量就确定下来了。因此,不能试图将一个地址赋给一个数组名;数组名之间也不能相互赋值。 若有变量声明:int b[10], c[10]; int *p; 对于下面的单个语句: p=b; 意思是指针p指向数组b的开始位置(p的值等于数组b的首地址); 其等价于:p=&b[0]; 意思是指针p指向数组元素b[0]的存储位置(即b[0]的地址,这里也是b的首地址); p=&b[5]; 意思是指针p指向数组元素b[5]; p=b; printf("%d:",*p);由于此时数组b的元素还没有确定的值,使用*p就没有意义了; c=b; c=p; 这两个赋值都是错误的。 第2节 指针
17
一维数组与指针举例 指针只能指向一个基类型相同的数据。 举例: 通过数组访问 通过指针访问、 数组名类似指针访问 第五章 数组与指针
第2节 指针
18
指针的分类 按基类型来分: 按星号的个数来分: 如:int *pi; char *pc; 请尽量避免使用多级指针。
第五章 数组与指针 指针的分类 按基类型来分: 按星号的个数来分: 在声明指针变量时仅带一个星号的变量叫一级指针。 如:int *pi; char *pc; int **p; 类似这样带多个星号的叫多级指针。在这里p是二级指针,理解成p是指向一个一级指针的指针。 譬如: int **pp; int *p; int x=99; p=&x; pp=&p; 那么 **pp的值就是x的值。 请尽量避免使用多级指针。 第2节 指针
19
第五章 数组与指针 二维数组与指针 若有: int a[3][4]={{1,2,3,4},{5,6,7,8},{1,3,5,7}}; int *p; 1, 2, 3, 4, 5, 6, 7, 8, 1, 3, 5, 7 通过数组名访问 通过数组自身指针访问 通过指针访问 第2节 指针
20
第五章 数组与指针 第3节 字符数组与字符串
21
字符数组 所谓字符数组是指数组中元素的类型都是字符型的。 char a[10]; //容量为10
第五章 数组与指针 字符数组 所谓字符数组是指数组中元素的类型都是字符型的。 char a[10]; //容量为10 char b[ ]= {'a','b','2',' ','w'}; //容量为5 char c[10]={'a','b','2',' ','w'}; //后5个取默认值,ASCII码值为0,即 ‘\0’ char d[ ]={ 'a','0','b','c','5', '\0', '\0', 'd'}; //容量为8 char *pb= {'a','b','2',' ','w'}; //error char *pb= b; char *pc=&c[2]; //right 第3节 字符数组与字符串
22
字符串 含有‘\0’字符的字符数组就能构成一个字符串。 字符串是一种特殊的字符数组。可以说字符串必然是字符数组,字符数组不一定是字符串。
第五章 数组与指针 字符串 含有‘\0’字符的字符数组就能构成一个字符串。 字符串是一种特殊的字符数组。可以说字符串必然是字符数组,字符数组不一定是字符串。 譬如:char str1[ ]={ 'a', '0', 'b', 'c', '5', '\0', '\0', 'd', '9'}; 这个数组的元素个数是9。其中‘a’, ‘0’, ‘b’, ‘4’, ‘c’, ‘\0’就组成了一个字符串 这个串的长度是5,即串长为5。 串长是指字符串中实际字符的个数,不含结束标记'\0'。 字符'\0'的ASCII码值是0。因此,上面的字符数组也可以写成: char str2[ ]={ 'a', '0', 'b', 'c', '5', 0, 0, 'd', '9'}; 第3节 字符数组与字符串
23
字符串的存储 字符串的定义通常写成如下形式:
第五章 数组与指针 字符串的存储 字符串的定义通常写成如下形式: char stra[ ]={"english"};//串长是7,占8个字节 char strb[ ]= "english"; //串长是7,占8个字节,这种形式最常用 char *pstr= "english"; //一个字符指针指向一个字符串常量 字符串变量在定义时,一般不指定容量;若指定的值小了,就是错误的。如上面的两个字符数组stra、strb,方括号中的整数不能小于8,否则就是错误的。因为结束标记'\0'也要占用一个字节的存储空间。 内存中的存储如图所示。 譬如:char s1[ ]= "english"; char s2[10 ]= "english"; s1 s2 第3节 字符数组与字符串
24
理解指针 对下述定义的理解: char stra[ ]={"english"}; char strb[ ]= "english";
第五章 数组与指针 理解指针 对下述定义的理解: char stra[ ]={"english"}; char strb[ ]= "english"; 在内存中,stra数组、strb数组均占用8个字节的空间,各存储区中的值是8个字符; 可通过数组名和下标来任意操作其中的字符。 char *pstr= "english"; //一个字符指针指向一个字符串常量 通过pstr可访问字符串中的每个字符,但不能修改其中的任意字符的值。 如:psrt[2]=‘a’; 是错误的。 第3节 字符数组与字符串
25
字符数组的输入输出 使用scanf、printf和%c与循环配合进行输入输出; 使用scanf、printf和%s进行整体输入输出:
第五章 数组与指针 字符数组的输入输出 使用scanf、printf和%c与循环配合进行输入输出; 使用scanf、printf和%s进行整体输入输出: 将会被当作字符串进行操作: 在使用scanf和%s 输入字符串时,输入空格或按下Enter键,字符串的输入就结束了。这个空格字符或Enter键会自动转换成‘\0’,作为字符串的结束。即,不可能输入空格。 使用printf输出字符数组时,只有碰到‘\0’才停止输出。因此,输出结果可能与字符数组的值不一致。 例子: 数组名; 指针名; 第3节 字符数组与字符串
26
字符串的输入输出 使用scanf、printf和%s配合进行输入输出: 使用专用函数gets、puts进行输入、输出。
第五章 数组与指针 字符串的输入输出 使用scanf、printf和%s配合进行输入输出: 在使用scanf和%s 输入字符串时,输入空格或按下Enter键,字符串的输入就结束了。这个空格字符或Enter键会自动转换成‘\0’,作为字符串的结束。即,不可能输入空格。 使用printf输出字符串。 使用专用函数gets、puts进行输入、输出。 使用gets(str)输入字符串,仅在按下Enter键时,字符串的输入才结束。可输入空格。 使用puts(str) 时,相当于 printf( “%s\n”,str); 第3节 字符数组与字符串
27
第五章 数组与指针 第4节 字符串处理函数
28
字符串处理函数 常用的几个字符串函数 str1需有足够的空间、容纳连接后的新串 √ √ des必须先有确定的指向、足够的容量
29
字符串处理函数 常用的几个字符串函数 //程序c5_5.cpp //程序c5_6.cpp
30
第五章 数组与指针 第5节 数组应用举例
31
筛选法 所谓筛选法就是像筛子一样,将不满足条件的过滤掉,剩下的即是所求的。 //程序c5_7.cpp使用筛选法求2 ~ 100中的素数
32
约瑟夫问题 //程序c5_8.cpp使用筛选法求解约瑟夫问题
33
排序算法 //程序c5_9.cpp求一维数组的最小值及其下标。 //程序c5_10.cpp对一个整型数组进行“选择排序”。
34
集合运算 集合运算算法的基本思想: //程序c5_11.cpp实现两个集合的交集运算。
已知2个源数组a、b,声明目标数组c。设置3个整型变量i、j、len(指示器),开始时i=j=len=0;i、j分别指向2个源数组的第一个元素,len=0表示目标数组当前的元素个数为0。将a[i]与b[j]进行比较,决定将谁放入c[len]中,再决定i、j、len如何增加,直到处理完了a、b中所有的元素为止。 //程序c5_11.cpp实现两个集合的交集运算。
35
统计问题 //c5_12.cpp统计一个字符串中各种字母字符的个数。 //c5_13.cpp统计一个字符串中英文单词的个数。
36
5.5.6 二维数组的应用 //程序c5_14.cpp求两个矩阵的乘积。 问题分析: //程序c5_15.cpp输出如下形式的二维数组
根据数学知识,一个i*k的矩阵A与k*j的矩阵B相乘,得到的是一个i*j的矩阵C。C中的每一个元素是多个乘积的和。 //程序c5_15.cpp输出如下形式的二维数组 //程序c5_16.cpp输出如下形式的矩阵
37
5.6 小结和补充 1.指针数组 指针数组是指数组的每个元素都是指针型的。 譬如:
int a[5]={1,2,3,4,5}, b[3]={10,20,30}; int *p[4]={ a,b,&a[3],&b[1] }; 即p[0]=a,p[1]=b,p[2]=&a[3],p[4]=&b[1] 变量p就是一个指针数组,每个数组元素的值都是一个地址。但是,上面的这个赋值没有太大的意义。指针数组多用于描述字符串数组。 //程序c5_17.cpp使用指针数组。
38
5.6 小结和补充 2.指向数组的指针(又称行指针) 譬如:
int (*p)[4]; p必须指向一个列数是4的整型二维数组,否则就是错误的。p又称为行指针。*(p+i)代表着二维数组第i行的首地址。 //程序c5_18.cpp 使用指向数组的指针。
Similar presentations