2021-09-17 C语言 数组和字符串

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] ;

行名(一维数组名)	元素a[0]	a[0][0]	a[0][1]a[1]	a[1][0]	a[1][1]a[2]	a[2][0]	a[2][1]

在内存中的存储方式(线性):
0	a[0][0]1	a[0][1]2	a[1][0]3	a[1][1]4	a[2][0]5	a[2][1]

注:
数组名代表数组起始地址,不能修改。对数组名求sizeof可以求得数组占用的总空间;行名(一维数组名)同样如此,行名是该行数组起始地址,可由sizeof求得行占用的总空间。

3.二维数组元素的引用
一般形式:

<数组名>[<下标1>][<下标2>]

二维数组初始化:
① 分行初始化
例:

int a[3][2] = {{1,2},{3,4},{5,6}} ;

值	1	2	3	4	5	6元素	a[0][0]	a[0][1]	a[1][0]	a[1][1]	a[2][0]	a[2][1]

int a [2][3] = {{1,2},{4}} ; //部分初始化

值	1	2	0	4	0	0元素	a[0][0]	a[0][1]	a[0][2]	a[1][0]	a[1][1]	a[1][2]

int a [][3] = {{1},{4,5}} ; //可省略行号初始化

值	1	0	0	4	5	0元素	a[0][0]	a[0][1]	a[0][2]	a[1][0]	a[1][1]	a[1][2]

② 按元素排列顺序初始化
例:

int a[3][2] = {1,2,3,4,5,6} ;

值	1	2	3	4	5	6元素	a[0][0]	a[0][1]	a[1][0]	a[1][1]	a[2][0]	a[2][1]

int a[3][2] = {1,2,3,4} ;

值	1	2	3	4	0	0元素	a[0][0]	a[0][1]	a[1][0]	a[1][1]	a[2][0]	a[2][1]

注:求二维数组的行数和列数
行数 = 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	a[0][0][0]2	a[0][0][1]3	a[0][1][0]……	……11	a[1][2][1]

字符数组
1.定义
字符数组是元素的数据类型为字符类型的数组
例:

char c[10] , ch[3][4] ;

2.字符数组的初始化
(1)逐个字符赋值
注:“abc”=‘a’,‘b’,‘c’,‘\0’
例:

char ch[5] = {‘H’,‘e’,‘l’,‘l’,‘o’} ;//缺少“\0”,不等价于“Hello”,是字符数组但不是字符串

值	H	e	l	l	o元素	ch[0]	ch[1]	ch[2]	ch[3]	ch[4]

char ch[5] = {‘B’,‘o’,‘y’} ;//未初始化的元素系统默认为‘\0’(0、\0、NULL等价只是形式不同)

值	B	o	y	\0	\0s元素	ch[0]	ch[1]	ch[2]	ch[3]	ch[4]

注:在用printf函数打印不含‘\0’的字符数组时,由于%s格式字符打印字符串在遇见‘\0’时才停止打印,所以会顺着地址持续打印(可能会出现乱码)直到遇见‘\0’。
(2)以字符串形式赋值
例:

char ch[6] = {“Hello”} ;
char ch[6] = “Hello” ;
char ch[] = “Hello” ;

值	H	e	l	l	o	\0元素	ch[0]	ch[1]	ch[2]	ch[3]	ch[4]	ch[5]

char fruit[][7] = {“Apple”,“Orange”,“Grape”,“Pear”,“Peach”} ;//二维字符数组初始化

fruit[0]	A	p	p	l	e	\0	\0fruit[1]	O	r	a	n	g	e	\0fruit[2]	G	r	a	p	e	\0	\0fruit[3]	P	e	a	r	\0	\0	\0fruit[4]	P	e	a	c	h	\0	\0

例:

#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Ⅱ码。
H	e	l	l	o	\0104	101	108	108	111	0

程序举例
输入一个字符串,然后将其逆序输出。(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;
}
  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值