程序设计入门——C语言学习笔记Lecture 3

Lecture 3 数组与函数

1. 数组

如何记录很多数?→ 数组
如何定义一个数组:<类型> 变量名称[元素数量];

int grades[100];//grades[0]——grades[99]
double weight[20];

注意:数组下标(0—n-1)与数组元素个数(n)不一致
数组越界:segment fault

1.1 数组的集成初始化

定义数组时给数组赋值称为数组的集成初始化;
在这里插入图片描述

1.2 数组的大小

  • sizeof给出整个数组所占据的内容的大小,单位是字节;
  • 数组中元素个数 = sizeof(a) / sizeof(a[0])

1.3 数组的遍历

  数组变量本身不能被赋值,要把一个数组的所有元素交给另一个数组,必须采用遍历:

错误赋值方式:
int a[] = {1, 2, 3, 4, 5, 6, };   int b[] = a;
正确赋值方式:
for ( i=0; i<length; i++) 
{
	b[i]=a[i];
}	

  遍历数组常见错误

  • 循环结束条件是<=数组长度;
  • 离开循环后,继续用i的值来做数组元素的下标。

1.4 数组作为函数参数

  • 数组作为函数参数时,往往必须再用另一个参数来传入数组的大小
  • 数组作为函数参数时,不能在[]中给出数组的大小(没有意义);
  • 也不能在参数列表中或函数内部利用sizeof来计算数组的元素个数(因为数组是以指针的形式传进函数
  • 详见指针的应用场景——“求最大最小值”部分

1.5 实例

1.5.1 统计输入量0-9中各个数字出现的个数

//统计输入量0-9中各个数字出现的个数,输入-1表示结束。
#include <stdio.h>

int main()
{
	const int number = 10;  //数组的大小
	int x;
	int count[number]; //定义数组 (C99:数组大小可以为一个变量)
	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]);
	}
	
	return 0;
}

1.5.2 选择排序

  先找出最大的,放到最后面(即与数组中最后一个数交换);固定最后一个,在剩下的数中再找出最大的,放到最后面;重复进行此步骤即可。

详见:选择排序&二分搜索

2.函数

  函数是一块代码,接收零个或多个参数,做一件事情,并返回零个或一个值。
函数定义:
在这里插入图片描述

2.1 void函数

  没有返回值的函数用void函数名(参数表),不能使用带值的return(可以没有return),调用的时候不能做返回值的赋值;如果函数有返回值,则必须使用带值的return。

2.2 函数声明

  • 要想把函数写在main函数后面,需要先写声明:函数头;
  • 函数头加;构成函数原型;函数原型可以不写参数名,只写参数类型

2.3 函数调用

  调用函数:函数名(参数值);  ()起到了表示函数调用的重要作用,即使没有参数也需要()   如果有参数,则需要给出正确的数量和顺序,这些值会被按照顺序依次用来初始化函数中的参数。
  从函数中返回值:return停止函数的执行,并送回一个值

  • return;
  • return 表达式;

  调用函数时给的值与参数的类型不匹配是C语言传统上的最大漏洞,编译器总是悄悄替你把类型转换好,但是这很可能不是你所期望的,后续的语言,C++/Java在这方面很严格。
  C语言在调用函数时,永远只能传值给函数(而不是变量)。每个函数有自己的变量空间,参数也位于这个独立的空间中,和其他函数没有关系。

2.4 本地变量

  函数的每次运行,就产生了一个独立的变量空间,在这个空间中的变量,是函数的这次运行所独有的,称作本地变量;定义在函数内部的变量就是本地变量,参数也是本地变量。
  本地变量的规则:

  • 本地变量是定义在块(即大括号{})内的;程序运行进入这个块之前,其中的变量不存在;离开这个块,其中的变量就消失了;
  • 块外面定义的变量在块里面仍然有效;块里面定义了和外面同名的变量则掩盖了外面的;
  • 不能在同一个块定义同名的变量;
  • 本地变量不会被默认初始化;参数在进入函数的时候被初始化了。

2.5 其他细节

  • 如果确定函数没有参数,函数定义写为void f(void);
    void f(); 表示f函数的参数表未知,并不表示没有参数;
  • 调用函数时的圆括号里的逗号是标点符号,不是运算符
    f(a, b)和f((a, b))区别在于前者传递了两个参数,后者传递了一个参数。
  • C语言不允许函数嵌套定义

3. 二维数组

定义:int a[3][5]; 通常理解为a是一个3行5列的矩阵:
在这里插入图片描述

3.1 二维数组的遍历

for ( i=0; i<3; i++)
	{
		for ( j=0; j<5; j++)
		{
			a[i][j] = i*j; 
			//a[i][j]是一个int,表示第i行第j列上的单元
		}
	}

3.2 二维数组的初始化

	int a[][5]=
	{
		{0,1,2,3,4},
		{1,2,3,4,5},
		{2,3,4,5,6},
	};
  • 列数是必须给出的,行数可以由编译器来数
  • 每行一个{},逗号分隔
  • 最后的逗号可以存在,有古老的传统
  • 如果省略,表示补零
  • 也可以用定位(C99 ONLY)

  注意:只有定义时可以这样初始化,定义完成后应通过遍历方法用for循环初始化;原因在于定义完成后a[][]被视作数组中的一个元素,而不是整个数组
  使用变量定义数组时,定义时不能直接初始化,需要之后利用遍历来初始化数组。例如:

const int cnt = 3;
int a[cnt][cnt];  
//此处不能直接对数组进行集成初始化,需要之后利用遍历来初始化数组

3.3 实例分析

tic-tac-toe游戏,详见:二维数组应用之tic-tac-toe游戏胜负判断

4.几点注意

  • “代码复制”是程序质量不良的表现;
  • 算法不一定和人的思考方式相同;单一出口原则(一个return);一专多能是不好的代码;
  • 小技巧:在程序中平白无故加个大括号,多数时候是为了调试程序,(观察程序输出过程)利用本地变量的规则,方便调试。
  • 收获:程序运行结果错误时,利用编译器的调试功能,一步一步调代码,观察代码运行过程,一般都可以发现错误所在;
发布了46 篇原创文章 · 获赞 84 · 访问量 1万+

猜你喜欢

转载自blog.csdn.net/weixin_43871127/article/details/104260031