Day5 数组和字符串
数组概述
① 构造数组类型之一。
② 数组是具有一定顺序关系的若干个变量的集合,组成数组的各个变量称为数组的元素。
③ 数组中各元素的数据类型要求相同,用数组名和下标确定。数组可以是一维的也可以是多维的。
一维数组
1.定义
所谓一维数组是指只有一个下标的数组,它在计算机的内存中是连续存储的。C语言中,一维数组的说明一般形式如下:
<存储类型> <数据类型> <数组名> [<表达式>]
例:
int a[6] ;
数组名表示内存首地址是地址常量。sizeof(数组名)是数组占用的总内存空间。编译时分配连续的内存空间,内存字节数=数组元素个数*sizeof(元素数据类型)
注:
① C语言对数组不作越界检查,使用时注意下标(数组根据下标访问)
int a[5] ; a[5] = 10 ;//越界,但编译时不报错,执行时会报错
② 关于用变量定义数组维数
int i = 15 ; int a[i] ;
2.一维数组的使用
(1)数组必须先定义后使用
(2)只能逐个引用数组元素,不能一次引用整个数组
(3)数组元素表示形式:数组名[下标] 其中,下标可以是常量或者整型表达式
例:
int a[10] ;
//printf(“%d”,a) ;//错误输出方式
for( j = 0 ; j < 10 ; j ++ ) {
printf(“%d\t”,a[j]) ;
}//正确输出方式
3.一维数组的初始化
初始化方式:在定义数组时,为数组元素赋初值
int a[5] = {1,2,3,4,5} ;
a[1] = 100 ;//不属于初始化
说明:
① 数组不初始化,其元素为随机值
② 对static数组元素不赋初值,系统会自动赋值为0
③ 可以只给前部分元素赋值
例:
static int a[5] ; //a[0] = 0 ; a[1] = 0 ; a[2] = 0 ; a[3] = 0 ; a[4] = 0 ;
int a[5] = {6,2,3} ; //a[0] = 6 ; a[1] = 2 ; a[2] = 3 ;
int a[3] = {6,2,3,5,1} ; //超出容量
int a[] = {1,2,3,4,5,6} ; //编译系统根据初值个数确定数组维数
注:
求数组元素个数:sizeof(数组名)/sizeof(数据类型)
4.程序举例:冒泡排序
重复的走访要排序的数列,一次比较两个元素的大小,如果顺序错误就交换。走访数列的工作是重复地进行直到没有元素再需要交换,也就是该数列已经排序完成。
#include <stdio.h>
int main(int argc, char *argv[])
{
int a[] = {3, 4, 17, 8, 31, 2, 9, 15}, n, i, j;
int t;
n = sizeof(a) / sizeof(int);
for (i = 0; i < n-1; i++) {
for (j = 0; j < n-1-i; j++) {
if (a[j] > a[j+1]){//0---
t = a[j];
a[j] = a[j+1];
a[j+1] = t;
}
}
}
for (i = 0; i < n; i++)
printf("%d ", a[i]);
puts("");
return 0;
}
二维数组
1.定义
一般形式:
<数据类型> <数组名> [<常量表达式1>][<常量表达式2>]
声明时列数(常量表达式2)不能省略,行数(常量表达式1)可以省略。
例:
int a[3][4] ; float b[2][5] ; int c[2][3][4] ;
//元素个数 = 行数 * 列数
2.数组元素的存放顺序
数组按顺序存放且行序优先,因为数组在内存中的存储是一维的线性存储关系。
例:
int a[3][2] ;
在内存中的存储方式(线性):
注:
数组名代表数组起始地址,不能修改。对数组名求sizeof可以求得数组占用的总空间;行名(一维数组名)同样如此,行名是该行数组起始地址,可由sizeof求得行占用的总空间。
3.二维数组元素的引用
一般形式:
<数组名>[<下标1>][<下标2>] ;
二维数组初始化:
① 分行初始化
例:
int a[3][2] = {{1,2},{3,4},{5,6}} ;
int a [2][3] = {{1,2},{4}} ; //部分初始化
int a [][3] = {{1},{4,5}} ; //可省略行号初始化
② 按元素排列顺序初始化
例:
int a[3][2] = {1,2,3,4,5,6} ;
int a[3][2] = {1,2,3,4} ;
注:求二维数组的行数和列数
行数 = sizeof(数组名)/sizeof(行名)
列数 = sizeof(行名)/sizeof(数据类型)
示例:
#include <stdio.h>
int main(int argc, char *argv[])
{
//int a[2][3] = {{1, 6, 9}, {2, 8, 5}};
//int a[2][3] = {{1, 6}, {2}};
//int a[][3] = {{1, 6}};
//int a[3][3] = {{1}, {2, 3}, {4}};
//int a[3][] = {{1}, {2, 3}, {4}};//不能省略列!!
int i, j;
for (i = 0; i < 3; i++) {
for (j = 0; j < 3; j++)
printf("%d ", a[i][j]);
putchar('\n');
}
return 0;
}
4.案例一:打印杨辉三角前十行
1
1 2
1 3 3 1
1 4 6 4 1
……
① 先打印十行十列的1
② 只显示下三角的值(行号>=列号的数)
③ 调整数值(第一列a[i][0] = 1,其余a[i][j] = a[i-1][j-1] + a[i-1][j])
#include <stdio.h>
int main(int argc, char *argv[])
{
int a[10][10] = {{0}};
int i, j;
for (i = 0; i < 10; i++) {
a[i][0] = 1;
for (j = 1; j <= i; j++)
a[i][j] = a[i-1][j-1] + a[i-1][j];
}
for (i = 0; i < 10; i++) {
for (j = 0; j <= i; j++)
printf("%-8d ", a[i][j]);
putchar('\n');
}
return 0;
}
案例二:
有一个二维数组的矩阵,要求输出其中值最大的元素以及它的行号和列号。
#include <stdio.h>
int main(int argc, char *argv[])
{
int a[2][3] = {{2, 5, 8}, {21, 56, 9}};
int i, j, row, column;
row = column = 0;
for (i = 0; i < 2; i++) {
for (j = 0; j < 3; j++) {
if (a[row][column] < a[i][j]) {
row = i;
column = j;
}
}
}
for (i = 0; i < 2; i++) {
for (j = 0; j < 3; j++)
printf("%5d ", a[i][j]);
putchar('\n');
}
printf("max=%d %d %d\n", a[row][column], row, column);
return 0;
}
多维数组
具有两个或两个以上下标的数组称为多维数组
例:
int c[2][3][2] ;
字符数组
1.定义
字符数组是元素的数据类型为字符类型的数组
例:
char c[10] , ch[3][4] ;
2.字符数组的初始化
(1)逐个字符赋值
注:“abc”=‘a’,‘b’,‘c’,‘\0’
例:
char ch[5] = {‘H’,‘e’,‘l’,‘l’,‘o’} ;//缺少“\0”,不等价于“Hello”,是字符数组但不是字符串
char ch[5] = {‘B’,‘o’,‘y’} ;//未初始化的元素系统默认为‘\0’(0、\0、NULL等价只是形式不同)
注:在用printf函数打印不含‘\0’的字符数组时,由于%s格式字符打印字符串在遇见‘\0’时才停止打印,所以会顺着地址持续打印(可能会出现乱码)直到遇见‘\0’。
(2)以字符串形式赋值
例:
char ch[6] = {“Hello”} ;
char ch[6] = “Hello” ;
char ch[] = “Hello” ;
char fruit[][7] = {“Apple”,“Orange”,“Grape”,“Pear”,“Peach”} ;//二维字符数组初始化
例:
#include <stdio.h>
int main(int argc, char *argv[])
{
char fruit[][20] = {"banana", "apple", "strawmerry", "watermelen"};
int i, j, n, m;
n = sizeof(fruit) / sizeof(fruit[0]);
m = sizeof(fruit[0]) / sizeof(char);
for (i = 0; i < n; i++) {
for (j = 0; j < m; j++)
putchar(fruit[i][j]);
putchar('\n');
}
return 0;
}
字符串
C语言中没有字符串变量,而是用字符数组处理字符串。字符串结束标志‘\0’。
例:“Hello”共5个字符,但在内存中占6个字节,字符串长度为5,且内存存放字符的ASCⅡ码。
程序举例
输入一个字符串,然后将其逆序输出。(strlen()计算字符串长度,而sizeof(数组名)/sizeof(数据类型)是求数组占用的总空间)
① 数据不变,逆序输出
#include <stdio.h>
#include <string.h>
#define N 20
int main(int argc, char *argv[])
{
//char arr[] = "welcome";
char arr[N] = {0};
int i, n;
printf("Please input a string:");
gets(arr);
n = strlen(arr); //n = sizeof(arr)/sizeof(char);
for (i = n-1; i >= 0; i--)
putchar(arr[i]);
putchar('\n');
return 0;
}
② 数据改变,顺序输出
#include <stdio.h>
#include <string.h>
#define N 20
int main(int argc, char *argv[])
{
char arr[N] = {0};
int i, j, n, ch;
printf("Please input a string:");
gets(arr);
n = strlen(arr);
i = 0;
j = n-1;
while (i < j) {
ch = arr[i];
arr[i] = arr[j];
arr[j] = ch;
i++;
j--;
}
puts(arr);
return 0;
}
字符串函数
C库中实现了很多字符串处理函数
需引用头文件<string.h>
几个常用的字符串处理函数:
① 求字符串长度的函数strlen
② 字符串拷贝函数strcpy
③ 字符串连接函数strcat
④ 字符串比较函数strcmp
1.字符串长度函数strlen
格式:strlen(字符数组名)
功能:计算字符串长度
返值:返回字符串实际长度,不包括‘\0’在内
例:
对于以下字符串s,求strlen(s)的值
char s [10] = {‘A’,‘O’,‘B’,‘c’,‘\0’,‘D’,‘\0’,‘E’} ; //值为4
char s[] = “\t\v\\\0will\n” ; //注意转义字符‘\t’‘\v’‘\\’等,值为3
char s[] = “\x69\141\n” ; //\xhh表示十六进制数代表的符号,\ddd表示八进制数代表的符号。例如:\x69 = ‘i’,\141 = ‘a’
2.字符串拷贝函数strcpy
格式:strcpy (字符数组1,字符数组2)
功能:将字符串2拷贝到字符串1中
返值:返回字符数组1的首地址
说明:字符数组1必须足够大;拷贝时‘\0’一同拷贝
例:
char src[] = “makeru” ;
char dest[30] ;
strcpy(dest,src) ;
//相当于↓
n = strlen(src) ;
while( i <= n ){
dest[i] = src[i] ;
i++ ;
}
3.字符串连接函数strcat
格式:stract(字符数组1,字符数组2)
功能:把字符数组2连接到字符数组1后面
返值:返回字符数组1的首地址
说明:字符数组1必须足够大;连接前两串均以‘\0’结束,连接后字符串1的‘\0’取消,新字符串后加‘\0’
例:
char dest[30] = “www.makeru” ;
char src[] = “.com.cn” ;
strcat(dest,src) ;
注:两个字符数组必须均为字符串,原因暂理解为存储地址连续时strcat函数读取两个‘\0’作为结束标志。
4.字符串比较函数strcmp
格式:strcmp(字符串1,字符串2)
功能:比较两个字符
比较规则:对两个字符串从左向右逐个字符比较(ASCⅡ码值),直到遇到不同字符或‘\0’为止
返值:返回int型整数:
① 若字符串1<字符串2,返回负整数-1
② 若字符串1>字符串2,返回正整数1
③ 若字符串1==字符串2,返回0
例:
char s1[] = “ad” ;
char s2[] = “abc” ;
n = strcmp(s1,s2) ; //n=1
5.其他字符串函数或字符函数的用法
(1)strncpy(p,p1,n)复制指定长度字符串
例:
char src[] = “makeru” ;
char dest[30] = “.com.cn” ;
strncpy(dest,src,4) ;
puts(src);
puts(dest);
输出结果:
makeru make.cn
(2)strncat(p,p1,n)附加指定长度字符串
例:
strncat(dest,src) ;
输出结果
.com.cnmake
(3)strcasecmp(p,p1)忽略大小写比较字符串
例:
char s1[] = “QUIT” ;
char s2[] = “quit” ;
n = strcasecmp(s1,s2) ; // n==0
(4)strncmp(p,p1,n)比较指定长度字符串
例:
char s1[] = “quit” ;
char s2[] = “quit\n” ;
n = strncmp(s1,s2,4) ; //n==0
(5)strchr(p,c)在字符串p中查找指定字符c
返回值为查找后第一个出现的目标字符在字符串中出现的位置地址
strrchr(p,c)查找字符串中出现的最后一个字符c
例:
char s1[] = “abas$+d$f” ;
int ch = ‘$’ ;
printf(“%p%p%p\n”,s1,strchr(s1,ch),strrchr(s1,ch)) ; //打印对应地址
printf(“%d %d\n”,strchr(s1,ch)-s1,strrchr(s1,ch)-s1) ; // 4 6
(6)strstr(p,p1)查找字符串,返回子串出现的地址
例:
char S[] = “How are you” ;
char subs[] = “are” ;
printf(“%d\n”,strstr(S,subs)-S) ; //4
(7)isalpha()检查是否为字母字符
isupper()检查是否为大写字母字符
islower()检查是否为小写字母字符
isdigit()检查是否为数字(0~9)
注:需包含头文件<ctype.h>
例:
#include <stdio.h>
#include <ctype.h>
int main(int argc, char *argv[])
{
int ch;
while ((ch = getchar()) != EOF) {
if (isalpha(ch)) {
if (isupper(ch))
printf("Upper:%c\n", ch);
if (islower(ch))
printf("Lower:%c\n", ch);
}
if (isdigit(ch))
printf("Digit:%d %c\n", ch-'0', ch);
putchar(ch);
}
return 0;
}
(8)toupper()将小写字母转换为大写字母
tolower()将大写字母转换为小写字母
例:
#include <stdio.h>
#include <ctype.h>
int main(int argc, char *argv[])
{
int ch;
while ((ch = getchar()) != EOF) {
if (isalpha(ch)) {
if (isupper(ch)) {
ch = tolower(ch);
}
else {
ch = toupper(ch);
}
printf("%c\n", ch);
}
}
return 0;
}