首页 > 其他分享 >C语言基础8数组

C语言基础8数组

时间:2024-08-03 16:54:29浏览次数:16  
标签:arr int 基础 C语言 char 数组 printf sizeof

什么是数组

数组是相同类型,有序数据的集合。

数组的特征

  • 数组中的数据被称为数组的元素,是同构的
  • 数组中的元素存放在内存空间里  

衍生概念:下标(索引)

  • 下标或索引代表了数组中元素距离第一个元素的偏移位置
  • 数组中元素的地址值,下标越大,地址值越大。(每一块内存空间都有一个独有的内存地址)
  • 数组的下标是从0开始的。

一维数组

定义

类型说明符 数组名 [数组容量]

  说明:

  • 数组的类型说明符由数组中的元素来决定,也就是元素使什么类型,数组就是什么类型
  • 数组名也是标识符,我们所说的数组【名】,大家可以理解为数据类型是数组的变量【名】
  • 数组容量也可以叫做常量表达式,举例:
    int ages[10]
    int lcd[1024*768]

类型:代表了数组中元素的类型

容量:数组中能存储多少个元素,数组容量可以是一个常量、常量表达式,还可以是符号常量,但必须是整型。

深入理解:

  • 定义一个数组,相当于申请了一个可以容纳所指定元素数量的内存单元。所申请的内存单元是连续的
  • 定义一个数组,相当于定义了多个匿名变量,这些变量可以通过数组名[下标]来标识。

数组元素的访问

原则:数组中的元素不能一次性访问所有元素,只能一个一个的访问

访问方式:

数组名 [下标];

举例:

//定义一个容纳10个元素的int数组
int arr[10];
//给数组的第一个元素赋值
arr [0] = 89;
//访问数组的第一个元素
int a = arr[0];

//错误示范
int b = arr[10];//error,下标越界异常

注意:数组元素的访问一定不能越界。

案列:

/* 
需求:一维数组案例-引用数组元素。利用循环给数组元素a[0]~a[9]赋值0~9,并且逆序输出 
*/ 
#include <stdio.h> 
int main() 
{ 
// 创建一个数组 
int arr[10]; 
// 使用for循环给数组赋值 
for(int i = 0;i < 10;i++) 
{ 
arr[i] = i; 
}
// 逆序输出 
// 我们通过循环将数组中的元素一个个取出来,称之为遍历 
for(int j = 9;j >= 0;j--) 
{ 
printf("%d ",arr[j]); 
}
printf("\n"); // 纯粹换行 
return 0; 
} 

数组的初始化

定义数组的同时,用指定数据来给对应元素赋值。

简化数组定义后,需要对元素一一赋值操作。

语法规则:

类型 数组名[容量] = {常量1,常量2,常量3...};

注意事项:

  • 数组可以部分初始化:也就是可以给数组中前几个元素初始化,未被初始化的元素,系统将自动初始化,如:0;如果定义数组时未指定数组容量,则系统会根据初始化元素的个数来决定数组容量
//1.如果只给数组前几个元素初始化,后续剩余元素会自动完成初始化,比如赋值0
int arr[10] = {1,2,3,4,5}//等价于以下写法
int arr[10] = {1,2,3,4,5,0,0,0,0,0}

//2.如果定义数组时未定义数组容量,根据初始化元素个数来决定容量
int arr[]={1,2,3,4,5}//等价于以下写法
int arr[5]={1,2,3,4,5}

衍生概念:

  • 柔性数组:柔性数组的概念是在C99标准,针对结构体的最后一个成员可以是一个未指定大小的数组;
广义简单理解:数组容量待定或者待确定的数组,举例: int arr[] = {1,2,3,4,5}

面试题:

在不知道数组类型的情况下,如何确定数组元素的个数
int length = sizeof(arr) / sizeof(arr[0])

说明:

1. arr 就是我们计算的数组本身, sizeof(arr) 用来计算该数组中总的字节大小。 2. sizeof(arr[0]) 用来计算数组中一个元素所占的字节大小,因为数组中的元素类型相同,所以 计算哪一个都行。 3. sizeof(arr)/sizeof(arr[0]) 就是用数组中总的字节数除以每一个元素所占的字节数,从而得 到元素的个数。

数组典型应用

冒泡排序

  • 向后冒泡
思想: 1. 一次只排好一个数,针对 n 个数,最差情况需要 n-1 次就可以排好 2. 每次排序将相邻数据两两比较,将较大或较小的数据向后交换,等所有数据都比较完成,将较 大 / 较小的数就会出现在最后,这也是该数应该有的位置。 3. 在余下的数中,再次应用第 2 步的操作,直到只剩下一个数。
  • 向前冒泡
思想: 1. 一次只排好一个数,针对 n 个数,最差情况需要 n-1 次就可以排好 2. 每次排序假定第一个元素是最大 / 最小的,用第一个元素的后面的元素一一与第一个元素比较, 遇到较大 / 较小的和第一个元素交换,访问完数组的最后一个元素,就排好了一个数; 3. 在余下的数中,再次应用第 2 步的操作,直到只剩下一个数。
冒泡排序案例:
/*
需求:一维数组案例-冒泡排序 
*/ 
#include <stdio.h> 
int main() 
{ 
// 创建一个数组,用来存储排序的数列 
int arr[11]; 
int i,j,temp;// i:比较的轮数,j:每一轮比较的次数,temp:临时变量,用来比较时交换数据 
printf("请输入11个测试整数:\n"); 
// 计算数组的大小 
int length = sizeof(arr) / sizeof(int); // 这里 sizeof(int) 等价于 sizeof(arr[0]); 
// 通过循环录入数据 
for(i = 0;i < length; i++) 
{ 
scanf("%d",&arr[i]); 
}
printf("\n"); 
// 对数组arr使用冒泡进行排序(注意:我们使用标准冒泡,大家也可以自行补充优化版的冒泡,如鸡尾酒排序法 
等等)
// 外层循环:控制比较的轮数,因为有11个数,所以我们需要比较 length -1 轮,也就是比较10轮 
for(i = 0;i < length -1;i++) 
{ 
// 内层循环:每一轮比较的次数,每一轮比较的次数为 length - 1 - i, 3-1-0=2,3-1-1=1,3-1-2=0 
for(j = 0;j < length-1-i;j++) 
{ 
// 相邻的两个数进行比较,满足条件交换位置 
if(arr[j] > arr[j+1]) 
{ 
temp = arr[j]; 
arr[j] = arr[j+1]; 
arr[j+1] = temp; 
} 
} 
}
printf("冒泡排序后遍历数组:\n"); 
for(i = 0; i < length; i++) 
{ 
printf("%4d",arr[i]); 
}
printf("\n"); 
return 0;
}

一维数组案例

·/* 
需求:一维数组案例-从键盘输入年、月、日,计算并输出该日是该年的第几天。 
*/ 
#include <stdio.h> 
int main() 
{ 
// 定义变量:年,月,日,统计总天数,循环变量,用来遍历当前月前面的月份 
int year,month,day,sum,k; 
// 定义一个数组,用来存放1~12月每月的天数 
int t[] = {31,0,31,30,31,30,31,31,30,31,30,31};// 柔性数组 
printf("请输入年份、月份、天:\n"); 
scanf("%d,%d,%d",&year,&month,&day); 
// 因为二月比较特殊,存在平年和润年这样的因素,所以需要进行平年和润年的判断 
if((year % 4 == 0 && year % 100 != 0) || year % 400 == 0) 
{ 
t[1] = 29; // 润年 2月 29天 
}
else 
{ 
t[1] = 28; // 平年 2月 28天 
}
sum = day; // 默认记录最后一个月的天数 
// 这是该年的第几天 
for(k = 0; k < month -1;k++) 
{ 
sum += t[k]; // 叠加前几个月的天数 
}
printf("%d月%d日是%d年的第%d天。\n",month,day,year,sum); 
return 0; 
} 

二维数组

定义

二维数组本质上是一个行列式的组合,也就是说二维数组是有行和列两部分构成。二维数组数据是通过行列进行解读。 二维数组可被视为一个特殊的一维数组,相当于二维数组又是一个一维数组,只不过它的元素是一维数组。

语法

类型 数组名[行数][列数]

举例

int arr[3][3] = {{1,2,3},{4,5,6},{7,8,9}}; // 等价于以下写法 
int arr[][] = {{1,2,3},{4,5,6},{7,8,9}}; // 柔性数组 
int arr[3][] = {{1,2},{4,5,6},{7}} // 等价于 {{1,2,0},{4,5,6},{7,0,0}} 

应用场合

主要应用于数据有行列要求的情况。

特殊写法

下标可以是整型表达式,如: a[2-1][2*2-1] 下标可以是已经有值的变量或数组元素 , 如 a[2*x-1][b[3][1]] 数组元素可以出现在表达式中, 如: b[1][2]=a[2][3]/2

初始化

  • 分行给二维数组赋初值
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}; // 等价于上面的写法
  • 可对部分元素赋初值,其余未赋值部分自动填充0|\0|0.0.....
 int a[3][4] = {{1},{5,6},{9}}; // 等价于 int a[3][4] = {{1,0,0,0},{5,6,0,0},{9,0,0,0}}
  • 若对全部元素赋初值,自定义数组时可以省略第一维度的数组长度,第二维度数组的长度必须指明
int a[][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
  • 在分行赋初值时,也可以省略第一维度的长度
int a[][4] = {{1,2,3},{0},{0,10}}; // 等价于 int a[][4] = {{1,2,3,0},{0,0,0,0},{0,10,0,0}}

案列

案例一:二维数组的遍历

/**
* 案例:二维数组的遍历 
*/ 
#include <stdio.h> 
int main() 
{ 
int arr[][3] = {{1},{2,4},{5,6,7}};// 经过论证:二维数组我们必须指明第2维的数组的长度 
// 获取行元素的大小 
int length = sizeof(arr) / sizeof(arr[0]); // 如果是二维数组,第1维的长度,应该是如左侧这样获取 
printf("length:%d\n",length); 
// 遍历二维数组,需要使用双层for循环,外层遍历行,内层遍历每一行的列 
for(int row = 0;row < length;row++) 
{ 
// 获取列元素的总大小 
int len = sizeof(arr[row]) / sizeof(int); 
for(int col = 0; col < len; col++) 
{ 
// 获取列元素 
printf("%3d",arr[row][col]);// 意思是获取数组arr 第row行第col列 
}
printf("\n"); 
}
return 0; 
}

案例二:矩阵的转置

/**
* 需求:二维数组案例-矩阵的转置(就是将一个2行3列的数组转换为3行2列的数组) 
*/ 
#include <stdio.h> 
int main() 
{ 
// 准备2个数组,存放转前和转后的数据 
int arr_before[2][3] = {1,2,3,4,5,6}; 
int arr_after[3][2] = {0};// 初始化,每一列上都是0 
// 遍历arr_before 
for(int i = 0;i < sizeof(arr_before)/sizeof(arr_before[0]);i++) 
{ 
for(int j = 0;j < sizeof(arr_before[i])/sizeof(int);j++) 
{ 
// 转置 
arr_after[j][i] = arr_before[i][j]; 
} 
}
// 遍历arr_after 
for(int i = 0;i < sizeof(arr_after)/sizeof(arr_after[0]);i++) 
{ 
for(int j = 0;j < sizeof(arr_after[i])/sizeof(int);j++) 
{ 
// 输出 
printf("%4d",arr_after[i][j]); 
}
printf("\n"); 
}
return 0; 
}

案例三:准备一个int类型的二维数组,求该数组中大的最大值,以及对应的行号,列号

/**
* 需求:二维数组案例-准备一个int类型的二维数组,求该数组中大的最大值,以及对应的行号,列号 
*/ 
#include <stdio.h> 
int main() 
{ 
// 准备一个二维数组 
int arr[3][4] = {{1,2,3,4},{9,8,7,6},{-10,10,-5,2}}; 
// 创建变量,用保存最大值、行号、列号 
int max = arr[0][0],row=0,col=0; 
// 遍历集合 
for(int i = 0;i < sizeof(arr) / sizeof(arr[0]);i++) 
{ 
for(int j = 0;j < sizeof(arr[i]) / sizeof(arr[i][0]);j++) 
{ 
// 判断最大值 
if(arr[i][j] > max) 
{ 
max = arr[i][j]; 
row = i; 
col = j; 
} 
} 
}
printf("max=%d,row=%d,col=%d\n",max,row,col); 
return 0; 
}

字符数组

概念

元素类型为 char 字符型的数组,字符数组往往是用来存储字符串数据的。需要注意的一点是,我们 C 语言中的字符是字节字符。 字节字符:也就是一个字符占 1 个字节
char a = 'A' // 正确
 char b = '1' // 正确
 char c = 65 // 正确 这是ASCII码编号,对应的值是 'A'
 char d = "A" // 错误,这是字符串的写法,也是char数组的写法,char d[1] = "A" 
char e = '马' // 错误,中文一个字符超过1一个字节 

语法

char 数组名[容量]; 
char 数组名[行容量][列容量];
字符数组的语法就是之前所学一维数组和二维数组的语法,只不过数据类型是 char 而已。 注意 : 如果我们的 char 数组初始化的时候,没有完全赋完值的时候,空出来的地方使用 \0 进行填充。

案例

案例一

/**
* 需求:字符数组案例-输出一个字符串(I LOVE YOU!) 
*/ 
#include <stdio.h> 
int main() 
{ 
// 准备一个测试字符串 I LOVE YOU! 
char arr[11] = {'I',' ','L','O','V','E',' ','Y','O','U','!'}; 
// 通过一个for循环进行遍历输出 
for(int i = 0;i < sizeof(arr)/sizeof(char);i++) 
{ 
printf("%c",arr[i]); 
}
printf("\n"); 
return 0; 
} 

案例二

/**
* 需求:字符数组案例-输出一个用字符组成的菱形图案 
*/ 
#include <stdio.h> 
int main() 
{ 
// 准备数据 
char arr[5][5] = {{' ',' ','*',' ',' '},{' ','*',' ','*',' '},{'*',' ',' ',' ','*'},{' 
','*',' ','*',' '},{' ',' ','*',' ',' '}}; 
// 遍历数组 
for(int i = 0;i < sizeof(arr)/sizeof(arr[0]);i++) 
{ 
for(int j = 0;j < sizeof(arr[i])/sizeof(char);j++) 
{ 
// 打印菱形 
printf("%c",arr[i][j]); 
}
// 内层循环每结束一轮,就是一行 
printf("\n"); 
}
printf("\n"); 
return 0; 
} 

字符串和字符串结束标志

说明

字符数组的多样表示

我们的 char 数组可以以数组的方式一个个输出每个字符;我们的 char 数组也可以以字符串的方式整体进行输出所有字符。具体如下面案例:
/* 
需求:字符数组->字符串 
*/ 
#include <stdio.h> 
int main() 
{ 
// 字符串第1种表示: 
char s1[] = {'h','e','l','l','o',' ','w','o','r','l','d'}; 
// 字符串第2种表示: 
char s2[] = {"hello world"}; 
// 字符串第3种表示: 
char s3[] = "hello world"; 
// 测试,使用字符串方式打印,这样就不用一一遍历 
printf("%s\n",s1); 
printf("%s\n",s2); 
printf("%s\n",s3); 
return 0; 
} 

字符串的基础操作

字符串输入

  • scanf("%s",数组名)

案例:

/*
* 需求:字符数组-字符串的输入输出 
*/ 
#include <stdio.h> 
int main() 
{ 
// 创建一个变量,用来存放人的名字 
char name[20]; 
printf("请输入您的姓名:\n");
scanf("%s",name);// 如果是字符串,这里不是变量地址,是变量名 
printf("您的姓名是:%s\n",name); 
return 0; 
} 
注意:采用 scanf 进行字符串输入,要求字符串中不能存在空格,否则字符串遇到空格会结束。
  • fgets( 数组名 , 数组容量, stdin);
说明:采用 fgets 进行字符串输入,可获取所有输入的字符串,包含 \n ,在实际的字符串处理时,我们可能需要处理 \n 案例:
/*
* 需求:字符数组-字符串的输入输出 
*/ 
#include <stdio.h> 
int main() 
{ 
// 创建一个变量,用来存放人的名字 
char name[20]; 
printf("请输入您的姓名:\n"); 
fgets(name,sizeof(name)/sizeof(char),stdin);// 输入,返回地址 
puts(name);// 输出 
return 0; 
} 
注意: 1. 如果输入的字符串不包含 空格 和 换行 ,可以使用 scanf() | fgets(); 2. 如果输入的字符串需要包含 空格 和 换行 ,只能使用 fgets(); 3. 经过对比,我们发现,在字符串的输入中, fgets() 更好;

字符串输出

  • puts( 数组名 )
案例:
/*
* 需求:字符数组-字符串的输入输出 
*/ 
#include <stdio.h> 
int main() 
{ 
// 创建一个变量,用来存放人的名字 
char name[20]; 
printf("请输入您的姓名:\n"); 
scanf("%s",name); 
puts(name);// 输出 问题?字符串如何拼接 
printf("您的姓名是:%s\n",name); 
return 0; 
} 
  • printf("%s", 数组名 );
案例:
/*
* 需求:字符数组-字符串的输入输出 
*/ 
#include <stdio.h> 
int main() 
{ 
// 创建一个变量,用来存放人的名字 
char name[20]; 
printf("请输入您的姓名:\n"); 
scanf("%s",name); 
printf("您的姓名是:%s\n",name); 
return 0; 
} 

字符串拼接

  • strcat( 数组名 ," 需要拼接的字符串 ")
注意: 需要引入 #include <string.h> 案例:
/*
* 需求:字符数组-字符串的输入输出 
*/ 
#include <stdio.h> 
#include <string.h> 
int main() 
{ 
// 创建一个变量,用来存放人的名字 
char name[20]; 
printf("请输入您的姓名:\n"); 
fgets(name,sizeof(name)/sizeof(char),stdin);// 输入,返回地址 
puts(strcat(name," 跑着!"));// 拼接 
return 0; 
} 

字符串拷贝

  • strcpy( 数组名 , 字符串 )
注意:需要引入 <string.h> 库 说明:这个方法适合给字符串赋值用
char str[16] = "马杰克" // 初始化,正确
 char str[16]; str[16] = "马杰克" // 赋值,错误
 char str[16]; strcpy(str,"马杰克") // 赋值,正确,结果:马杰克

案例:

/*
* 需求:字符数组-字符串的输入输出 
*/ 
#include <stdio.h> 
#include <string.h> 
int main() 
{ 
// 创建一个变量,用来存放人的名字 
char name[20]; 
printf("请输入您的姓名:\n"); 
scanf("%s",name); 
strcpy(name,"你好"); 
printf("%s\n",name);// 输出 
return 0; 
} 

字符串比较

  • strcmp( 字符串 1, 字符串 2);
注意: 1. 需要引入 <string.h> 2. 返回的结果是 boolean 案例:
/*
* 需求:字符数组-字符串的输入输出 
*/ 
#include <stdio.h> 
#include <string.h> 
int main() 
{ 
// 创建一个变量,用来存放人的名字 
char username[20]; 
printf("请输入您的账户:\n"); 
scanf("%s",username); 
if(strcmp(username,"admin")) 
{ 
printf("账户输入错误!\n"); 
}
else 
{ 
printf("账户输入正确!\n"); 
}
return 0; 
}

获取字符串长度

  • strlen( 字符串 )
注意: 1. 需要 <string.h> 2. 返回字符串长度 案例:
/*
* 需求:字符数组-字符串的输入输出 
*/ 
#include <stdio.h> 
#include <string.h> 
int main() 
{ 
// 创建一个变量,用来存放人的名字 
char username[20]; 
printf("请输入您的账户:\n"); 
scanf("%s",username); 
// 获取字符串长度 
unsigned long len = strlen(username); 
if(strcmp(username,"admin")) 
{ 
printf("账户输入错误!%lu\n",len); 
}
else 
{ 
printf("账户输入正确!%lu\n",len); 
}
return 0; 
} 

标签:arr,int,基础,C语言,char,数组,printf,sizeof
From: https://blog.csdn.net/m0_69147706/article/details/140839024

相关文章

  • C语言基础7循环结构
    什么是循环        代码的重复执行,就叫做循环。循环的分类无限循环:程序设计中尽量避免无限循环。(程序中的无限循环必须可控)有限循环:循环限定循环次数或者循环的条件循环的构成循环体循环条件当型循环的实现while语法:while(循环条件){循环语句;}......
  • C语言基础6分支结构
    分支结构分支结构:又被称之为选择结构概念选择结构:根据条件成立与否,选择相应的操作条件建构关系表达式:含有关系运算符的表达式(<,>,>=,<=,!=,==)逻辑表达式:含有逻辑运算符的表达式(&&,||,!),往往用来构建复杂的符合条件:比如:常量/变量:值是否非0,取值(0|1)注意:类似以下写法,没有意义......
  • C++ 面向对象基础-构造函数
    目录1.构造函数1.1基本使用1.2函数参数默认值1.3构造初始化列表 1.4隐式调用构造函数2.拷贝构造函数2.1概念2.2浅拷贝2.3深拷贝3.析构函数1.构造函数1.1基本使用构造函数是一种特殊的成员函数,用于创建对象时初始化,写法上有以下要求:●函数名称必......
  • C++入门基础
    1.C++的第一个程序当然C++有⼀套自己的输入输出,严格说C++版本的helloworld应该是这样写的。 2.命名空间2.1namespace(命名空间)的价值在C/C++中,变量、函数和后面要学到的类都是大量存在的,这些变量、函数和类的名称将都存在于全局作用域中,可能会导致很多冲突。使用命名......
  • C语言运算符优先级口诀
    口诀内容(优先级自上而下递减;由逗号分隔的,优先级自左到右递减。)圆方括号,箭头句号。单目增减非反负,针强址长,从右。乘除求模,加减,位移,大小,等不等。位与异或,逻辑与或。条件赋值均右。真逗。解释(斜体字是补全;加粗字是对整行的说明;代码块即是所对应操作符。)圆括号()方括号[]......
  • 函数名冲突导致的C语言“conflicting types”编译错误
    快速解答:啊,看来你也遇到了“conflictingtypes”——类型冲突编译错误。如果你不是遇到:循环引用而没有用宏定义来解决。声明或定义在调用后面。声明和定义冲突。.h.gch未更新。那么我想告诉你,你可跟我一样忘了C语言不支持“函数重载”,即你的函数名不能重复。所......
  • C语言运算符优先级口诀
    口诀内容(优先级自上而下递减;由逗号分隔的,优先级自左到右递减。)圆方括号,箭头句号。单目增减非反负,针强址长,从右。乘除求模,加减,位移,大小,等不等。位与异或,逻辑与或。条件赋值均右。真逗。解释(斜体字是补全;加粗字是对整行的说明;代码块即是所对应操作符。)圆括号()方括号[]......
  • 【Java基础】02变量和数据类型
    变量一个数据存储空间的表示不同数据存入具有不同内存地址的空间,相互独立,内存地址不好记,通过变量名可以简单快速地找到数据。变量命名规则包含数字、字母、下划线、$不能以数字开头,不能是纯数字英文命名,要有意义帕斯克命名法(驼峰命名法)大骆驼:HelloWorld首字母大写,一般......
  • LeetCode面试150——238除自身以外数组的乘积
    题目难度:中等默认优化目标:最小化平均时间复杂度。Python默认为Python3。目录1题目描述2题目解析3算法原理及代码实现3.1左右乘积列表参考文献1题目描述给你一个整数数组nums,返回数组answer,其中answer[i]等于nums中除nums[i]之外其余各元素的乘积......
  • 一天速通顺序结构(0基础,软件“Dev-c++”需自己下载)
    今天浅浅带大家速通顺序结构,话不多说,上干货!1,cout语句我们都知道,任何程序都会用到输出,那该怎么实现输出呢,代码实现:#include<iostream>usingnamespacestd;intmain(){cout<<"字符串";cout<<endl;return0;}其中"#include<iostream>"是头文件,起到声明输入输出......