C语言小白养成计划五:数组

1.引入——学习数组之前,我们保存一个数,都会定义一个变量:

int a;//保存一个整数

double b;//保存一个小数

char c;//保存一个字符

......

如果需要保存N个整数、小数、字符,怎么办?一个个得保存显然是行不通的,这时候就该数组出手了。

2.一维数组

2.1 语法格式

类型说明符 数组名[整型表达式];

类型说明符:指定数组元素的类型,任意c语言合法类型都可以。

数组名: 和变量一样,数组也有一个名字,符合c语言标识符的规定。

整型表达式 :指定数组中元素的个数(之前的c语言标准规定该表达式中不能有变量,后面的标准

允许该表达式中出现变量,但是不能初始化

int n = 10;

int a[n];//可以

int a[n] = {1,2,3....};//不可以

例如:

int a[10];//定义了一个数组,有10个元素,每个元素都是int类型,所以分配了 4*10 字节内存

double b[5];//定义了一个数组,有5个元素,每个元素都是double类型,这里分配了 5*8 字节内存

......

2.2 一维数组元素在内存的存放顺序是存放在连续的内存地址空间。

2.3怎么表示数组中的某个元素:下标法

数组名[下标]//下标:整数范围 [0,n-1] (n表示数组元素个数)

见图

练习:

定义一个数组 int a[10];

依此从键盘输入10个数字,为数组a的各个元素赋值

#include<stdio.h>

int main()
{
    int a[10];
    
    int i;
    for(i=0;i<10;i++)//验证数组元素存储是连续并且按顺序的
    {
        printf("%p    ",&a[i]);//这里打印输出的是地址(%p)
    }
    
    
    for(i=0;i<10;i++)//依次输入10个整数给数组元素赋值
    {
        scanf("%d",&a[i]);
    }
    
    
    for(i=0;i<10;i++)//输出数组元素
    {
        printf("%d ",a[i]);
    }
    printf("\n");
    return 0;
}

2.4 一维数组初始化 (定义数组的时候给数组元素初始值),数组的初始化要用 {}

(1) 数组元素全部初始化

int a[5] = {10,6,23,100,68};//定义了一个数组a,有5个元素,值分别初始化为 10,6,23,100,68

int a[5];

a = {1,2,3,4,5};//错误的

(2) 可以只对前面部分元素初始化

后面的元素采取默认值(int类型默认值为0 double类型默认值 0.0 char类型的默认值'\0'..)

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

a[0] ~ a[4] 分别初始化为 1,2,3,4,5,而a[5] ~ a[9] 都采取默认值0

(3) 如果对全部元素初始化,定义数组时,可以省略数组元素个数

如:

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

可以省略元素个数,编译器会根据{}里面的数值个数反推元素个数,[ ]里会自动补充6

(4) char 类型的数组初始化

char c[5] = {'a','b','c','d','e'};这里因为没有'\0'作为结束标志 所以它是没有指定长度的,后面会细说。

char c[6] = {'a','b','c','d','e'}; //c[5]保存的是 '\0'

还有一种简洁的特殊写法

char c[6] = "abcde"; //这种初始化的效果和上面的效果完全一样, c[5]保存的是 '\0'

练习:

定义一个数组,元素类型为int,为其初始化,再求该数组所有元素之和、最小值和最大值

"打擂台"思路,先假设某个元素是目标元素,然后依次和后面的元素进行比较(打擂台)

int main()
{
int a[10] = {1,2,3,4,5,6,10,21,100,50};

int sum = 0;
int i;
int min = a[0];
int max = a[0];
for(i=0;i<10;i++)
sum += a[i];

for(i=1;i<10;i++)
{
if(a[i] < min)
{
min = a[i];
}


if(a[i] > max)
{
max = a[i];
}
}

printf("数组元素之和:%d\n",sum);
printf("数组最小值为:%d,最大值为:%d\n",min,max);
return 0;
}

练习:

计算斐波拉契数列前15项之和,1 1 2 3 5 8 ...:从第三项开始的数为前两项之和。

先求前15项每一项的值,再循环相加即可

int a[15] = {1,1};
int i;
for(i=2;i<15;i++)//从第三项开始,等于前两项之和
{
a[i] = a[i-1] + a[i-2];//依次计算 a[2]~a[14]的值
}

int sum = 0;
for(i=0;i<15;i++)
{
sum+=a[i];
}

printf("前15项之和为%d\n",sum);

练习:

给定一个一维数组(元素类型是Int),判断该数组元素是否递增

如果递增打印 YES 否则打印NO

int a[10] = {3,4,5....};
递增
a[0] < a[1] < a[2] < a[3] < a[4] < a[5] < a[6] < a[7] < a[8] < a[9]
int flag = 0;

for(i=0;i<9;i++)//注意:防止数组下标越界
{
if(a[i]>=a[i+1])
{
printf("NO\n");
flag = 1;
break;//只要 a[i]>=a[i+1]成立一次,就说明不是递增,打印NO,并且break
}
}

if(flag == 0) //if(i==9)
printf("YES\n");

练习:

给定一个升序的一维数组,查找是否存在某个元素,如果存在打印YES 不存在打印NO

int a[10] = {5,10,14,20,25,30,37,50,100,200};
int x;
scanf("%d",&x);
int i;
for(i=0;i<10;i++)
{
if(a[i] == x)
{
printf("YES\n");
break;
}
}

if(i==10)
{
printf("NO\n");
}

如果上面的数组中有1000000个元素,最坏的情况需要查找1000000次,效率不高,优化算法:

“二分查找法/折半查找法” (使用这种方法的前提是有序)

思路:每次都和中间元素做比较,比中间元素大(排除了前面一半数据),比中间元素小(排除了后面一半数据),相等 就是找到了

#include<stdio.h>
int main()
{
    int a[10000];
    int i;
    for(i=0;i<10000;i++)
    {
        a[i] = i*2;
    }

    int x;
    scanf("%d",&x);//输入要查找的元素
    
    int begin = 0;
    int end = 10000-1;
    int mid = (end - begin)/2 + begin; //也可以写为:(end+begin)/2,前面那个方便理解
    int count = 0;
    
    while(begin<=end)// begin>end说明范围不存在了,结束循环
    {
        count ++;
        if(x == a[mid])//和中间元素做比较
        {
            printf("YES,下标为%d\n",mid);
            break;
        }
        else if(x > a[mid])//排除了 mid及前面的所有元素    [mid+1, end]   
        {
            begin = mid+1;
            mid = (end - begin)/2+ begin;
        }
        else//排除了 mid及后面的所有元素    [begin, mid-1]  
        {
            end = mid-1;
            mid = (end - begin)/2+ begin;
        }
        
    }
    
    if(begin>end)
    {
        printf("NO\n");
    }

    printf("一共比较了%d次\n",count);
    return 0;
}

还有很多种关于排序的算法,下一章将会做出详解。

3,二维数组:类似数学上的矩阵,有行和列

定义语法:

类型说明符 数组名[行大小][列大小];

行大小,列大小:整形表达式(之前是不能写变量的)

元素个数: 行大小*列大小

类型说明符:每个元素的类型

比如:

int a[3][4];

3行4列共12个元素,每个元素都是int类型

内存分布:

连续按顺序存储

怎么表示数组中的某个元素:下标法

a[i][j](0<=i<N 0<=j<M 其中N为行大小,M为列大小)

一个三行4列的二位数组可以这样表示:

int a[3][4];

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]

练习:

定义一个二维数组,元素类型为int,依次从键盘输入给各个元素赋值,

再打印验证

int a[3][3];
int i,j;
for(i=0;i<3;i++)
{
for(j=0;j<3;j++)
{
scanf("%d",&a[i][j]);
}
}

for(i=0;i<3;i++)
{
for(j=0;j<3;j++)
{
printf("%d ",a[i][j]);
}
printf("\n");
}

二维数组初始化

用{}

int a[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};

int a[3][4] = {{1,2,3,4},{5,6,7,8},{9,10,11,12}};

int a[3][4] = {1,2,3,4,5,6,7,8,9,10};//a[2][2] = 0 a[2][3] = 0

int a[3][4] = {{1,2,3},{5,6},{9,10,11}};//a[0][3]=0 a[1][2]=0 a[1][3]=0 a[2][3]=0

//有些情况,行大小可以省略,根据后面的初始值的个数自动推导出来。列大小永远不能省略

int a[][4] = {1,2,3,4,5,6,7,8,9,10};

练习:

定义一个二维数组并初始化,元素类型为int。求“山顶元素”的个数

“山顶元素”:比周围(上下左右)的元素都要大

10 20 80

9 90 70

30 10 8

80,90,30都是山顶元素

#include<stdio.h>
int main()
{
    int a[3][3] = {
        10, 20 ,80 ,
        9 , 90 ,70 ,
        30, 10 ,8
    };
    
    int count = 0;
    int i,j;
    for(i=0;i<3;i++)
    {
        for(j=0;j<3;j++)
        {
            if((i==0 || a[i][j] > a[i-1][j])   //利用惰性运算
                && (i==2 || a[i][j] > a[i+1][j])
                && (j==0 || a[i][j] > a[i][j-1])
                && (j==2 || a[i][j] > a[i][j+1])
                )
            {
                count++;
            }
            
        }
    }
    
    printf("count=%d\n",count);
    return 0;
}

练习:

打印杨辉三角的前10行

1

1 1

1 2 1

1 3 3 1

1 4 6 4 1

1 5 10 10 1

.........

#include<stdio.h>
int main()
{
    int a[15][15] = {0};
    
    int i,j;
    for(i=0;i<15;i++)
    {
        a[i][0] = 1;//第一列所有元素都为1
        a[i][i] = 1;//斜对角所有元素都为1
    }
    
    for(i=2;i<15;i++)//行
    {
        for(j=1;j<i;j++)
        {
            a[i][j] = a[i-1][j] + a[i-1][j-1];
        }
    }
    
    
    for(i=0;i<15;i++)
    {
        for(j=0;j<=i;j++)
        {
            printf("%4d    ",a[i][j]);
        }
        printf("\n");
    }
    
    return 0;

}

5,字符数组

数组元素类型是 char ,基本语法也满足前面讲的数组的所有语法

比如:

char c[5] = {'a','b','c','d','e'};

访问元素下标法 : c[0] c[1] ...c[4]

有一些和其他类型数组不一样的地方。如:

初始化可以这么做:

char c[6] = "abcde";//最后一个元素是系统自动补 '\0'

c语言中可以用字符数组来表示一个字符串,字符串:一串以'\0'字符结尾的字符集合

字符串长度:'\0'之前的字符个数(不包括'\0'本身,它是字符串的结束符)

char c[6] = "abcde"; //数组c有6个元素,字符串c的长度是5

char c[5] = {'a','b','c','d','e'};//数组c有5个元素,字符串c的长度不确定的

char c[] = "abcde";//数组c有6个元素,后面有一个'\0',字符串c的长度是5

char c[] = {'a','b','c','d','e'};//数组c有5个元素,字符串c的长度不确定的

char c[6] = {'a','b','c','d','e'};//数组c有6个元素,c[5]默认为'\0',字符串c的长度是5

char c[5]={“abcde”}; “abcde"占用空间是6字节,超出c的长度了

当你想把字符数组当做字符串使用时,必须要明确其长度。在明确其长度时,遍历字符数组比遍历其他类型的数组多了一种方法.

int a[10] = {1,2,3,4,5,6,7,8,9,10};

for(i=0;i<10;i++)

{

printf("%d ",a[i]);

}

char c[6] = "abcde";

for(i=0;i<5;i++)//可以像其他数组一样使用循环语句遍历数组元素

{

printf("%c",c[i]);

}

还可以直接使用 %s 对其进行遍历,如:

printf("%s",c);//使用%s打印时,必须明确其长度,否则会出问题的

//因为 %s打印时,是从第一个元素开始,直到遇到'\0'结束;不会管是否越界

练习:

使用字符数组保存一个字符串,然后把这个字符串中的小写字母变为大写,大写字母变为小写

char c[] = "abc12XYz";
int i;
for(i=0;i<strlen(c);i++)
{
if(c[i]>='a' && c[i]<='z')
c[i] -= 32;
else if(c[i]>='A' && c[i]<='Z')
c[i] += 32;
}
-------------------
int i=0;
while(c[i] != '\0')
{
if(c[i]>='a' && c[i]<='z')
c[i] -= 32;
else if(c[i]>='A' && c[i]<='Z')
c[i] += 32;

i++;
}
  • 2
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值