作者 : 会敲代码的Steve
墓志铭:博学笃志 切问静思
前言:本文旨在复习C语言数组章节的知识点、分为以下几个部分:
- 什么是数组
- 一维数组、一维数组的初始化、一维数组的遍历、冒泡排序。
- 二维数组、二维数组的创建和初始化、二维数组的使用
- 数组作为函数传参时
- 数组越界
- C99标准的变长数组
正文:
目录
1.什么是数组?
2.一维数组初始化
2.1 一维数组遍历
2.2 冒泡排序
2.3 代码
3.二维数组
3.1 二维数组的创建和初始化
3.2 二维数组的遍历
4.数组作为函数元素传参
5.c99标准的变长数组
1.什么是数组?
数组是一组相同数据的集合
2.一维数组初始化
前面我们学习了如何定义一个变量,其中变量是这么定义的 :
int a; //int 数据类型 //变量名
那数组是如何定义的呢? 让我们看下面的代码
int arr[5]={0,1,2,3,4}; //int 数据类型 arr 数组名 //[5]代表里面有五个元素
所以这是一个包含有5个元素的int类型数组;
数组的初始化:
数组的初始化是指,在创建数组的同时给数组的内容一些合理初始值(初始化)
但是对于下面的代码要区分,内存中如何分配。
char arr1[] = "abc";
char arr2[3] = {'a','b','c'};
对于数组的使用我们之前介绍了一个操作符: [] ,下标引用操作符。它其实就数组访问的操作符。 我们来看代码:
# include <stdio.h>
int main (void)
{
int arr[5]={0,1,2,3,4};//数组的完全初始化
}
总结:
- 1.数组是使用下标来访问的,下标是从0开始。
- 2. 数组的大小可以通过计算得到。
int arr[10];
int sz = sizeof(arr)/sizeof(arr[0]);
2.1 一维数组遍历
数组是可以通过下标的方式来遍历,上面已经介绍过了数组的初始化,我们来尝试一下写写代码。
for(int i = 0;i<5;i++)
{
printf("%d ",arr[i]);//依次访问0-4的所有数组元素
}
return 0;
于是这就是数组的一个简单的遍历。
补充:
数组的下标是有范围限制的。 数组的下规定是从0开始的,如果数组有n个元素,最后一个元素的下标就是n-1。 所以数组的下标如果小于0,或者大于n-1,就是数组越界访问了,超出了数组合法空间的访问。 C语言本身是不做数组下标的越界检查,编译器也不一定报错,但是编译器不报错,并不意味着程序就 是正确的, 所以程序员写代码时,最好自己做越界的检查。
#include <stdio.h>
int main()
{
int arr[10] = {1,2,3,4,5,6,7,8,9,10};
int i = 0;
for(i=0; i<=10; i++)
{
printf("%d\n", arr[i]);//当i等于10的时候,越界访问了
}
return 0;
}
二维数组的行和列也可能存在越界。
2.2 冒泡排序
冒泡排序(Bubble Sort)也是一种简单直观的排序算法。它重复地走访过要排序的数列,一次比较两个元素,如果他们的顺序错误就把他们交换过来。走访数列的工作是重复地进行直到没有再需要交换,也就是说该数列已经排序完成。这个算法的名字由来是因为越小的元素会经由交换慢慢"浮"到数列的顶端。
作为最简单的排序算法之一,冒泡排序给我的感觉就像 Abandon 在单词书里出现的感觉一样,每次都在第一页第一位,所以最熟悉。冒泡排序还有一种优化算法,就是立一个 flag,当在一趟序列遍历中元素没有发生交换,则证明该序列已经有序。但这种改进对于提升性能来
说并没有什么太大作用。
1. 算法步骤
比较相邻的元素。如果第一个比第二个大,就交换他们两个。
对每一对相邻元素作同样的工作,从开始第一对到结尾的最后一对。这步做完后,最后的元素会是最大的数。
针对所有的元素重复以上的步骤,除了最后一个。
持续每次对越来越少的元素重复上面的步骤,直到没有任何一对数字需要比较。
2. 动图演示
2.3 代码
#include <stdio.h>
int main() {
int a, b, temp;
int m[10];
for (a = 0; a < 10; a++) {
scanf("%d", &m[a]);
}
for (a = 0; a < 9; a++) {
for (b = a + 1; b < 10; b++) {
if (m[a] > m[a + 1]) {
temp = a[m];
a[m] = a[m + 1];
a[m + 1] = temp;
}
}
}
for (a = 0; a < 10; a++) {
printf("%d ", m[a]);
}
return 0;
}
3.二维数组
二维数组只是比一维数组多一个维度,可以理解为矩阵。
3.1 二维数组的创建和初始化
创建:
//数组创建
int arr[3][4];
char arr[3][5];
double arr[2][4];
初始化:
int arr[3][4] = {1,2,3,4};
int arr[3][4] = {{1,2},{4,5}};
int arr[][4] = {{2,3},{4,5}};//二维数组如果有初始化,行可以省略,列不能省略
3.2 二维数组的遍历
define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <math.h>
#include <time.h>
int main(void)
{
int arr[3][4] = { {2, 7, 8, 5},
{75, 8, 9, 8},
{26, 37, 99, 9} };
for (size_t i = 0; i < 3; i++) //行
{
for (size_t j = 0; j < 4; j++) //列
{
printf("%d ", arr[i][j]*2);
}
printf("\n");
}
4.数组作为函数元素传参
往往我们在写代码的时候,会将数组作为参数传个函数,比如:我要实现一个冒泡排序(这里要讲算法 思想)函数 将一个整形数组排序。
错误的冒泡排序:
#include<stdio.h>
void sort(int arr[]);
int main()
{
int i = 0;
int rtr[10]={0};
for(i = 0;i<10;i++)
{
scanf("%d",&rtr[i]);
}
sort(rtr);
for(i = 0;i<10;i++)
{
printf("%d ",rtr[i]);
}
return 0;
}
void sort(int arr[])
{
int sz = sizeof(arr)/sizeof(arr[0]);
int i,j = 0;
for(i = 0;i<sz;i++)
{
for(j = 0;j<sz-1-i;j++)
{
if(arr[j]>arr[j+1])
{
int temp = arr[j];
arr[j]=arr[j+1];
temp = arr[j];
}
}
}
}
难道数组作为函数参数的时候,不是把整个数组的传递过去?
正确的冒泡排序:
#include<stdio.h>
void sort(int arr[],int sz);
int main()
{
int i = 0;
int rtr[10]={0};
int sz = sizeof(rtr)/sizeof(rtr[0]);
for(i = 0;i<sz;i++)
{
scanf("%d",&rtr[i]);
}
sort(rtr,sz);
for(i = 0;i<sz;i++)
{
printf("%d ",rtr[i]);
}
return 0;
}
void sort(int arr[],int sz)
{
int i,j = 0;
for(i = 0;i<sz;i++)
{
for(j = 0;j<sz-1-i;j++)
{
if(arr[j]>arr[j+1])
{
int temp = arr[j];
arr[j]=arr[j+1];
temp = arr[j];
}
}
}
}
数组名是什么?
#include <stdio.h>
int main()
{
int arr[10] = {1,2,3,4,5};
printf("%p\n", arr);
printf("%p\n", &arr[0]);
printf("%d\n", *arr);
//输出结果
return 0;
}
如果数组名是首元素地址,那么:
int arr[10] = {0};
printf("%d\n", sizeof(arr));
为什么输出的结果是:40?
- 补充: 1. sizeof(数组名),计算整个数组的大小,sizeof内部单独放一个数组名,数组名表示整个数 组。
- &数组名,取出的是数组的地址。&数组名,数组名表示整个数组。 除此1,2两种情况之外,所有的数组名都表示数组首元素的地址。
5.c99标准的变长数组(补充)
这样的代码会报错吗?
#include<stdio.h>
int main()
{
int n = 5;
int arr[n];
}
答案是在C99标准下,并不会;但如果在msvc里面则使用会提示你要使用变量而不是常量。这就是C99标准。