C语言中的数组
- C语言中的数组 - 1 语法定义和基本概念 - 1.1 基本概念
- 1.2 一维数组的定义和引用
- 1.3 数组默认值问题
- 2.1 利用数组求斐波那契数列的前10个数,每5个数为一行输出。
- 2.3 顺序查找法,输入5个整数,将他们存入数组a中,在输入一个数x,找数字中查找是否存在这个元素,如果找到,返回这个数组的index,没找到打印 Not found
- 2.4 冒泡排序
- 2.5 选择排序
- 4.2 引用
- 4.3 二维数组在内存中的存放形式**
- 4.4 例题-练习题 - 例7-7 将一个3 x 2 的矩阵中的值存入到一个3 x 2 的二维数组中,现将矩阵输出出来,再找出其中最大值的下标将其输出。
- 例7-8 定义一个3 x 2 的二维数组a, 二维数组的值由下式给出,按照矩阵的形式输出a,a[i][j] = i + j
- 例7-9 输入一个正整数n(1< n <= 6),根据a[i][j] = i * n + j + 1;. 生成一个 n x n 的矩阵,然后将这个矩阵行列互换后输出。
- 例7-11 判断输入的字符串是否是回文数 回车结束,回文数正反都一样
C语言中的数组
1 语法定义和基本概念
1.1 基本概念
在C语言中,数组是最基本的
构造类型,前面的 整型、浮点型、字符型 都是基本数据类型。
数组中的元素在内存中连续存放,所以用数组名和下标可以唯一的确定一个数组元素。
基于以上的观点,我们可以这样去定义数组:具有相同基本数据类型的一组元素,在内存中连续存放而组成的一种数据结构
1.2 一维数组的定义和引用
int arr1[10];// 定义一个 int 型的数组,大小为10
char arr2[10];// 定义一个 char 型的数组,大小为10
float arr3[10];// 定义一个 float 型的数组,大小为10
实际上数组名是一个常量地址,用来存放内存空间的首地址
1.3 数组默认值问题
运行下面的一段代码,发现如果数组中没有指定默认值,数是随机的。所以书上例题清0是有必要的
#include <stdio.h>int main(void) {int a = 1, arr1[10];static int arr2[10];for (int i = 0; i < 10; i++){printf("%d \n",arr1[i]);}printf("------------------\n");for (int i = 0; i < 10; i++){printf("%d \n",arr2[i]);}return 0;}
1.4 一维数组的初始化
建议不省略,严格写法 如 : int arr1[10] = {1,2,3,4,5,6,7,8,9,10};
int arr1[10] = {1,2,3,4,5,6,7,8,9,10};
static int arr2[2]; // 静态数组不赋值,默认是0
static int arr3[5] = {1,2,3,4,5}; // 也是可以的
static int arr4[10] = {1,2} //这样的话 前两位元素的值为 1和2,后面8个元素的值都是 0
int arr4[10] = {1,2} //这样的话 前两位元素的值为 1和2,后面8个元素的值不确定
2.简单例题练习
2.1 电视节目投票
/* 投票情况统计 */#include <stdio.h>int main(void){int count[8]; // 电视节目-对应的类目数组int i, response;// 数组个元素存放 int 0for (i = 0; i < 8; i++){count[i] = 0;}for (i = 1; i <= 10; i++){printf("input your response (1~8): \n");scanf("%d", &response);if (response < 1 || response > 8){ // 防止数组下标越界printf("this response is bad \n");}else{count[response]++;}}printf("category----num \n");for (i = 0; i <= 8; i++){printf("%4d%4d\n", i, count[i]);}return 0;}
2.1 利用数组求斐波那契数列的前10个数,每5个数为一行输出。
#include <stdio.h>
int main(void)
{
// [1]定义一个数组存放斐波那契数列的前10个数
int arr1[10] = {1, 1};
// [2]for 循环计算出 后面的8个元素的值
for (int i = 2; i < 10; i++){
arr1[i] = arr1[i - 1] + arr1[i - 2];
}
// [3]遍历数组,满5个一换行输出
for (int i = 0; i < 10; i++){
printf("%4d", arr1[i]);
if ((i + 1) % 5 == 0) {
printf("\n");
}
}
return 0;
}
偶然发现 将printf(" 1 "); 中的双引号就会报错,猜想 C中单引号只是为了表示字符型 项 ‘A’ 这样的
2.3 顺序查找法,输入5个整数,将他们存入数组a中,在输入一个数x,找数字中查找是否存在这个元素,如果找到,返回这个数组的index,没找到打印 Not found
#include <stdio.h>
int main(void) {
int i, number, x, a[5];
int flag = 0;
printf("请输入5个整数: \n");
for ( i = 0; i < 5; i++){
scanf("%d", &number);
a[i] = number;
}
printf("请输入要查找的数x:");
scanf("%d", &x);
for ( i = 0; i < 5; i++){
if(x == a[i]){
flag = 1;
printf("找到了这个数,在数组中的下标是 %d \n",i);
break;
}
}
if (flag == 0) {
printf("没找到啊~");
}
return 0;
}
2.4 冒泡排序
原理:对一组数进行排序,两个相邻位置比较,大的数移动到右边,小的数移动到左边…
看例子理解 : [5,4,3,2,1] 进行冒泡排序的过程
+++++++++++++++
1️⃣ 5,4 => 4, 5, 3, 2, 1
2️⃣ 5 , 3 => 4, 3, 5, 2, 1
3️⃣ 5 , 2 => 4, 3, 2, 5, 1
4️⃣ 5,1 => 4, 3, 2, 1, 5
+++++++++++++++
1️⃣ 4 , 3 => 3, 4, 2, 1, 5
2️⃣ 4 , 2 => 3, 2, 4, 1, 5
3️⃣ 4 , 1 => 3, 2, 1, 4, 5
+++++++++++++++
1️⃣ 3 , 2 => 2, 3, 1, 4, 5
2️⃣ 3 , 1 => 2, 1, 3, 4, 5
+++++++++++++++
1️⃣ 2 , 1 => 1, 2, 3, 4, 5
+++++++++++++++
我们发现按照这种算法,每一轮比较都会为下一次比较较少一次比较。
第一轮 比较 n-1次, 第二轮比较 n-2 次 …. …. 最后第 n-1 轮比较 1次。然后我们将其转换为数学问题 n个数一共要比较1 + 2 + 3 + ... + (n -1) = n * (n - 1) / 2
#include <stdio.h>
int main(void) {
int i, j, arr[5] = {5, 4, 3, 2, 1};
// 外层循环控制只是第几轮比较
for (i = 0; i < 5 - 1; i++){ // 5 -1 实际上就是 数组长度-1
for (j = 0; j < 5 - (i + 1); j++){ // 每次确定了一个 ,而i的初始值是 0 ... 所以你懂的。
if (arr[j] > arr[j+1]) { // 满足条件要去实现值的互换 a= a+b; b= a- b; a= a -b;
arr[j] = arr[j] + arr[j+1];
arr[j+1] = arr[j] - arr[j+1];
arr[j] = arr[j] - arr[j+1];
}
}
}
for (i = 0; i < 5; i++){
printf("%4d", arr[i]);
}
return 0;
}
2.5 选择排序
原理:将一组数从头扫到末尾,找到最小的一个数和第一个数做交换。直到从头到尾扫描一遍。
看例子理解:[5, 4, 3, 2, 1] 进行选择排序
1️⃣ {1} , {4, 3, 2, 5} — 有序队列+1,无序队列 -1
2️⃣ {1,2 }, { }
… …
懒得写了,其实冒泡排序和选择排序的规则是,选择排序确定一个位置,然后和不同位置的元素相互比较,而冒泡排序每轮则是和相邻位置的元素相比较,位置数不断变化的。
#include <stdio.h>
int main(void)
{
int i, j, t, arr[5] = {5, 4, 3, 2, 1};
for (i = 0; i < 4; i++){
for (j = i+1; j < 5 ; j++){
if(arr[i] > arr[j]){
arr[i] = arr[i] + arr[j];
arr[j] = arr[i] - arr[j];
arr[i] = arr[i] - arr[j];
}
}
}
for (i = 0; i < 5; i++){
printf("%4d", arr[i]);
}
return 0;
}
2.6 二分查找
针对于
有序数组的一中查找方式。假设有一个size 为10的 升序数组
int arr1[10] = {1, 2 ,3, 4, 5, 6, 7, 8, 9, 10};
int x; // x 是我们要找的数
int low = 0, height = 9 ;
int mid = (low + height) / 2;
判断 array[mid] 和 x 的大小关系 ... ... 就可以进一步缩小查找的范围。直到找到这个数
当这个范围一直缩小,缩小到一个数而这个数还不是要查找的数是程序终止
#include <stdio.h>
int main(void) {
// [1]定义变量
int x, low, height, mid, arr[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
low = 0;
height = 9;
printf("Enter x: \n");
scanf("%d", &x);
// [2]开始查找
while(low <= height){
mid = (low + height) / 2;
if(arr[mid] == x){
break;
}else if (arr[mid] > x){
height = mid - 1;
}else if (arr[mid] < x){
low = mid + 1;
}
}
// [3]输出结果
if(low <= height){
printf("index = %d \n", mid);
}else{
printf("Not Found \n");
}
return 0;
}
3.思考
3.1 C语言中如何求数组的大小?
其他语言带来的参考
不像 java array.length ,
js 数组 也有 length 属性 (实际上 js中的数组用 .length 计算得到的并不一定对,这里就不写说明了 )。
php 用 count() ?
很遗憾 C语言中的数组既没有 length 属性 也没有 count() 方法
但是 C 中有这样一个方法
sizeof(), 他可以有这个变量的字节数
于是 我们是否可以求出 数组的大小?
由于 C 中的数组数据类型一致,所以嘿嘿这样sizeof(arr)/sizeof(arr[0])就可以解决问题了,也就是 总占用字节/每个单元的字节 = 单元个数
但是我们要理解,如果是下面这样
int a[10] = {1, 2, 3, 4, 5}; 我们sizeof(arr)/sizeof(arr[0])求出的是10,后面的元素没有被初始化,也就是将我们无法确定数组中元素的实际数量… …
4.二维数组
应用场景
和java 等其它编程语言一样,C语言也支多维数组。常用二维数组表示二维表个矩阵。
4.1 定义
类型名 数组名[行][列]
int arr[2][3];/ 这个二维数组2行3列,一共存放了6个 int型的 元素 /
4.2 引用
注意先行后列,其它略过… ….
二维数组的初始化
分行赋值
int a[3][3] ={{1, 2 ,3}, {4, 5, 6}, {7, 8, 9}};顺序赋值
int a[3][3] = {1, 2, 3, 4, 5, 6, 7, 8, 9};
此时这个二维数组用矩阵表示就是下面这个样子
1 2 3
4 5 6
7 8 9
4.3 二维数组在内存中的存放形式**
参考下图
4.4 例题-练习题
例7-7 将一个3 x 2 的矩阵中的值存入到一个3 x 2 的二维数组中,现将矩阵输出出来,再找出其中最大值的下标将其输出。
#include <stdio.h>
int main(void) {
// 定义数组、行列变量
int arr[3][2];
int i, j, row, col;
// 将数据存到数组中
printf("请输入6个数:\n"); // 提示用户输入6个数
for (i = 0; i < 3; i++){ // 控制行
for (j = 0; j < 2; j++){ // 控制列
scanf("%d", &arr[i][j]);
}
}
// 按照矩阵的格式输出二维数组
for (i = 0; i < 3; i++){
for (j = 0; j < 2; j++){
printf("%4d", arr[i][j]);
}
printf("\n");
}
// 遍历整个二维数组找出最大值
row = col = 0;
for (i = 0; i < 3; i++){
for (j = 0; j < 2; j++){
if(arr[i][j] > arr[row][col]){
row = i;
col = j;
}
}
}
// 输出矩阵中最大数的 index
printf("max = arr[%d][%d] = %d \n", row, col, arr[row][col]);
return 0;
}
例7-8 定义一个3 x 2 的二维数组a, 二维数组的值由下式给出,按照矩阵的形式输出a,a[i][j] = i + j
#include <stdio.h>
int main(void)
{
int i, j;
int a[3][2];
// 给数组赋值
for (i = 0; i < 3; i++ ){
for (j = 0; j < 2; j++){
a[i][j] = i + j;
}
}
// 按照矩阵的形式输出二维数组 a
for (i = 0; i < 3; i++ ){
for (j = 0; j < 2; j++){
printf("%4d", a[i][j]);
}
printf("\n");
}
return 0;
}
例7-9 输入一个正整数n(1< n <= 6),根据a[i][j] = i * n + j + 1;. 生成一个 n x n 的矩阵,然后将这个矩阵行列互换后输出。
/*
例如 n = 3 时,如下
1 2 3 1 4 7
4 5 6 2 5 8
7 8 9 3 6 9
转化前 转换后
*/
#include<stdio.h>
int main(void) {
int i, j, n;
int a[6][6];
printf("Enter n: \n");
scanf("%d", &n);
// 给二维数组赋值
for (i = 0; i < n; i++){
for (j = 0; j < n; j++){
a[i][j] = i * n + j + 1;
}
}
// 输出原矩阵
printf("原矩阵如下: \n");
for (i = 0; i < n; i++){
for (j = 0; j < n; j++){
printf("%4d", a[i][j]);
}
printf("\n");
}
// 行列互换
int temp;
for (i = 0; i < n; i++){
for (j = 0; j < n; j++){
if (i <= j ){
// a[i][j] = a[i][j] + a[j][i];
// a[j][i] = a[i][j] - a[j][i];
// a[i][j] = a[i][j] - a[j][i];
temp = a[i][j];
a[i][j] = a[j][i];
a[j][i] = temp;
}
}
}
// 输出转换后的矩阵
printf("新矩阵如下: \n");
for (i = 0; i < n; i++){
for (j = 0; j < n; j++){
printf("%4d", a[i][j]);
}
printf("\n");
}
return 0;
}
例7-11 判断输入的字符串是否是回文数 回车结束,回文数正反都一样
#include <stdio.h>
int main(void) {
int i, left, right;
static char s[10];
// 存入数组
printf("Enter a String (length <= 10) : ");
i = 0;
while( (s[i] = getchar()) != '\n' ){
i++;
}
// s[i] = '\0';
for(left = 0, right = i-1; left < right; left++, right--){
if(s[left] != s[right]){
break;
}
}
if(left >= right ){ // 表示for循环正常结束
printf("true");
}else {
printf("false");
}
return 0;
}
5. 从字符型数组引到字符串
5.1 基本概念。
C语言不像是Java等其他的编程语言,并没有为字符串单独设置一个基本数据类型,而是用数组存放连续的字符char表示了字符串
定义一维字符数组
- char str[80];
- char str[5] = { ‘H’, ‘a’, ‘p’,’ p’, ‘y’};
- static str[6] = { ‘H’, ‘a’, ‘p’,’ p’, ‘y’};
- static str[6] = { ‘H’, ‘a’, ‘p’,’ p’, ‘y’, ‘\0’};
- static str[] = { ‘H’, ‘a’, ‘p’,’ p’, ‘y’, ‘\0’};
定义一个字符串
static char str[6] = {'H', 'a', 'p',' p', 'y', '\0'};// 第一种方式static char str[6] = {"Happy};// 第二种方式static char str[6] = "Happy";// 第三种方式
这里的 长度设置比size 多1,应为我们需要设置 ‘\0’ 作为字符串的结束符。
static char s; s[0] = 'a'; s[1] = '\0';
等价于 => static char s[80] = "a";
区分 “a” 和 ‘a’,前者是字符串常量,后者这是一个字符而已,我们遍历字符串是用的是 '\0'.
5.2 练习
例题 7-13 输入一个以回车符号未结束的字符串(少于80个字符)),统计其中数字字符的个数
#include <stdio.h>
int main() {
// [1] 数组存取字符
int i, count;
printf("请输入字符串,字符个数 < 80 : ");
char str[80];
while ( (str[i] = getchar()) != '\n'){
i++;
}
str[i] = '\0';
// [2]遍历统计其中数字的个数
count = 0;
for (i = 0; str[i] != '\0'; i++){
if( str[i] > '0' && str[i] < '9'){
count++;
}
}
printf("count = %d \n", count);
return 0;
}

