十六、 数组
数组: 使用一段连续的存储空间,存储多个类型相同变量的构造类型
构造类型: 可以进行拆分
16.1 一维数组
只用一个下标表示的数组
格式:
存储类型 数据类型 数组名[长度];
回顾一下存储类型:
存储类型有:
static : 静态
extern : 外部
register: 寄存器
auto : 默认
再回顾一下修饰词:
修饰词:
const: 不可以修改
volatile:防止内存优化,保持内存可见性
数据类型:
数据类型:基本类型(int char float double short)
构造类型,指针类型,空类型
- 数组需要有 [ ]
使用:
在使用时:
数组名 [下标];
注意:数组的下标默认是从 0 开始的
也就是说一个长的为n的数组,其元素下标是从0到n-1.
数组在声明及初始化时示例:
此情况是在Linux下的C语言,C99
不是在Windows下,也不是C++,别抬杠,要不就自己试试,实践出真知
int arr[29];对
int arr[0];错
int arr[];错
int arr[1.5];错
int n=3;
int arr[n]={1,2,3}; 错
int arr[n]; 对
#define N 3
int arr[N];对
16.1.1 一维数组的定义及初始化
1. 全局变量未初始化时,数组的值都是0;
2. 局部变量在未初始化时,数组的值是随机值(看之前这个地址上是啥值)
3.全部初始化
int arr[4]={11,22,33,44};
4,部分初始化
int arr[4]={11};//默认剩余元素为0
int arr[4]={0};//数组清0
5,省略数组长度初始化,默认数组长度是实际元素的个数
int arr[]; //错,只定义
int arr[]={1,2,3};//对,初始化 int arr[3]
6,错误初始化
int arr[4];
arr[4]={1,2,3,4};//错的 arr[4]越界,arr[4]表示一个元素
int arr[4];
arr={1,2,3,4};//错的
内存置位函数:memset()
函数原型:
//void *memset(void *s, int c, size_t n);
//void *s: 表示数组名
//int c:初始化的值
//size_t n: 字节大小
它在置位时,是将每个字节上的内容都置位为 c的值(二的补码表示的有符号数)
16.1.2 一维数组的引用
1.数组下表从0开始,如果有n个元素,下表范围0--n-1
2.arr[0]\arr[1]...arr[n-1]:表示数组的值
3.数组的越界访问
1) 如果越界访问的空间没有被占用,可以访问,结果是随机值
2) 如果越界访问的空间被占用,存储数据不重要,可以访问,结果是随机值
3) 如果越界访问的空间被占用,存储数据重要,强行访问,则段错误
16.1.3 数组地址
一维数组数组名,表示数组的首地址,也就是第一个元素的地址。
即:arr=&arr[0]
1.数组的地址是连续的
2.数组名是常量,不可以进行自增或自减arr++\++arr\--arr\arr--
如果想要自增自减,可以先用指针指向数组名,然后自增或自减指针
int main(int argc, const char *argv[])
{
int arr[5]={11,22,33,44,55};
printf("arr=%p\n",arr);
for(int i=0;i<5;i++)
{
printf("&arr[%d]=%p\n",i,&arr[i]);
}
//arr++;//arr=arr+1 报错
return 0;
}
16.1.4 冒泡排序
1. 比较相邻的元素。如果第一个比第二个大,就交换他们两个。
对每一对相邻元素做同样的工作,从开始第一对到结尾的最后一对。
在这一点,最后的元素应该会是最大的数。
2. 针对所有的元素重复以上的步骤,除了最后一个。
3. 持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
16.1.5 简单选择排序
简单选择排序:
默认第一个值为最值
从后面找比第一个值小/大,而且是最小或最大的,实现交换
首先是找出序列中最小的,然后再找出第二小的
(也就是除了上一次找出来的元素,从剩下的元素中找出最小的)
重复去寻找直到排序完成,一般外层循环次数为 元素个数-1
简单选择排序的升序和降序:
升序:
int jdxz_up(int *arr,int n){
int min;
for(int i=0;i<n-1;i++){
min = i;
for(int j=i+1;j<n;j++){
if(arr[min]>arr[j])
min = j;
}
if(i!=min)
myswap((arr+i),(arr+min));
}
}
降序:
int jdxz_down(int *arr,int n){
int max;
for(int i=0;i<n-1;i++){
max = i;
for(int j=i+1;j<n;j++){
if(arr[max]<arr[j])
max = j;
}
if(i!=max)
myswap((arr+i),(arr+max));
}
}
我写的交换函数:
void myswap(int *a,int *b){
*a^=*b;
*b^=*a;
*a^=*b;
}
此处使用了指针进行传值,若是尚不能理解指针,就当做是数组中对应的元素就行了
注意:
内层for循环中进行比较时,一定要是和最值进行比较,千万别比错了!!!
16.2 二维数组
用两个下标表示的数组
格式:
存储类型 数据类型 数组名[行数][列数];
如:int arr[3][4];
16.2.1 二维数组的定义和初始化
1. 按行初始化
int arr[2][3]={{1,2,3},{4,5,6}} //全部初始化
int arr[2][3]={{1,0,0},{2,3,0}}; //部分初始化,剩余元素默认以0填充
int arr[][3]={{1,2,3},{4,5,6}}
2. 按列初始化
int arr[2][3]={1,2,3, 4,5,6} //全部初始化
int arr[2][3]={1,2,3,0,0,0}; //部分初始化,剩余元素默认以0填充
int arr[][3]={1,2,3, 4,0,0}
3. 错误初始化
int arr[2][]={1,2,3,4};//错误第一维不可以省略
int arr[2][3];
arr[2][3]={1,2,3,4,5,6}; //错误
int arr[2][3];
arr={1,2,3,4};//错误
16.2.2 二维数组引用
1.二维数组行列下标从0开始,m行n列:行下标:[0,m-1]
列下标:[0,n-1]
2. 按列引用
for(int i=0;i<2;i++)
{
for(int j=0;j<3;j++)
{
printf("%d\t",arr[i][j]);
}
printf("\n");
}
3.二维数组按行遍历
for(int i=0;i<2*3;i++)
{
printf("%d\t",arr[0][i]);
}
4.越界引用
1) 如果越界访问的空间没有被占用,可以访问,结果是随机值
2) 如果越界访问的空间被占用,存储数据不重要,可以访问,结果是随机值
3) 如果越界访问的空间被占用,存储数据重要,强行访问,则段错误
段错误:访问了不该访问的内存空间
16.2.3 二维数组地址
二维数组的数组名等价于第一行的地址,二维数组数组名是常量
不可以进行自增或自减,二维数组的地址连续
arr++;//会报错,数组名是常量,不可以自增
二维数组名arr的类型是是(*)[列数]
如: int arr[2][3];
它的类型为:int(*)[3]
所以在传参的时候需要写成:int (*arr)[3]
16.3 一维字符数组(注意:这玩意面试题经常出现)
存储字符类型的一维数组;
格式:存储类型 char 数组名[常量表达式];
char str[10];
字符数组:由0个多个字符组成的线性结构,就是一维数组,存储多个字符类型的容器
字符串:由0个或多个单字符组成的整体【都是用双引号括起来,字符串存在\0,所有汉字均属于字符串
字符数组存储字符串,字符串是内容,字符数组是容器
16.3.1 字符数组的定义以及初始化
1. 字符数组使用单字符初始化
char str[4]={'A','B','C','D'}//全部初始化
char str[4]={'A','B',0,0}//部分初始化,剩余元素使用'\0'-->0
char str[]={'A','B','C','D'}//省略数组长度,默认是实际元素的个数
2. 字符数组使用字符串初始化
char str[4]={"ABC"}//当使用双引号时,计算机会自动填充\0 全部初始化
char str[4]="ABC";//当字符串初始化是{}可以省略不写
char str[100]="ASD"//剩余使用\0填充
char str[]="hello";//只有初始化后才能省略数组长度。默认是6
3. 错误初始化
char str[4];
str="hello" 错误
char str[4];
str[4]="hello" //错误
16.3.2 一维字符数组的引用
1.一维数组的下表从0开始 str[0]:表示一个字符
2.单个字符引用
char str[6]="hello";
for(int i=0;i<6;i++)
{
scanf("%c",&str[i]);
}
for(int i=0;i<6;i++)
{
printf("%c",str[i]);
}
3.整个字符串整体引用,格式控制符%s
char str[]="hello\0123456"
scanf("%s",str);
printf("%s",str);//hello
gets和puts字符串输入输出:
gets:
头文件:#include <stdio.h>
格式:char *gets(char *s);
返回值:char *: 返回字符串的地址
参数:char *s 表示输入字符数组的变量名
使用格式:
char str[6];
gets(str);
gets特点:可以识别空格
puts :
格式:int puts(const char *s);
返回值:int:表示输出字符串的字符个数
参数:const char *s 表示输出字符数组的变量名
使用格式:
char str[6]="hello"
puts(str);
puts特点:自动换行
可以试下这些的输出和你想的一样不
char str[6];
//scanf:不可以输入空格
//scanf("%s",str);
//printf不存在自动换行
//printf("%s",str);
gets(str);//可以输入空格,不安全,识别不了\0
puts(str);//自带换行
16.3.4 字符数组长度和字符串长度【考点,面试题最经常出的点】
字符数组长度:计算\0 sizeof
字符串长度:不计算\0,实际字符的个数 strlen
16.4 二维字符数组
格式 : char 数组名[常量表达式1][常量表达式2];
常量表达式1 : 表示行,表示字符串的个数
常量表达式2 : 表示列,表示每个字符数组的大小
char str[4][10]; //4行10列 4个字符串,每个字符串10字节
char a; //单字符 1个字节
char arr[10]//字符数组 一个字符串 10个字节
char arr[3][10];//二维字符数组 3个字符串 每个字符串10个字节
16.4.1 定义和初始化
1. 按列初始化
char str[3][4]={{'a','b','c','d'},\
{'A','S','D','F'},\
{'1','2','3','4'}};//单字符的全部初始化
char str[3][4]={{'a','b'},\
{'A'},\
{'1','2','3'}};//单字符的全部初始化,使用\0填充
char str[][4]={{'a','b'},\
{'A'},\
{'1','2','3'}};//省略行数
2. 按行初始化
char str[3][4]={"abc","ASD","123"};
16.4.2 二维字符数组的引用
1.按行引用【常用】
char str[3][4]={"asd","ASD","123"};
//按行引用,等价于一位数组的使用方式
for(int i=0;i<3;i++)
{
printf("%s\n",str[i]);
}
2.按列引用
//按列引用
for(int i=0;i<3;i++)
{
for(int j=0;j<4;j++)
{
printf("%c",str[i][j]);
}
puts("");
}
3.特殊的字符串初始化
char str[3][5]={"abcde","ASDFG","1234"};
for(int i=0;i<3;i++)
{
printf("%s\n",str[i]);
//str[0]="abcdeASDFG1234"
//str[1]="ASDFG1234"
//str[2]="1234"
}
16.5 字符串函数
strlen
作用 : 计算字符串长度的,不计算\0
头文件 : #include <string.h>
格式 : size_t strlen(const char *s);
返回值 : size_t 等价于 unsigned long 输出格式控制符%lu %ld
参数 : const char *s --->表示字符数组变量名
使用格式 :
strlen(字符串);
字符串:可以是变量,可以是字符串常量
1. 计算字符数组变量的长度
char str[]="hello";
int len=strlen(str);//把strlen默认返回类型转换为int
printf("len=%d",len);
printf("%ld",strlen(str));
2. 计算字符串常量的长度
int len=strlen("hello");
printf("len=%d\n",len);
3. 非函数实现计算字符串长度
size_t count=0;
for(int i=0;str[i];i++)
{
count++;
}
printf("count=%lu\n",count);
size_t 类型 是unsigned long , 所以格式控制符需要用 %lu 或 %ld
strcpy
作用 : 字符串拷贝,赋值
头文件 : #include <string.h>
格式 : char *strcpy(char *dest, const char *src);
返回值 : char * 表示连接后的字符串dest
参数 : char *dest, const char *src
把src拷贝dest, src不变 dest可以改变
dest:目标字符串 src:源字符串
使用格式 :
strcpy(字符串1,字符串2);
字符串1:只能是变量
字符串2:可以是变量,可以是常量
char dest[6]="hello";
char src[]="world12345"
dest=src;--->strcpy(dest,src);
strcpy(dest,src);//把src字符串的值赋值给dest dest变src src不变
目标字符串的长度需要足够大,否则会出现乱码 或 段错误
1. 字符串1变量,字符串2变量,实现拷贝
char dest[6]="hello";
char src[]="world12345"
strcpy(dest,src);
puts(dest);
printf("%s",strcpy(dest,src));
2. 字符串1变量,字符串2常量,实现拷贝
printf("%s\n",strcpy(dest,"你好"));
3.非函数实现字符串拷贝
char str[10]="hellojh";
char str1[]= "1234";
int i;
//循环str1
for( i=0;str1[i];i++)
{
str[i]=str1[i];
}
str[i]=str1[i];//str[i]=0 str[i]='\0'
puts(str);
strcat
作用 : 字符串连接
头文件 : #include <string.h>
格式 : char *strcat(char *dest, const char *src);
返回值 : char * --->表示返回链接后的字符串
参数 : dest:目标字符串 src:源字符串,src不变 dest变
把src连接到dest的后面
使用格式 :
strcat(字符串1,字符串2)
字符串1:只能是变量
字符串2:可以是变量,可以是常量
1.字符变量连接字符变量
char dest[20]="hello";//连接是必要保证目标字符串空间足够大,否则越界
char src[]="world";
strcat(dest,src);//把src连接到dest后面 dest:helloworld src:world
puts(dest);
printf("%s",strcat(dest,src));
2. 变量连接常量
printf("%s",strcat(dest,"1234"));
3. 非函数连接
char str[20]="hello1234";
i
char str1[]="1234";
j
//循环找到str的最后一个位置
int i;
for( i=0;str[i]!='\0';i++);
//循环str1存到str的后面
int j;
for(j=0;str1[j]!='\0';j++)//循环str1
{
str[i++]=str1[j];
//i++;
}
str[i]=str1[j]
puts(str);
strcmp
作用 : 字符串比较
头文件 : #include <string.h>
格式 : int strcmp(const char *s1, const char *s2);
返回值 : int 表示字符串1 与 字符串2之间的ASCII差值,只计算第一个不同的字符
参数 : const char *s1, const char *s2 不会发生改变
使用格式 :
strcmp(字符串1,字符串2);
字符串1:可以是变量,常量
字符串2:可以是变量,常量
char s1[]="ab";
char s2[]="ab";
如果字符串1>字符串2 ASCII>0 if(s1 >s2) --->if(strcmp(s1,s2)>0)
如果字符串1<字符串2 ASCII<0 if(s1 <s2) --->if(strcmp(s1,s2)<0)
如果字符串1==字符串2 ASCII==0 if(s1 ==s2) --->if(strcmp(s1,s2)==0)
1. 变量和变量之间的比较
char s1[]="qb";
char s2[]="ab";
printf("%d\n",strcmp(s1,s2));//32
//比较s1和s2字符串的大小
if(strcmp("qb","ab")>0)
printf("s1>s2\n");
else if(strcmp(s1,s2)<0)
printf("s1<s2\n");
else if(strcmp(s1,s2)==0)
printf("s1==s2\n");
2.非函数实现字符串比较
char str1[]="12sd";
char str2[]="12ed";
int i=0;
while(str1[i]==str2[i])
{
if(str1[i]=='\0')
break;
i++;
}
if(str1[i]-str2[i]>0)
printf("%s>%s\n",str1,str2);
else if(str1[i]-str2[i]<0)
printf("%s<%s\n",str1,str2);
else
printf("%s=%s\n",str1,str2);
小作业1:
1.输出起始值到终止值之间的完美数
完美数:除本身约数和等于本身
例如:6:1 2 3 6 不计算6
1+2+3==6 是完美数
2.循环输入7为评委的分数(小数)【不允许排序计算】
计算最大和:第一大加第二大
计算最大差
计算最小和
计算最小差
3.打印图形
*******
*****
***
*
4,循环输入n个数,降序输出
- 下面是我写的,代码在图后面
1.
2.
4.
1.
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main(int argc, const char *argv[])
{
int start,end,sum;
scanf("%d",&start);
scanf("%d",&end);
for(int i=start;i<=end;i++){
sum = 0;
for(int j=1;j<i;j++){
if(i%j==0)
sum+=j;
}
if(sum == i)
printf("%d\n",i);
}
return 0;
}
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
double max_add(double*,double);
double max_sub(double*,double);
double min_add(double*,double);
double min_sub(double*,double);
double main(double argc, const char *argv[])
{
double arr[7]={0};
for(int i=0;i<7;i++)
scanf("%lf",arr+i);
printf("max_add = %lf\n",max_add(arr,7));
printf("max_sub = %lf\n",max_sub(arr,7));
printf("min_add = %lf\n",min_add(arr,7));
printf("min_sub = %lf\n",min_sub(arr,7));
return 0;
}
double max_add(double *arr,double n){
double max,max2;
int i,j=0;
for(i=0;i<n;i++)
if(i==0)
max=arr[i];
else
if(max<arr[i]){
max=arr[i];
j=i;
}
for(i=0;i<n;i++){
if(i==0){
max2 = arr[i];
if(i==j)
max2=arr[i+1];
continue;
}
if(i==j)
continue;
else if(max2<arr[i])
max2=arr[i];
}
return max+max2;
}
double max_sub(double *arr,double n){
double max,min;
for(int i=0;i<n;i++)
if(i==0)
max=min=arr[i];
else{
if(max<arr[i]){
max=arr[i];
}
if(min>arr[i]){
min=arr[i];
}
}
return max - min;
}
double min_add(double *arr,double n){
double min,min2;
int i,j=0;
for(i=0;i<n;i++)
if(i==0)
min=arr[i];
else
if(min>arr[i]){
min=arr[i];
j=i;
}
for(i=0;i<n;i++){
if(i==0){
min2 = arr[i];
if(i==j)
min2=arr[i+1];
continue;
}
if(i==j)
continue;
else if(min2>arr[i])
min2=arr[i];
}
return min+min2;
}
double min_sub(double *arr,double n){
double min=fabs(*arr);
for(int i=0;i<n-1;i++)
for(int j=i+1;j<n-1;j++)
if(min>fabs(arr[i]-arr[j]))
min = fabs(arr[i]-arr[j]);
return min;
}
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int main(int argc, const char *argv[])
{
for(int i=0;i<4;i++){
for(int j=0;j<i;j++)
printf(" ");
for(int k=0;k<(4*2-1)-2*i;k++)
printf("*");
putchar(10);
}
return 0;
}
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int scanf_arr(int*,int);
int print_arr(int*,int);
int bubble_down(int *,int);
void myswap(int*,int*);
int main(int argc, const char *argv[])
{
int n;
scanf("%d",&n);
int arr[n];
memset(arr,0,sizeof(arr));
scanf_arr(arr,n);
bubble_down(arr,n);
print_arr(arr,n);
return 0;
}
int bubble_down(int *arr,int n){
if(NULL==arr)
return -1;
for(int i=0;i<n-1;i++)
for(int j=0;j<n-i-1;j++)
if(*(arr+j)<*(arr+j+1))
myswap(arr+j,arr+j+1);
}
int scanf_arr(int *arr,int n){
if(NULL==arr)
return -1;
for(int i=0;i<n;i++)
scanf("%d",arr+i);
return 0;
}
int print_arr(int *arr,int n){
if(NULL==arr)
return -1;
for(int i=0;i<n;i++)
printf("%d ",*(arr+i));
printf("\n");
return 0;
}
void myswap(int *a,int *b){
*a^=*b;
*b^=*a;
*a^=*b;
}
小作业2
1.杨辉三角,要长得和下图那个差不多,注意数字对齐
2,输入3行4列的二维数组,计算第二大值
3,单词的逆置
“good good study”
4.实现函数atoi,(将字符串转化为数字,注意出现非数字的字符时要进行判断)
例如:输入字符串"1234"
输出:1234
提醒:sum=sum*10+str[i]-48
下面是我做的(代码在后面):
1.
2.
3.
4.
代码:
1.
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int setyanghui(int (*a)[11],int line);
int printyanghui(int (*a)[11],int line);
int main(int argc, const char *argv[])
{
int a[6][11]={0};
a[0][6]=1;
int line = sizeof(a)/sizeof(a[0]);
setyanghui(a,line);
printyanghui(a,line);
return 0;
}
int setyanghui(int (*a)[11],int line){
if(NULL==a)
return -1;
int row = 11;
for(int i=1;i<line;i++){
for(int j=0;j<row;j++)
if(j<1)
a[i][j]=a[i-1][j+1];
else if(j>row-2)
a[i][j]=a[i-1][j-1];
else
a[i][j]=a[i-1][j+1]+a[i-1][j-1];
}
return 0;
}
int printyanghui(int (*a)[11],int line){
if(NULL==a)
return -1;
int row = 11;
for(int i=0;i<line;i++){
for(int j=0;j<row;j++)
if(0==a[i][j])
printf(" ");
else
printf("%d",a[i][j]);
putchar(10);
}
return 0;
}
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
void input(int (*a)[4],int line);
void output(int (*a)[4],int line);
int get_max2(int (*a)[4],int line);
int main(int argc, const char *argv[])
{
int a[3][4]={0};
input(a,3);
get_max2(a,3);
output(a,3);
return 0;
}
void input(int (*a)[4],int line){
int row=4;
for(int i=0;i<line;i++)
for(int j=0;j<row;j++)
scanf("%d",a[i]+j);
}
void output(int (*a)[4],int line){
int row=4;
for(int i=0;i<line;i++){
for(int j=0;j<row;j++)
printf("a[%d][%d]=%d\t",i,j,a[i][j]);
putchar(10);
}
}
int get_max2(int (*a)[4],int line){
int max,max_l=0,max_r=0,max2,max2_l=0,max2_r=0,row=4;
for(int i=0;i<line;i++){
for(int j=0;j<row;j++){
if(0==i&&0==j)
max=a[i][j];
else if(max<a[i][j]){
max=a[i][j];
max_l=i;
max_r=j;
}
}
}
for(int i=0;i<line;i++){
for(int j=0;j<row;j++){
if(0==i&&0==j){
max2=a[i][j];
if(i==max_l&&j==max_r)
max2=a[i][j+1];
}
else if(max2<a[i][j]){
if(i==max_l&&j==max_r)
continue;
else{
max2=a[i][j];
max2_l=i;
max2_r=j;
}
}
}
}
printf("第二大的数为:%d\n",max2);
printf("它在第%d行,第%d列\n",max2_l+1,max2_r+1);
return max2;
}
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
char *swapstr(char *s);
int main(int argc, const char *argv[])
{
char s[128]={"good good study"};
swapstr(s);
puts(s);
return 0;
}
char *swapstr(char *s){
char *p=s,*s1=s;
s1+=strlen(s)-1;
while(s1>s){
*s^=*s1;
*s1^=*s;
*s^=*s1;
s1--;
s++;
}
char *s2 = p;
s1=s=p;
for(;;s++){
if(' '==*s||'\0'==*s){
s1=s-1;
while(s1>s2){
*s2^=*s1;
*s1^=*s2;
*s2^=*s1;
s1--;
s2++;
}
if('\0'==*s)
break;
s1=s2=s+1;
}
}
return p;
}
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
#include<math.h>
int myatoi(const char *nptr);
int main(int argc, const char *argv[])
{
char s[128];
gets(s);
printf("%d\n",myatoi(s));
return 0;
}
int myatoi(const char *nptr)
{
for(int i=0;'\0'!=*(nptr+i);i++){
if(*(nptr+i)>'9'||*(nptr+i)<'0')
return -1;
}
char c;
int num = 0, sum = 0, i = 0, j = 0;
while (*(nptr + i))
{
i++;
}
for (i--; i >= 0; i--, j++)
{
c = *(nptr + i);
num = c - '0';
sum += (num * pow(10, j));
}
return sum;
}