chapter 4 数组


C语言程序设计

chapter 4 数组

1. 数组的概念

数组:同类数据的集合

定义方式:类型 数组名[数组大小];
数组中的变量称为为数组元素,由于数组中每个元素都有下标,因此数组元素也称为下标变量。
数组下标取值从0开始,使用数组时下标不能越界,同一数组的所有数组元素在内存中占用一片连续的存储单元。

例如:int num[10]; //表示定义一个数组num,最多能存放10个int类型的元素。
解析:定义了一个名字为 num 的数组,它有10个元素,每个元素都是一个int型变量,下标变量为num[0]~num[9],num数组占用了一片连续的、大小为10*sizeof(int)字节的空间。

例如:int num[10][10];//表示定义一个数组num,最多能存放10*10个int类型的元素。
像这样的用两个 [] 的定义的数组,我们称之为二维数组,同样还有三维数组,多维数组,但是需要注意的时,电脑内存分配是有限的,数组所占空间大小也是有限的。

2. 数组元素的引用

每个数组元素都是一个变量,数组元素可以表示为:数组名[下标]
其中,下标可以是任何值为整型的表达式,该表达式里可以包含变量和函数调用。引用时,下标值应在数组定义的下标值范围内。
例如:若i、j都是int型变量,则 num[5]、num[i+j]、num[i++] 都是合法的元素。

在定义一个一维数组的同时,可以给数组中的元素赋初值。
格式:类型名 数组名[元素个数]={值1,值2,……};

例如:int a[10]={0,1,2,3,4,5,6,7,8,9};
相当于:a[0]=0  a[1]=1  a[2]=2  a[3]=3  a[4]=4  ……  a[8]=8  a[9]=9

使用数组时,要注意:
(1)数组下标为正整数
(2)在定义元素个数的下标范围内使用
当在程序中把下标写成负数或者大于元素个数时,程序编译不会出错,当然结果也是错的。
(3)定义数组时使用的容量大小必须使用常数,且需要注意:
在 C语言中常量的定义为:#define N 10000
在C++中还支持:const int N=1000;但是这个方式在C语言中表示只读变量,不能等同于为常量。

3. 作用域

根据数组定义的位置,我们将数组分为全局变量和局部变量
全局变量:是指不被{}包裹起来的变量;
局部变量:是指被{}包裹起来的变量。

并且编译器会给这些数组变量初始化不同的值,具体如下:
全局变量,默认初始化为 0.
局部变量,随机初始化一个值.
局部变量,部分赋值,则未赋值部分初始化为 0.

#include<stdio.h>
#define N 100
int a[N];   //全局变量,默认初始化为 0
int b[N]={1,2,3,4,5}; //全局变量,部分赋值,其余默认初始化为 0

int main() {
    int c[N];//局部变量,随机初始化一个值
    int d[N]= {1,2,3,4,5};//局部变量,部分赋值,则未赋值部分初始化为 0
    int n=10;

    printf("a[i]:"); for(int i=0; i<=n; i++) printf("%d ", a[i]); printf("\n");
    printf("b[i]:"); for(int i=0; i<=n; i++) printf("%d ", b[i]); printf("\n");
    printf("c[i]:"); for(int i=0; i<=n; i++) printf("%d ", c[i]); printf("\n");
    printf("d[i]:"); for(int i=0; i<=n; i++) printf("%d ", d[i]); printf("\n");

    return 0;
}

输出结果:
a[i]:0 0 0 0 0 0 0 0 0 0 0
b[i]:1 2 3 4 5 0 0 0 0 0 0
c[i]:7603456 0 75 0 0 3 12260288 0 0 0 1
d[i]:1 2 3 4 5 0 0 0 0 0 0

4. 数组案例学习

【题目描述】现有 10 个数据 {0,1,2,3,4,5,6,7,8,9},将他们存储到内存中,并逆序输出。

#include<stdio.h>
int main(){
    int n=10;
    int a[10]={0,1,2,3,4,5,6,7,8,9};
    for(int i=n-1; i>=0; i--){
        printf("%d ", a[i]);
    }
    return 0;
}

【题目描述】现有 n 个整数数据,将他们存储到内存中,并逆序输出(n<=10000)。

输入样例:
5
45 12 34 89 21
输出样例:
21 89 34 12 45
#include<stdio.h>
#define N 10000
int a[N];
int main(){
    int n; scanf("%d", &n);
    for(int i=0; i<n; i++){ // [0, n-1]
        scanf("%d", &a[i]);
    }
    for(int i=n-1; i>=0; i--){// [n-1, 0]
        printf("%d ", a[i]);
    }
    return 0;
}

5. 最大值所在位置

【题目描述】输入 n 个正整数,存放在 a[1]~a[n] 中,输出最大值所在位置(n<=10000)。

输入样例:
5
1 2 6 4 5
输出样例:
3
#include<stdio.h>
#define N 10010
int a[N];
int main(){
    int n, max_a=-1, max_i=-1; scanf("%d", &n);
    for(int i=1; i<=n; i++){
        scanf("%d", &a[i]);
        if(max_a<a[i]){
            max_a=a[i];
            max_i=i;
        }
    }
    printf("%d", max_i);
    return 0;
}

6. 斐波那契数列

【题目描述】斐波那契数列指的是这样一个数列:0,1,1,2,3,5,8,13,21...
求数列的前 50 项,并按照从大到小的顺序输出。

无输入,输出样例部分如下:
50 : 7778742049
49 : 4807526976
48 : 2971215073
47 : 1836311903
46 : 1134903170
45 : 701408733
...
5 : 3
4 : 2
3 : 1
2 : 1
1 : 0
#include<stdio.h>
#define N 100
long long a[N]={0,0,1};
int main(){
    int n=50;
    for(int i=3; i<=n; i++){
        a[i] = a[i-1]+a[i-2];
    }
    for(int i=n; i>=1; i--){
        printf("%d : %lld\n", i, a[i]);
    }
    return 0;
}

7. 第几天

【题目描述】输入年、月、日,输出该天是这一年的第几天。

输入样例:2021 8 24
输出样例:236

#include<stdio.h>
int main(){
    int a[12]={31,28,31,30,31,30,31,31,30,31,30,31};
    int year,month,day; scanf("%d%d%d", &year, &month, &day);
    int ans=day;
    if(month>2){
        if(year%400==0 || year%4==0&&year%100!=0) ans++;
    }
    for(int i=0; i<month-1; i++){
        ans += a[i];
    }
    printf("%d", ans);
    return 0;
}

8. 起立与坐下

【题目描述】有n个人,编号为 1~n。
开始时,所有人都站着,接着第2个人和2的倍数的人坐下,
然后,第3个人及3的倍数的人按相反的操作(坐的人站起来,站着的人坐下),
依次类推,一共操作到第k人及k的倍数。
问最后有哪些人站着。输入n和k,输出站着的人的编号。

输入样例:7 3
输出样例:1 5 6 7

#include<stdio.h>
#define N 10010
int a[N];//0表示站着,1表示坐着
int main(){
    int n,k; scanf("%d%d", &n, &k);
    for(int i=2; i<=k; i++){
        for(int j=1; j<=n; j++){
            if(j%i==0) a[j]=!a[j];
        }
    }
    for(int i=1; i<=n; i++){
        if(a[i]==0) printf("%d ", i);
    }
    return 0;
}

9. 排序

【题目描述】输入n个数,存在数组a中,每个数都是介于0~k之间的整数,
此处k为某个整数(n<=100000,k<=1000),按从小到大的顺序,输出a数组中的数据。

输入样例:
10
2 3 1 2 4 55 3 55 3 2
输出样例:
1 2 2 2 3 3 3 4 55 55
#include<stdio.h>
#define N 1010
int a[N];
int main(){
    int n, k=1000; scanf("%d", &n);
    for(int i=1; i<=n; i++){
        int x; scanf("%d", &x);
        a[x]++; //计数思想
    }
    for(int i=0; i<=k; i++){
        for(int j=1; j<=a[i]; j++){
            printf("%d ", i);
        }
    }
    return 0;
}

10 . 二维数组

二维数组的定义格式:类型说明符 数组名[常量表达式1][常量表达式2]
例如:int a[3][4], b[5][6];
解释:定义 a为一个 3*4(3行4列)的数组,b为一个 5*6 (5行6列)的数组,且均为int类型。
用矩阵形式是在逻辑上的概念,可以形象的表示出行列关系。
在内存中,各元素是连续存放的,并不是二维的,而是线性的。

a[0][0] a[0][1] a[0][2] a[0][3]
a[1][0] a[1][1] a[1][2] a[1][3]
a[2][0] a[2][1] a[2][2] a[2][3]

b[0][0] b[0][1] b[0][2] b[0][3] b[0][4] b[0][5]
b[1][0] b[1][1] b[1][2] b[1][3] b[1][4] b[1][5]
b[2][0] b[2][1] b[2][2] b[2][3] b[2][4] b[2][5]
b[3][0] b[3][1] b[3][2] b[3][3] b[3][4] b[3][5]
b[4][0] b[4][1] b[4][2] b[4][3] b[4][4] b[4][5]

二维数组的初始化
1.分行赋值:int a[3][4]={{1,2,3,4}, {5,6,7,8}, {9,10,11,12}};
2.同行赋值:int b[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};
上述两种赋值方式均是可行的,且结果是相同的。

a,b均为:
1 2 3 4
5 6 7 8
9 10 11 12

但是,如果按照如下方式赋值会出现不同的结果:
1.分行赋值:int a[3][4]={{1,2,3,4}, {5}, {9,10,11,12}};
2.同行赋值:int b[3][4]={1,2,3,4,5,6,7,8,9,10,11,12};

a:
1 2 3 4
5 0 0 0
9 10 11 12

b:
1 2 3 4
5 6 7 8
9 10 11 12

二维数组的赋值特性与一维数组相同,全局默认为0;局部部分赋值,未赋值部分为0;局部未赋值,则随机。

11. 二维数组案例学习

【题目描述】给定正整数 n, m,以及一个 n*m 的矩阵,请按原矩阵保存并输出,
同时输出该矩阵顺时针旋转 90度后的新矩阵,
输出的原矩阵以及新矩阵之间换行,且每个数据占 5个宽度。

输入样例:
2 4
1 2 3 4
5 6 7 8
输出样例:
    1    2    3    4
    5    6    7    8

    5    1
    6    2
    7    3
    8    4
#include<stdio.h>
#define N 100
int a[N][N];
int main(){
    int n, m; scanf("%d%d", &n, &m);
    for(int i=1; i<=n; i++){
        for(int j=1; j<=m; j++){
            scanf("%d", &a[i][j]);
        }
    }

    for(int i=1; i<=n; i++){
        for(int j=1; j<=m; j++){
            printf("%5d", a[i][j]);
        }printf("\n");
    }
    printf("\n");
    for(int i=1; i<=m; i++){
        for(int j=n; j>=1; j--){
            printf("%5d", a[j][i]);
        }printf("\n");
    }
    return 0;
}

12. 杨辉三角

【题目描述】给出 n(n≤20),输出杨辉三角的前 n行。
如果你不知道什么是杨辉三角,可以观察样例找找规律
输入样例:6
输出样例:

1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
#include<stdio.h>
#define N 110
int a[N][N];
int main(){
    int n=10; scanf("%d", &n);
    a[1][1]=1;
    for(int i=2; i<=n; i++){
        for(int j=1; j<=i; j++){
            a[i][j]= a[i-1][j-1]+a[i-1][j];
        }
    }
    for(int i=1; i<=n; i++){
        for(int j=1; j<=i; j++){
            printf("%d ", a[i][j]);
        }printf("\n");
    }
    return 0;
}

13. 蛇形方阵

【题目描述】给出一个不大于 9 的正整数 n,输出 n×n 的蛇形方阵。
从左上角填上 1 开始,顺时针方向依次填入数字,如同样例所示。
注意每个数字有都会占用 3 个字符,前面使用空格补齐。

输入样例:4
输出样例:

  1  2  3  4
 12 13 14  5
 11 16 15  6
 10  9  8  7
#include<stdio.h>
int a[10][10];
int main(){
    int n; scanf("%d", &n);
    a[1][1]=1;
    int i=1, j=1, cnt=1;
    while(cnt<n*n){
        while(j+1<=n && a[i][j+1]==0){//右
            a[i][++j] = ++cnt;
        }
        while(i+1<=n && a[i+1][j]==0){//下
            a[++i][j] = ++cnt;
        }
        while(j-1>0 && a[i][j-1]==0){//左
            a[i][--j] = ++cnt;
        }
        while(i-1>0 && a[i-1][j]==0){//上
            a[--i][j] = ++cnt;
        }
    }
    for(int i=1; i<=n; i++){
        for(int j=1; j<=n; j++){
            printf("%3d",a[i][j]);
        }printf("\n");
    }
    return 0;
}

14. 字符数组

我们已经知道字符型数据是以字符的ASCII代码存储在存储单元的,一般占一个字节,由于ASCII代码也属于整数形式,因此在 C99标准中,把字符类型归纳为整型类型中的一种。
C语言中没有字符串类型,也没有字符串变量,字符串是存放在字符数组中的。

char c[11];// 定义一个大小为 11的字符数组 c
c[0]='H'; c[1]='e'; c[2]='l'; c[3]='l'; c[4]='o'; c[5]=' ';
c[6]='W'; c[7]='o'; c[8]='r'; c[9]='l'; c[10]='d';

int c[11]; //char类型本身就是以ASCII代码存储的,所以用 int也可以,但是浪费空间
c[0]='H'; c[1]='e'; c[2]='l'; c[3]='l'; c[4]='o'; c[5]=' ';
c[6]='W'; c[7]='o'; c[8]='r'; c[9]='l'; c[10]='d';

字符数组的初始化

列表初始化

char c[11]={'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'};
把11个字符依次赋值给 c[0]~c[10]这 11个元素。

char c[]={'H', 'e', 'l', 'l', 'o', ' ', 'W', 'o', 'r', 'l', 'd'};
如果没有给出数组长度,系统会自动根据初值个数确定数组长度,如上数组 c的长度会自动定位 11.

字符串常量初始化

char c[]={"c program"};
char c[]="c program"; //可以省略 {}

字符串结束标志 : '\0'
C系统在用字符数组存储字符串常量时会自动加一个 '\0' 作为结束符。
例如:"c program" 共 9个字符,字符串时存储在一维数组中的,在数组中它占 10字节,最后一个字节 '\0'是由系统自动加上去的。
字符数组并不要求它的最后一个字符为 '\0',甚至可以不包含 '\0',比如像如下写法也是合法的:

char c[9]={"c program"};

字符数组的输入输出
1.逐个输入输出:用格式符 "%c"
2.将整个字符串一次输入输出:用格式符 "%s"

char str[100];
scanf("%s", str); //不加 &, 在 C语言中 数组名代表该数组的第一个元素的地址,也就是该数组的起始地址。
printf("%s", str);
printf("%o", str); //以8进制形式输出数组的起始地址。

当然,字符数组也可以构建二维数组,甚至三维,多维,不过这一点就不多赘述了,有兴趣可以自己测试一下。

15. 字符串处理函数

注意:字符串处理函数的头文件:#include<string.h>

char str[10]="Hello World!";
puts(str); //输出字符串,puts()输出时会将 '\0'转换为 '\n'即输出完字符数组后换行
gets(str); //输入字符串,gets()返回字符数组的首地址,但是由于溢出问题在 C11已被移除

char str1[100]="Hello ", str2[]="World!";
strcat(str1, str2);//连接字符串,将 str2连接到 str1之后, 并返回 str1的首地址。(str1必须足够大)
注意:strcat连接前两个字符串都有 '\0', 连接时将 字符串 str1后的 '\0'取消,只在新串最后保留 '\0'.

strcpy(str1, str2);//复制字符串,将 str2复制到 str1中
注意:不能直接: str1="Hello "; str1=str2; 这两条语句都是不合法的。

strncpy(str1, str2, n);//复制前n个字符,将 str2的前 n个字符复制到 str1中

strcmp(str1, str2);//字符串比较,从左至右,按 单个字符的ASCII代码比较。
如果 str1 与 str2相等, return 0;
如果 str1 大于 str2, return 正整数;
如果 str1 小于 str2, return 负整数;

strlen(str);//返回字符串的实际长度

strlwr(str);//字符串大写转小写
strupr(str);//字符串小写转大写

char ch = tolower(ch);//单个字符转小写,头文件 <ctype.h>
char ch = toupper(ch);//单个字符转大写,头文件 <ctype.h>

16. 字符计数

【题目描述】给定一个字符串(长度不超过100)以及单个字符,
求该字符在字符串中出现的次数,不区分大小写。
输入格式:两行,第一行一个字符串,第二行单个字符。
输出格式:一个整数,表示该字符在字符串中出现的次数。
输入样例:

ABCabcA
a

输出样例:

3

题解:

#include<stdio.h>
#include<string.h>
#include<ctype.h>
char a[101], b;
int main(){
    scanf("%s\n%c", a, &b);
    int len=strlen(a), ans=0;
    b=tolower(b);
    for(int i=0; i<len; i++){
        a[i] = tolower(a[i]);
        if(a[i]==b) ans++;
    }
    printf("%d\n", ans);
    return 0;
}

17. 寻找字符串

【题目描述】给定两个字符串 a, b,寻找字符串 b 在字符串 a 中出现的次数,字符可重叠。
如:a="abababa", b="aba",则 b 在 a中出现的次数为 3 次。

输入格式:两行,第一行为字符串 a,第二行为字符串 b,字符串长度不大于 1000。
输出格式:一个整数,表示字符串 b 在 a 中出现的次数。

题解:

#include<stdio.h>
#include<string.h>
#define N 1010
char a[N], b[N];
int main(){
    fgets(a, 1001, stdin);//会读入\n, 也可以使用scanf("%s", a);
    fgets(b, 1001, stdin);
    int len1=strlen(a)-1, len2=strlen(b)-1;
    int ans=0;
    for(int i=0; i<len1; i++){
        bool flag=1;
        for(int j=0; j<=len2/2; j++){
            if(a[i+j]!=b[j]){
                flag=false; break;
            }
        }
        if(flag) ans++;
    }
    printf("%d\n", ans);
    return 0;
}

18. 对称字符串

题目描述:对于给定的正整数 N(N<=20), 有如下对应的对称字符串。

A[1]:A
A[2]:ABA
A[3]:ABACABA
A[4]:ABACABADABACABA
...
A[N]:...

输入格式:一个正整数 N。
输出格式:一行字符串A[N]。

题解:

#include<stdio.h>
#include<string.h>
#define N 1000000
char a[N];
int main(){
    int n, len=0; scanf("%d",&n);
    for(int i=1; i<=n; i++){
        strcat(a+len+1, a);
        a[len]='A'+i-1;
        len = strlen(a);
    }
    printf("%s\n", a);
    return 0;
}


免责声明!

本站转载的文章为个人学习借鉴使用,本站对版权不负任何法律责任。如果侵犯了您的隐私权益,请联系本站邮箱yoyou2525@163.com删除。



 
粤ICP备18138465号  © 2018-2025 CODEPRJ.COM