数组基本概念
概念:具有一定顺序的若干变量的集合
定义格式:
存储类型 数据类型 数组名[元素个数]
例:int arr[5];
数组名:代表数组的首地址(地址常量),不能为左值,不能被重新赋值
访问元素:数组名[下标],下标的范围:0 ~ n-1
n:元素个数
arr[0]:访问第一个元素
arr[3]:访问第四个元素
修改数组里面的元素:数组名[下标]=新值
注意不要越界,数组越界可能不会报错,需要自己注意
特点:
- 数据类型相同,元素的数据类型要和数组的数据类型一致
- 内存连续
- 数组名[下标]--->变量名 数组内的元素--->变量的值
注意:
- 下标的范围:0 ~ n-1
- 数组名命名需要符合标识符的命名规则
- 在同一个函数中,数组名不能与其他变量名相同
一维数组
定义格式
存储类型 数据类型 数组名[元素个数]
例:int arr[5];
数组名:代表数组的首地址(地址常量),不能为左值,不能被重新赋值
访问元素:数组名[下标],下标的范围:0 ~ n-1
n:元素个数
arr[0]:访问第一个元素
arr[3]:访问第四个元素
修改数组里面的元素:数组名[下标]=新值
注意不要越界,数组越界可能不会报错,需要自己注意
初始化
全部初始化:
int arr[3]={1,2,3}; //1 2 3
部分初始化:未初始化部分值为0
int arr[3]={1,2} //1 2 0
未初始化:未初始化的部分为随机值,需要单独赋值,不能整体赋值
int arr[3]; //随机值
引用
- 先定义后引用
- 每次只能访问一个是数组元素,想引用数组中的所有元素需要循环遍历
- 引用时防止数组的越界,虽然编译器有时不会报错
- 对数组中每一个元素的地址的打印用%p格式
内存连续
元素 大小 地址
数组大小
sizeof(数组名);
大小=数据类型的大小 * 元素个数;
int a[6]; // 4*6 = 24
float buf[3] = {1.2, 3,1}; // 4*3 = 12
double c[2]; // 8*2 = 16
计算数组中元素个数:sizeof(数组名)/sizeof(数组的数据类型)
遍历数组
将循环变量作为下标,循环遍历数组
清零函数
bzero
#include <strings.h>
void bzero(void *s,size_t n);
功能:将数组的内存空间设置为 0
参数:s:要清空的数组的首地址
n:数组的大小(字节)
返回值:无
用法:bzero(数组名,sizeof(数组名));
memset
#include <strings.h>
void *memset(void *s,int c,size_t n);
功能:将数组的内存空间设置为 0
参数:s:要清空的数组的首地址
c:你要设置的值
n:数组的大小(字节)
返回值:清空的数组的首地址
用法:memset(数组名,设置的值,sizeof(数组名));
字符数组
概念:字符数组的里面存放的都是字符 实际存放的是字符串
定义格式
char str[3]={'a','b','c'}; //逐个字符赋值
char str[]={'a','b','c'}; //逐个字符赋值
char str[]="hello"; //使用字符串赋值 sizeof(str)=6(系统添加\0)
注意:字符串赋初值时经常省略数组的长度(\0),以后面实际赋值为准,要注意数组越界问题
输入输出
输入
1) 直接使用%s输入
char buf[32];
scanf("%s", buf); // 从终端输入字符串到数组 buf,但是遇到空格或者\n 会结束
sacnf("%[^\n]", buf); // 从终端输入字符串到数组 buf,直到遇到\n 结束
2) gets
char *gets(char *s);
功能:从终端输入字符串
参数:目标字符串的首地址
返回值:目标字符串的首地址
注意:谨慎使用、使用时会报警告,不检查数组越界
输出
1) printf("%s\n", buf); // 遇到 \0 就会结束
2) puts
int puts(const char *s) ;
功能:向终端输出字符串
参数:要输出字符串的首地址
返回值:输出字符的个数
计算字符串的实际长度
1) 循环遍历,找到\0位置
2) strlen
#include<string.h>
功能:计算字符串的实际长度(不包括\0)
参数:要计算的字符串的首地址
返回值:字符串的实际个数
3)sizeof和strlen的区别:
- sizeof 是关键字;strlen 是函数
- sizeof 计算数据所占空间字节大小;stelen 计算字符串的实际个数
- 在元素个数省略的情况下,sizeof 包括\0,strlen 不包括 \0
- 在这情况下计算字符串长度 sizeof 比 strlen 大 1
排序
冒泡排序
排序思想:相邻的两个数进行比较(两两比较),如果前者大与后者则交换位置(每一轮排序完成确定一个元素的位置)
例:int arr[]={5,4,3,2,1};
// 冒泡排序
#include <stdio.h>
int main(int argc, char const *argv[])
{
int arr[] = {5, 4, 3, 2, 1};
int i, j, temp;
for (j = 0; j < sizeof(arr) / sizeof(int) - 1; j++) // 比较的轮数
{
for (i = 0; i < sizeof(arr) / sizeof(int) - 1 - j; i++) // 每一轮比较的次数
{
if (arr[i] > arr[i + 1])
{
temp = arr[i];
arr[i] = arr[i + 1];
arr[i + 1] = temp;
}
}
}
for (i = 0; i < 5; i++)
{
printf("%d", arr[i]);
}
printf("\n");
return 0;
}
分析:
第一轮:j=0
5 4进行比较:4 5 3 2 1
5 3进行比较:4 3 5 2 1
5 2进行比较:4 3 2 5 1
5 1进行比较:4 3 2 1 5
第二轮:j=1
4 3进行比较:3 4 2 1 5
4 2进行比较:3 2 4 1 5
4 1进行比较:3 2 1 4 5第三轮:j=2
3 2进行比较:2 3 1 4 5
3 1进行比较:2 1 3 4 5第四轮:j=3
2 1进行比较:1 2 3 4 5
选择排序
排序思想:在n个数中找最小值的下标暂时存储,然后和正确的位置交换(每一轮排序完成确定一个元素的位置)
例:int arr[] = {5, 3, 2, 4, 1};
// 选择排序
#include <stdio.h>
int main(int argc, char const *argv[])
{
int arr[] = {5, 3, 2, 4, 1};
int i = 0, j, temp;
while (i < sizeof(arr) / sizeof(int) - 1) // 排序的轮数
{
int min = i; // 待排序数组中最小值下标
for (j = i + 1; j < sizeof(arr) / sizeof(int); j++) // 每一轮比较的次数
{
if (arr[j] < arr[min]) // 判断当前值与最小值的大小关系
{
min = j; // 更新最小值下标
}
}
// 通过交换确定最小值位置
if(min!=i)
temp = arr[i];
arr[i] = arr[min];
arr[min] = temp;
i++;
}
// 输出数组内容
for (i = 0; i < sizeof(arr) / sizeof(int); i++)
{
printf("%d", arr[i]);
}
printf("\n");
return 0;
}
分析:
找到最小值下标,与 arr[i]交换
第一次
begin 0
5 3 2 4 1 min 0
5 3 2 4 1 min 1
5 3 2 4 1 min 2
5 3 2 4 1 min 2
5 3 2 4 1 min 4
arr[4]与 arr[0]交换
1 3 2 4 5
第二次
begin 1
1 3 2 4 5 min 1
1 3 2 4 5 min 2
1 3 2 4 5 min 2
1 3 2 4 5 min 2
arr[2]与 arr[1]交换
1 2 3 4 5
二维数组
定义格式
存储类型 数据类型 数组名[行数][列数];
例:int arr[2][3];
访问元素
数组名[行下标][列下标] (下标范围:0 ~ 行数-1,0 ~ 列数-1)
arr[0][0]:第一行第一列的元素
arr[1][2]:第二行第三列的元素
注意:行数可以省略,但是列数不能省略
int arr[][3];
二维数组元素个数 = 行数 * 列数
数组名
a:表示第一行的首地址
a+1:表示第二行的首地址
a[0]:表示第一行第一列的首地址
a[1]:表示第二行第一列的首地址
初始化
1) 全部初始化:
int arr[2][3] = {1, 2, 3, 4, 5, 6}; // 1 2 3 4 5 6 顺序赋值
int arr[2][3] = { {1, 2, 3}, {4, 5, 6} }; // 1 2 3 4 5 6 按行赋值
2) 部分初始化:
int arr[2][3] = {1, 2, 3, 4}; // 1 2 3 4 0 0 顺序赋值
int arr[2][3] = {{1, 2}, {4, 5}}; // 1 2 0 4 5 0 按行赋值
3) 未初始化:
int arr[2][3]; // 随机数,需要单独赋值
数组大小
大小= 数据类型大小 * 行数 * 列数;
sizeof(数组名);
遍历数组
双层for:外层循环控制行,内层循环控制列
#include <stdio.h>
int main(int argc, char const *argv[])
{
int i, j, sum = 0;
int arr[3][3];
printf("input:\n");
for (i = 0; i < 3; i++)//控制行数
{
{
for (j = 0; j < 3; j++)//控制列数
scanf("%d", &arr[i][j]);
}
}
for (i = 0; i < 3; i++)//控制行数
{
for (j = 0; j < 3; j++)//控制列数
{
printf("%d ", arr[i][j]);//输出每一个元素
sum += arr[i][j];
}
printf("\n");//换行
}
printf("sum=%d\n", sum);
printf("%p", arr);//arr打印数组首地址
printf("%p", arr[0]);//arr[0]打印第一行第一列元素的地址
return 0;
}
数组编程练习
示例1:数组求和
#include <stdio.h>
int main(int argc, char const *argv[])
{
int arr[3];
int i;
int sum=0;
for (i = 0; i < sizeof(arr)/sizeof(int); i++)
{
scanf("%d", &arr[i]);
}
for (i = 0; i < sizeof(arr)/sizeof(int); i++)
{
sum+=arr[i];
printf("%d", arr[i]);
printf(" %ld", sizeof(arr[i]));
printf(" %p\n",&arr[i]);
}
printf("sum=%d\n",sum);
printf("%ld\n",sizeof(arr));
return 0;
}
示例2:计算斐波那契数列的前15项并逆序输出(1 1 2 3 5 8 13 21)
#include <stdio.h>
#include <string.h>
int main(int argc, char const *argv[])
{
int arr[15];
int i, j;
arr[0] = 1;
arr[1] = 1;
int n = sizeof(arr) / sizeof(int);
for (i = 2; i < n; i++)
{
arr[i] = arr[i - 1] + arr[i - 2];
// printf("%d\n", arr[i]);
}
// bzore(arr,sizeof(arr));
// memset(arr,0,sizeof(arr));
for (i = 14; i >= 0; i--)
{
printf("%d ", arr[i]);
}
return 0;
}
示例3:3行4列的矩阵,输出其最大值及所在行和列
#include <stdio.h>
int main(int argc, char const *argv[])
{
int i, j, max, h, l;
int arr[3][4];
printf("input:\n");
for (i = 0; i < 3; i++)
{
{
for (j = 0; j < 4; j++)
scanf("%d", &arr[i][j]);
}
}
max = arr[0][0];
for (i = 0; i < 3; i++)
{
for (j = 0; j < 4; j++)
{
if (arr[i][j] > max)
{
max = arr[i][j];
h = i + 1;
l = j + 1;
}
}
}
printf("%d\n", max);
printf("%d %d\n", h, l);
return 0;
}
示例4:在终端输入大写字母,小写字母,数字,空格,分别输出他们的个数
#include <stdio.h>
int main(int argc, char const *argv[])
{
int n = 0, m = 0, k = 0, b = 0;
char buf[32] = {}; // 初始化
// scanf("%s", buf); // 遇到空格或\n结束
scanf("%[^\n]", buf); // 遇到\n结束
for (int i = 0; i < 32; i++)
{
if (buf[i] == ' ')
{
k++;
}
else if (buf[i] >= 'a' && buf[i] <= 'z')
{
n++;
}
else if (buf[i] >= 'A' && buf[i] <= 'Z')
{
m++;
}
else if (buf[i] >= '0' && buf[i] <= '9')
{
b++;
}
}
printf("%s\n", buf);
printf("空格:%d 小写字母:%d 大写字母:%d 数字:%d", k, n, m, b);
return 0;
}
示例5:实现字符串大小写转换
#include <stdio.h>
#include <string.h>
int main(int argc, char const *argv[])
{
char buf[32] = {};
printf("input str:\n");
scanf("%[^\n]", buf);
int i;
int n = strlen(buf);
for (i = 0; i < n; i++)
{
if (buf[i] >= 65 && buf[i] <= 90)
{
buf[i] += 32;
}
else if (buf[i] >= 97 && buf[i] <= 122)
{
buf[i] -= 32;
}
}
printf("%s\n", buf);
return 0;
}
示例6:将字符串中所有下标为奇数位置上的字母转换为大写,若该位置上不是字母,则不转换
#include<stdio.h>
#include<string.h>
int main(int argc, char const *argv[])
{
char s[32];
printf("input:\n");
scanf("%s",s);
int i;
for(i=0;i<strlen(s);i++)
{
if(i%2!=0&&s[i]>=97&&s[i]<=122)
{
s[i]=s[i]-32;
}
}
printf("%s\n",s);
return 0;
}
示例7:将hello字符串倒置
#include <stdio.h>
#include <string.h>
int main(int argc, char const *argv[])
{
char buf[32] = "hello";
char ch;
int i, n = strlen(buf);
for (i = 0; i < n/2; i++)
{
ch = buf[i];
buf[i] = buf[n - i - 1];
buf[n - i - 1] = ch;
}
printf("%s\n", buf);
return 0;
}
示例8:
求s=a+aa+aaa+aaaa+…,其中a是一个数字,n表示a的位数,a和n由键盘输入
输出内容:s=2+22+222+2222+22222=24690
#include <stdio.h>
#include <string.h>
int main()
{
int s = 0, a, n;
int buf[32] = {};
printf("输入数字:\n");
scanf("%d", &a);
printf("输入几个数相加:\n");
scanf("%d", &n);
buf[0] = a;
printf("s=%d",a);
for (int i = 1; i < n; i++)
{
buf[i] = 10 * buf[i - 1] + a;
printf("+%d", buf[i]);
s += buf[i];
}
s += a;
printf("=%d\n", s);
return 0;
}