前言
所谓数组,是有序的元素序列。 若将有限个类型相同的变量的集合命名,那么这个名称为数组名。组成数组的各个变量称为数组的分量,也称为数组的元素,有时也称为下标变量。用于区分数组的各个元素的数字编号称为下标。数组是在程序设计中,为了处理方便, 把具有相同类型的若干元素按无序的形式组织起来的一种形式。 这些无序排列的同类数据元素的集合称为数组。
数组是用于储存多个相同类型数据的集合。
C语言数组的概念
数组的概念和定义
我们知道,要想把数据放入内存,必须先要分配内存空间。放入4个整数,就得分配4个int类型的内存空间:1
int a[4];
这样,就在内存中分配了4个int类型的内存空间,共 4×4=16 个字节,并为它们起了一个名字,叫a。
我们把这样的一组数据的集合称为数组(Array),它所包含的每一个数据叫做数组元素,所包含的数据的个数称为数组长度(Length),例如int a[4];就定义了一个长度为4的整型数组,名字是a。
数组中的每个元素都有一个序号,这个序号从0开始,而不是从我们熟悉的1开始,称为下标(Index)。
此处演示一下如何使用循环结构将数据放入数组,然后依次读取数组元素的值:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
int main()
{
int arr[10];
int i = 0;
printf("请依次输入十个数字:\n");
for(i=0; i<10; i++)
{
scanf("%d",&arr[i]);
}
for(i=0; i<10; i++)
{
printf("%d ",arr[i]);
}
return 0;
}
注意:①数组中每个元素的类型必须相同,对于 int arr[10] 每一个元素都必须为int
②访问数组元素时,下边的取值范围为0≤index<length
数组内存是连续的
数组是一个整体,它的内存是连续的;也也就是说,数组元素之间是相互挨着的,彼此之间没有一点点缝隙。连续的内存为指针操作(通过指针来访问数组元素)和内存处理(整块内存的复制、写入等)提供了便利,这使得数组可以作为缓存(临时存储数据的一块内存)使用。
二维数组的定义
一般形式:1
dataType arrayName[length1][length2];
其中,dataType为数据类型,arrayName为数组名,length1为第一维下标的长度,length2位第二维下标的长度。
我们可以将二维数组看为一个表格,length1为行,length2为列。列入:1
int a[3][4];
便是一个三行四列名为a的数组。
此处演示二维数组的初始化及输出:1
2
3
4
5
6
7
8
9
10
11
12
13
14
15int main()
{
int arr[3][5] = {1,2,3,4,5,6,7,8,9};
int i = 0;
int j = 0;
for(i=0; i<sizeof(arr)/sizeof(arr[0]); i++)
{
for(j=0; j<sizeof(arr[0])/sizeof(arr[0][0]); j++)
{
printf("%d ",arr[i][j]);
}
printf("\n");
}
return 0;
}
注意:
对于二维数组的初始化要注意:
1.可以只对部分元素赋值,为赋值的元素自动取零。如:1
int a[3][3] = {{1},{2],{3}};
2.如果对全部元素赋值,第一维长度可以不给出。如:1
int a[3][3] = {1,2,3,4,5,6};
也可以写为1
int a[][3] = {1,2,3,4,5,6};
(即可以没有行,不能没有列)
3.二维数组可以看作是由一维数组嵌套而成的;如果一个数组的每个元素又是一个数组,那么它就是二维数组。当然,前提是各个元素的类型必须相同。根据这样的分析,一个二维数组也可以分解为多个一维数组,C语言允许这种分解。
例如,二维数组a[3][4]可分解为三个一维数组,它们的数组名分别为 a[0]、a[1]、a[2]。
这三个一维数组可以直接拿来使用。这三个一维数组都有 4 个元素,比如,一维数组 a[0] 的元素为 a[0][0]、a[0][1]、a[0][2]、a[0][3]。
C语言数组元素的查询
对无序数组查询
1 |
|
解析:遍历整个数组,用if语句判断输入数字是否存在于数组当中
对有序数组的查询
1 |
|
解析:有序数组查询方法和无序相似,但是由于知道数组是升序排序,所以在查到所需数字时不必再遍历后面的数字,所以有18~21行
C语言字符数组和字符串
用来存放字符的数组称为字符数组,例如:1
char c[20] = {'a','b','c','d'}; //给部分数组元素赋值
也可以将字符串直接赋值给字符数组,例如:1
char c[50] = {"you have a pair of beautiful eyes"};
或1
char c[50] = "you have a pair of beautiful eyes"; /这样更简洁方便
在定义数组时为了方便也可不指定数组长度,例如:1
2char c[] = "you have a pair of beautiful eyes";
char c[] = {'a','b','c','d','\0'}; // 注意\0
字符串结束标志 \0
字符串是一系列连续的字符的组合,要想在内存中定位一个字符串,除了要知道它的开头,还要知道它的结尾
字符串的开头很容易,知道它的名字(字符数组名或者字符串名)就可以
在C语言中,字符串总是以’\0’作为结尾,所以’\0’也被称为字符串结束标志,或者字符串结束符。
C语言在处理字符串时,会从前往后逐个扫描字符,一旦遇到’\0’就认为到达了字符串的末尾,就结束处理。’\0’至关重要,没有’\0’就意味着永远也到达不了字符串的结尾。
由” “包围的字符串会自动在末尾添加’\0’。例如,”abc123”从表面看起来只包含了 6 个字符,其实C语言会在最后隐式地添加一个’\0’,这个过程是在后台默默地进行的,所以我们感受不到。
需要注意的是,逐个字符地给数组赋值并不会自动添加’\0’,例如:1
char c[] = {'a','b','c','d'};
此时并不会如愿输出abcd,而是有其他多余的东西,所以我们需在末尾添加’\0’,如上一个语句
当用字符数组存储字符串时,要特别注意’\0’,要为’\0’留个位置;这意味着,字符数组的长度至少要比字符串的长度大 1。请看下面的例子:1
char a[7] = "abcdef";
“abcdef”看起来只包含了 6 个字符,我们却将 a 的长度定义为 7,就是为了能够容纳最后的’\0’。如果将 a 的长度定义为 6,它就无法容纳’\0’了,系统会报错。
字符串长度 strlen
字符串长度,就是字符串包含了多少个字符(不包括最后的结束符’\0’)。例如”abc”的长度是 3,而不是 4
他的用法举例:1
2
3
4
5
6
7
8
9
int main()
{
char str[] = "c:\test\code\35\test.c"; //转义字符
long f = strlen(str);
printf("%ld",f);
return 0;
}
输出 17
字符串的输入和输出
字符串的输出
1 |
|
注意,输出字符串时只需要给出名字,不能带后边的[ ],例如,下面的两种写法都是错误的:1
2printf("%s\n", str[]);
puts(str[10]);
字符串的输入
在C语言中,有两个函数可以让用户从键盘上输入字符串,它们分别是:
scanf():通过格式控制符%s输入字符串。除了字符串,scanf() 还能输入其他类型的数据。
gets():直接输入字符串,并且只能输入字符串。
但是,scanf() 和 gets() 是有区别的:
scanf() 读取字符串时以空格为分隔,遇到空格就认为当前字符串结束了,所以无法读取含有空格的字符串。
gets() 认为空格也是字符串的一部分,只有遇到回车键时才认为字符串输入结束,所以,不管输入了多少个空格,只要不按下回车键,对 gets() 来说就是一个完整的字符串。换句话说,gets() 用来读取一整行字符串。
但是,scanf() 和 gets() 是有区别的:
scanf() 读取字符串时以空格为分隔,遇到空格就认为当前字符串结束了,所以无法读取含有空格的字符串。
gets() 认为空格也是字符串的一部分,只有遇到回车键时才认为字符串输入结束,所以,不管输入了多少个空格,只要不按下回车键,对 gets() 来说就是一个完整的字符串。换句话说,gets() 用来读取一整行字符串。
注意: 就目前学到的知识而言,int、char、float 等类型的变量用于 scanf() 时都要在前面添加&,而数组或者字符串用于 scanf() 时不用添加&,它们本身就会转换为地址。
C语言字符串处理函数
字符串连接函数strcat
strcat 是 string catenate 的缩写,意思是把两个字符串拼接在一起,strcat() 将把 arrayName2 连接到 arrayName1 后面,并删除原来 arrayName1 最后的结束标志’\0’。这意味着,arrayName1 必须足够长,要能够同时容纳 arr1 和 arr2,否则会越界(超出范围)。
程序举例:1
2
3
4
5
6
7
8
9
10
11
int main()
{
char arr1[100] = "abcde";
char arr2[60] = "aaaaa";
//scanf("%s",arr2);
strcat(arr1, arr2);
printf("%s",arr1);
return 0;
}
可以看到输出结果为 abcdeaaaaa
及去掉了arr1的\0 将arr2的内容添加到了arr1后面
字符串复制函数 strcpy()
strcpy 是 string copy 的缩写,意思是字符串复制,也即将字符串从一个地方复制到另外一个地方。trcpy() 会把 arrayName2 中的字符串拷贝到 arrayName1 中,字符串结束标志’\0’也一同拷贝。
程序举例:1
2
3
4
5
6
7
8
9
10
int main()
{
char arr1[50] = "hello";
char arr2[50] = "goodbye";
strcpy(arr1,arr2);
printf("arr1:%s",arr1);
return 0;
}
可看到程序的输出结果为: arr:goodbye
arr1拷贝了arr2的内容并被完全覆盖
另外注意,strcat() 要求 arr1 要有足够的长度,否则不能全部装入所拷贝的字符串。
字符串比较函数 strcmp()
strcmp 是 string compare 的缩写,意思是字符串比较。字符本身没有大小之分,strcmp() 以各个字符对应的 ASCII 码值进行比较。strcmp() 从两个字符串的第 0 个字符开始比较,如果它们相等,就继续比较下一个字符,直到遇见不同的字符,或者到字符串的末尾。
返回值:若 arrayName1 和 arrayName2 相同,则返回0;若 arr1 大于 arr2,则返回正数;若 arr1 小于 arr2,则返回负数。
程序举例:1
2
3
4
5
6
7
8
9
10
11
12
int main()
{
char arr1[] = "abcd";
char arr2[] = "Abad";
char arr3[] = "abcd";
printf("arr1:arr3=%d\n",strcmp(arr1,arr3));
printf("arr1:arr2=%d\n",strcmp(arr1,arr2));
printf("arr2:arr3=%d\n",strcmp(arr2,arr3));
return 0;
}
运行结果:0 1 -1
附:冒泡排序
1 |
|