本帖最后由 君莫笑WXH 于 2017-3-16 18:22 编辑
数组:字面理解:‘数’指数据;‘组’,就是小组。由数据组成的小组,就叫数组
数组可以这样理解,你建造(定义)了一栋工科楼(数组)叫做“务成楼”,整栋楼有100个房间用来存储数据,你把每一个房间从0-99编号(在C语言中就写为 int WuChengLou[100] ;)
提醒:在C语言学习中不要迷信书、考题、老师、网络回帖;要迷信CPU、编译器、调试器、运行结果!
例如:
int类型占用2个字节是16位机的时代,现在都是32位机,64位机,所以,不可死记硬背课本或者课件上内容!
以我电脑为例!运行如下代码:常用数据类型对应字节数可用如sizeof(char),sizeof(char*)等得出
#include <stdio.h>
#include <stdlib.h>
int main()
{
printf("%d\n",sizeof(char));
printf("%d\n",sizeof(int));
}
此时,int类型占用4个字节,cahr类型占用1个字节
一.数组的初始化
1>静态数组、动态数组初始化
static int b[5] = {1, 2, 3, 4, 5};
静态存储的数组如果没有初始化,所有元素自动赋0
static int b[5];
动态存储的数组如果没有初始化,所有元素为随机值auto int c[5]; 等价与 int c[5];
2>针对部分元素的初始化
static int b[5] = {1, 2, 3};
b[0] = 1, b[1] = 2, b[2] = 3, b[3] = 0, b[4] = 0
auto int fib[20] = {0, 1};
fib[0] = 0, fib[1] = 1, 其余元素不确定 如果对全部元素都赋初值,可以省略数组长度int a[ 10 ] = {0, 1, 2, 3, 4, 5, 6, 7, 8, 9}
二.对数组元素进行交换
其本质就是一个数据存入替换的过程
temp = a[index]; //将需要交换的其中一个数据存入“介质”中
a[index] = a[k]; //将另一个数据替换上一个数据
a[k] = temp;//将之前取出放入介质中的数据存入第二个数据
数组有几个特点一定要注意,看到数组就要想到:
1、 数组里面的数据类型是相同的,小组里面的成员肯定要一样的啊,俗话说物以类聚,人以群分,计算机里面也是这样啊。
我们顺便看下数据的基本类型:【int ,float, double, char 】
这些是基本类型,所以它们可以存在以下类型数组:int a[10], float f[10], doule d[10], char str[10]; 它们每一个都有10个元素,每一个元素的类型都是其前面声明的类型。
2、其实数组在内存中是连续分配的,如下图:
定义了一int型数组a,它有7个元素,分别是5,2,0,1,3,1,4它们在内存里面是连续存放的,每个元素占用4个字节。
仔细看上面的图,每一个字符都有一个地址,它们的跨度是4(字节)。数组的每个元素都可以通过下标来访问,下标(比如常用index来表示其下标)其实就是他在数组中的位置,也就是他的号。
拉10个人过来,报数,1,2,3.....,只不过,C语言里数组的下标是从0开始的。在计算机里面能访问的最小单位就是字节了,也就是地址只能找到以字节为单位,不能再精确了。
数组名a和变量名道理上是一样的,在编译时就和数组的首地址绑定上了,a就是数组的首地址,变量名和数组名其实都是方便人们记忆而取的代号,它在代码反汇编后,其实不存在变量名的。
我们再来看一个字符型数组
定义了一char型数组a,它有6个元素,分别是'W', 'X', 'H', 'W', 'X', 'H'它们在内存里面是连续存放的,每个元素占用一个字节。强烈谴责那些将'A' 当成"A"的人,前者是单个字符,后者是字符串。
鄙视那些,问“字符和字符串有什么区别?”的人,不知道字符和字符串的区别,那你吃过羊肉串吗?
单个羊肉块’A’能叫串吗,多个羊肉块串”A”起来才叫串,所以字符是单个,字符串可以是多个字符组成的数组(最后有一个结束符号 \0 )。
需要注意的是字符和字符串的输入与输出格式:
例输入:abcdefgh
接下来两种输入
【
while((str = getchar( )) != '\n')
i++;
str = '\0';
】
【
scanf(“%s”,str); //注意此处‘ & ’
】
思考这两种情况 ???
补充:为什么在scanf函数里,有的输入变量前面不用加“&”符号?
学习C的话,一定会接触到2个语句,scanf和printf。
这两个函数都是被定义在头文件stdio.h里的常用函数,在使用的时候需要加上#include<stdio.h>来保证可以成功调用到这2个函数。scanf是格式输入函数,它按照程序猿指定的格式,从键盘上把数据输入到指定的变量之中。
scanf的用法是
1. int a;//声明(待输入)变量a为int(Integer,整形)数据类型,系统会分配一段内存地址给a变量
2. scanf("%d",&a);//从键盘以十进制的形式(%d,decimal system)格式扫描(scanf,formatted-scan)一个输入量,将之存储在变量a所在的地址(&a)
【%是格式的前缀,%d 十进制有符号整数,%u 十进制无符号整数,%f浮点数,%s 字符串,%c 单个字符,%p 指针的值,%e 指数形式的浮点数,%x, %X 无符号以十六进制表示的整数,
%0 无符号以八进制表示的整数, %g用来输出实数,它根据数值的大小,自动选%f格式或%e格式(选择输出时占宽度较小的一种),且不输出无意义的0】
&是取址运算,&a即取a变量的内存地址。 其实整个scanf函数的核心就是定义扫描的数据为何种格式类型,将之存放在什么位置。
正如前文所说,scanf的目的是将格式化的数据存储到一个地址……“&"运算得到的结果是一个内存地址,我们就是将某个变量写到这个内存地址里去...
在scanf("%s",str)里的str不需要加“&”运算,究其本质则涉及指针的相关知识。定义str[10] 为 char数据类型,则str[10]是一个数组,str表示数组所在的内存段的头地址。
而scanf()函数所需要的地址,其实质就是一段数据所对应的内存段的起始地址,str已经是其数据所在的内存段的头地址,自然不需要“&”取值。当然,加上的话,也不会报错……
关于二维数组
定义格式:数组名[行下标] [列下标
]
a是个二维数组,它有3X4=12个字符元素,
而编译器将它认为是一个一维数组,它有三个元素,分别是a[0], a[1], a[2], 每一个元素是一个含有4个字符的数组。
通过上面的分析可以看出,数组有很多地方很相似,其实,编译器这哥们处理数组的时候就是将其看成指针来处理的,没有办法,编译器只认地址,变量名一直都是被编译器所不接受的。
二维数组的初始化
分行赋初值
int a[3][3] = {{1,2,3},{4,5,6},{7,8,9}};
static int b[4][3] = {{1,2,3},{ },{4,5}};
顺序赋初值
int a[3][3] = {1,2,3,4,5,6,7,8,9};
static int b[4][3] = {1,2,3,0,0,0,4,5};
二维数组的遍历
方法是使用一个嵌套循环,通过下标增减进行遍历
for(i = 0; i < n; i++)
for(j = 0; j < n; j++)
a[j]=……;
矩阵
经典数组编程
1>自定义1个函数day_of_year(year, month, day),
计算并返回年 year、月month和日day对应的是该年的第几天。
day_of_year(2000, 3, 1)
返回61
day_of_year(1981, 3, 1)
返回60
分析: 月 0 1 2 3 …… 11 12
非闰年 0 31 28 31 30 31
闰年 0 31 29 31 30 31
函数部分代码
int day_of_year(int year, int month, int day)
{
int k, leap;
int tab[2][13]={
{0, 31, 28, 31, 30,31,30,31,31,30,31, 30,31},// 注意该处的‘,’
{0, 31, 29, 31, 30,31,30,31,31,30,31, 30,31}
};
leap = (year%4==0&&year%100!=0) || year %400==0;
for (k=1; k<month; k++)
day = day + tab[leap][k];
return day;
}
2>输入一个以回车结束的字符串(少于80个字符),统计其中数字字符的个数。
代码实现:
#include <stdio.h>
int main(void)
{
int count, i;
char str[80];
printf(“Enter a string: ");
i = 0;
while((str = getchar( )) != '\n')
i++;
str = '\0';
count = 0;
for(i = 0; str != '\0'; i++)
if(str <= '9' && str >= '0')
count++;
printf("count = %d\n", count);
return 0;
} |