10.24-28
一、数组
数组概念及基础知识
定义数组
•<类型>变量名称[元素数量];
• Int grades[ 100];
• double weight [20];
•元素数量必须是整数
•C99之前:元素数量必须是编译时刻确定的字面量
数组
• 是一种容器(放东西的东西),特点是:
•其中所有的元素具有相同的数据类型;
•一旦创建,不能改变大小
•* (数组中的元素在内存中是连续依次排列的)
int a 10
•一个int的数组
• 10个单元:a[o],a[1],a[9]
•每个单元就是一个int类型的变量
•可以出现在赋值的左边或右边:
• a[2]= a[1]+6;
•*在赋值左边的叫做左值
数组的单元
•数组的每个单元就是数组类型的一个变量
•使用数组时放在口中的数字叫做下标或索引,下标从0
开始计数:
• grades [0]
• grades[99]
• average[5]
有效的下标范围
•编译器和运行环境都不会检查数组下标是否越界,无论是对数组单元做读还是写
•一旦程序运行,越界的数组访问可能造成问题,导致程序崩溃
•segmentation fault
• 但是也可能运气好,没造成严重的后果
•所以这是程序员的责任来保证程序只使用有效的下标值:[0,数组的大小一1]
长度为0的数组
·int a[0]
·可以存在但无用
1、利用数组求平均值
int x;
double sum = 0;
int cnt = 0;
int number[100]; //定义数组
scanf("%d", &x);
while ( x!= -1 ){
number[cnt]=x; //对数组中的元素赋值
sum += x;
cnt ++;
scanf("%d", &x);
}
if ( cnt > 0) {
printf("%f\n", sum/cnt);
int i;
for ( i=0; i<cnt; i++){
if(number[i]>sum/cnt){ //使用数组中的元素
printf("%d\n", number[i]); //遍历数组
}
}
}
2、求1-9出现的次数
const int number = 10;
int x;
int count[number];
int i;
for(i=0; i<number;i++) {
count[i]=0;
}
scanf("%d", &x);
while(x!=-1){
if (x>=0 && x<=9) {
count[x] ++;
}
scanf("%d",&x);
}
for (i=0;i<number;i++){
printf("%d:%d\n", i, count[i]);
}
二、函数
什么是函数?
•函数是一块代码,接收零个或多个参数
做一件事情,并返回零个或一个值
•可以先想像成数学中的函数:
•y=f(x)
1、函数求和
void /*函数头,返回类型*/sum/*函数名*/(int begin, int end)//参数表
{
int i;
int sum =0;
for (i=begin;i<=end;i++) {
sum += i;
}
printf("%d到%d的和是%d\n", begin, end, sum);
}//函数体
int main()
{
sum(1, 10);
sum(20, 30);
sum(35,45);
以上这种注释方法不可取
这里只是为了便于认识函数
调用函数
•函数名(参数值);
•()起到了表示函数调用的重要作用
•即使没有参数也需要()
•如果有参数,则需要给出正确的数量和顺序
•这些值会被按照顺序依次用来初始化函数
中的参数
函数返回
·函数知道每一次在哪里调用它,会返回到正确的地方
从函数中返回值
·return停止函数的执行,并送回一个值
·return;
·return 表达式;
·可以赋值给变量
·也可以再传给函数
·甚至可以丢弃
没有返回值的函数
·void函数名(参数表)
·不能使用带值的return
·可以没有return
·调用的时候不能做没有返回值的赋值
如果函数有返回值必须使用带值的return
2、函数定义可在后也可在前
void sum(int begin, int end); //原型声明
int main()
{
sum(1, 10);
sum(20, 30);
sum(35,45);
return 0;
}
void sum(int begin, int end) //函数定义
{
int i;
int sum =0;
for (i=begin;i<=end;i++) {
sum += i;
}
printf("%d到%d的和是%d\n", begin, end, sum);
}
函数先后关系
·c的编译器自上而下顺序分析你编码
·再看到sum(1,10)的时候,他需要知道sum()的样子
·也就是知道sum()要几个参数,每个参数的类型如何,返回什么类型
·这样才能检验你对sum()的调用是否正确
函数原型
·函数头,已分号“;”结尾,就构成函数的原型
·函数原型的目的是告诉编译器这个函数长什么样
·名称
·参数(数量及类型)
·返回类型
·现在一般写在调用它的函数前
调用函数
·如果函数有参数,调用函数时必须传递给他数量、类型的正确的值
·可以传递给函数的值是表达式的结果,这包括
·字面量
·变量
·函数的返回值
·计算的结果
3、值
void swap(int a, int b); //a,b形参 ;参数
int main()
{
int a = 5;
int b = 6;
swap(a,b); //实参 ; 值
printf("a=%d b=%d\n", a, b);
return 0;
}
void swap(int a, int b) //形参 ; 参数
{
int t = a;
a = b;
b = t;
}
传值
•每个函数有自己的变量空间,参数也位于这个独立的空间中,和其他函数没有关系
•过去,对于函数参数表中的参数,叫做”形式参数“,调用函数时给的值叫做“实际参数”
•现在,对于函数参数表中的参数,叫做”参数“,调用函数时给的值叫做“值”
本地变量
·函数的每次运行就产生了一个独立的变量空间这个空间中的变量,是函数的这次运行所独有的作本地变量
·定义在函数内部的变量就是本地变量
·参数也是本地变量
变量的生存期和作用域
·生存期:什么时候这个变量开始出现了,到什么时候它消亡了
·作用域:在(代码的)什么范围内可以访问这个变量(这个变量可以起作用)
·对于本地变量,这两个问题的答案是统一的:大括号内一块
本地变量的规则
•本地变量是足义在块内的
•它可以是定义在函数的块内
•也可以定义在语句的块内
•甚至可以随便拉一对大括号来定义变量
•程序运行可以这个块之前,其中的变量不存在,离开这个块,其中的变量就消失了
•块外面定义的变量在里面仍然有效
•块里面定义了和外面同名的变量则掩盖了外面的
•不能在一个块内定义同名的变量
•本地变量不会被默认初始化
没有参数时
·void f(void)
·还是void f()
·在传统的C中,它表示f函数的参数表未知,并不表示没有参数
调用函数时圆括号里的逗号是标点符号,不是运算符,例f(a,b)
而f((a,b))中逗号是运算符
C语言不允许嵌套定义
三、数组运算
数组的集成初始化
int a[] = {2,4,6,7,1,3,5,9,11,13,23,14,32};
•直接用大括号给出数组的所有元素的初始值
• 不需要给出数组的大小,编详器替你数数
集成初始化时的定位 C99 ONLY!
int all0] ={
[0] =2, [2]=3, 6 ,
•用n在初始化数据中给出定位
•没有定位的数据接在前面的位置后面
•其他位置的值补零
•也可以不给出数组大小,让编译器算
•特别适合初始数据稀疏的数组
数组的大小
1、sizeof给出整个数组所占据的内容的大小,单位是字节
sizeof(a)/sizeof(a[0])
2、sizeof[0])给出数组中单个元素的大小,于是相除就得到了数组的单元个数
3、这样的代码;一旦修改数组中初始的数据,不需要修改遍历的代码
数组的赋值
int a[] ={ 2,4,6,7,1,3,5,9,11,13,23,14,32};
不能 Int b[]=a[];
1、数组变量本身不能破赋值
2、要一个数组的所有元素交给另一个数组,必领采用遍历
for( i=0; i<length; i++ ) {
b[i] = a[i];
}
遍历数组
for ( i=0; i<length; i++ ) {
b[i]=a[i];
}
for (i =0; i<number; i++) {
Count[i];
}
for (i=o; i<length; i++){
If ( a[i] == key ) {
ret = i
break;
}
}
for ( i=0; i<cnt; i++ ) {
If ( number[i] > average ) {
Printf(“%d”, number[i]);
}
}
for ( i=0; i=number; i++ ) {
Printf(“%d:%d\n”, i, count[i]);
}
1、通常都是使用for循环,让循环变量以0到<数组的长度,这样缩环体内最大的正好是数组最大的有效下标
2、常见错误是:
•循环结束条件是<=数组长度,或;
•离开循环后,继续用i的值来做数组元素的下标!
数组作为函数参数时:
•往往必须再用另一个参数来传人数组的大小
•不能在中给出数组的大小
•不能再利用sizeof来计算数组的元素个数
1、二维数组(矩阵)井字棋
#include <stdio.h>
int main()
{
const int size = 3;
int board[size][size];
int i, j;
int numOfX1;
int numOfO1;
// 添加两个变量,判断行列的时候,标记列中X和O的个数;判断对角线的时候,标记另一条对角线的X和O的而数量;以便减少循环次数。
int numOfX2;
int numOfO2;
int result = -1; // -1:没人赢,1:X赢,0:O赢
// 读入矩阵
for(i = 0;i < size;i++){
for(j=0;j <size;j++){
scanf("%d",&board[i][j]);
}
}
// 判断行列
for (i = 0; i < size && result == -1; i++)
{
numOfX1 = numOfO1 = numOfX2 = numOfO2 = 0;
for (j = 0; j < size; j++)
{
if (board[i][j] == 1)
{
numOfX1++;
}
else
{
numOfO1++;
}
if (board[j][i] == 1)
{
numOfX2++;
}
else
{
numOfO2++;
}
}
if (numOfO1 == size || numOfO2 == size)
{
result = 0;
}
else if (numOfX1 == size || numOfX2 == size)
{
result = 1;
}
}
// 判断对角线
if (result == -1)
{
numOfX1 = numOfO1 = numOfX2 = numOfO2 = 0;
for (i = 0; i < size && result == -1; i++)
{
if (board[i][i] == 1)
{
numOfX1++;
}
else
{
numOfO1++;
}
if (board[i][size - i - 1] == 1)
{
numOfX2++;
}
else
{
numOfO2++;
}
}
if (numOfO1 == size || numOfO2 == size)
{
result = 0;
}
else if (numOfX1 == size || numOfX2 == size)
{
result = 1;
}
}
if (result == 0)
{
printf("O方胜\n");
}
else if (result == 1)
{
printf("X方胜\n");
}
else
{
printf("平局\n");
}
return 0;
}
2、线性搜索
#include <stdio.h>
/*
找出key在数组a中的位置
@param key 要寻找的数宇
@param a要寻找的数组
@param length 数组a的长度
@return 如果找到,返回其在a中的位置;如果找不到则返回-1
*/
int search(int key, int a[], int length);
int main(void)
{
int a[] = {12,4,6,7,1,3,5,9,11,13,23,14,32};
int x;
int loc;
printf("请输入一个数字:");
scanf("%d", &x);
loc=search(x, a, sizeof(a)/sizeof(a[0]));
if ( loc != -1 ) {
printf("%d在第%d个位置上\n", x, loc);
}else{
printf("%d不存在\n",x);
}
return 0;
}
int search(int key, int a[], int length)
{
int ret = -1;
int i;
for ( i=0; i< length; i++ ) {
if ( a[i] == key ) {
ret = 1;
break;
}
}
return ret;
}
3、搜索的例子 美分对应单词
#include <stdio.h>
int amount[] = {1,5,10,25,50};
char *name[] = {"penny", "nickel", "dime", "quarter", "half-dollar"};
int search(int key, int a[], int len)
{
int ret = -1;
for ( int i=0; i<len; i++ )
{
if ( key == a[i] )
{
ret = i;
break;
}
}
return ret;
}
int main()
{
int k = 10;
int r = search(10, amount, sizeof(amount)/sizeof(amount[0]));
if ( r > -1 )
{
printf("%s\n", name[r]);
}
return 0;
}
4、数字排序(由小到大)
#include <stdio.h>
int max(int a[], int len)
{
int maxid = 0;
for ( int i=1; i<len; i++ )
{
if ( a[i] > a[maxid] )
{
maxid = i;
}
}
return maxid;
}
int main()
{
int a[] = {2,45,6,12,87,34,90,24,23,11,65};
int len = sizeof(a)/sizeof(a[0]);
//选择排序
for ( int i=len-1; i>0; i-- )
{
int maxid = max(a, i+1);
//swap a[maxid], a[len-1]
int t = a[maxid];
a[maxid] = a[i];
a[i] = t;
}
for ( int i=0; i<len; i++)
{
printf("%d ", a[i]);
}
return 0;
}
5、搜索对应位置
#include <stdio.h>
int search(int key, int a[], int len)
{
int ret = -1;
for ( int i=0; i<len; i++ )
{
if ( key == a[i] )
{
ret = i;
break;
}
}
return ret; //单一出口
}
int main()
{
int a[] = {1,3,2,5,12,14,23,6,9,45};
int r = search(12, a, sizeof(a)/sizeof(a[0]));
printf("%d\n", r);
return 0;
}