4.0. 函数 程序的最小独立单元 - 语句 程序:为解决某一问题而设计的一系列有序指令的集合。 数据说明:数据的描述(数据的名称、类型、和初值等) 语句:如何处理数据的描述
函数的定义: 函数就是对某一特定功能的抽象 函数的作用: 代码重用,模块化(便于定位错误) 例:编写一个加法函数,参数为两个值,无返回值。
函数的分类
通过用来执行一些功能比较单一的语句 例如:getchar()
有参函数
通过处理传递过来的参数将函数值返回给主调函数
Sin(),cos()
库函数分为标准库函数和第三方库函数。 库函数的特点:右C语言提供;用户无需定义,也不必再程序中做类型说明,只想要在程序前包含有该函数的头文件。 典型的如:system()
函数定义的语法格式: 函数定义有4个要素:参数列表,返回类型,函数名和函数体,参数列表和返回值类型,函数名用于和程序中其他实体区分,而函数体是一段可执行的代码块,实现特定的算法或功能。函数调用的两种方式
函数调用有两种类型,一是”先定义,后调用”,这要求函数定义和调用语句在同一个文件内,编译器能从函数定义中提取函数的参数列表、输出类型等接口信息。
如果没有函数的定义,就想要将函数实例写在主调用函数之前。 举例:函数声明和调用在一个文件内:
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> void add (int a,int b) ;int main () {int num1,num2;printf ("请输入数值a:" );scanf ("%d" , &num1);printf ("\n请输入数值b:" );scanf ("%d" , &num2);add (num1,num2);system ("pause" );return 30 ;} void add (int a, int b) {int c = a + b;printf ("a+b = %d\n" , c);}
二是”函数声明+函数调用” 大多数情况下,函数的定义与函数的调用,并吧在一个文件内,即使在一个文件中也有可能调用在前而定义在后,这时想要,在调用之前先对函数声明,告诉编译器有这么一个函数的存在。
举例:函数的跨文件调用
#pragma once #define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> void Hello () {printf ("Hello World\n" );}
#include "4.0 函数.h" void add (int a,int b) ;int main () {int num1,num2;printf ("请输入数值a:" );scanf ("%d" , &num1);printf ("\n请输入数值b:" );scanf ("%d" , &num2);add (num1,num2);Hello ();system ("pause" );return 30 ;} void add (int a, int b) {int c = a + b;printf ("a+b = %d\n" , c);}
函数注意事项:
函数的定义在程序中都是平行的,即不允许在一个函数的内部调用(再写)另一个函数。
函数名是用户自定义标识符,当函数值为整型时类型名可省略。当函数不需要向调用出返回值时,使用void类型名。
形参列表中的形参是用户自定义标识符,没有参数时,圆括号不能省略,此时函数为无参函数。
函数在没有声明的时候必须写在主调函数Main之前否则会出错。因为程序是自上而下执行的4.1. 数组 数组的概念
数组的概念:
数组是可以在内存中连续存储多个元素的结构 数组中的所有元素必须属于相同的数据类型 举例:int a[5] = {0,1,2,3,4}; printf(“&a”); 在内存中查看连续的5个元素
数组语法
类型数组名[数组元素个数] = {数组元素};
例如:int a[10] = {0};
int a[] = {1,2,3}; // 当数组元素确定的时候数组个数可以省略
int a[5] = {1,2,3}; // 不足填充0
printf(“%d\n”, sizeof(a) / sizeof(int));// 查看数组元素的个数
一组数组就好比对货物的编号。 注意:数组的下标是从0开始的。数组在内存中是连续排列的 告诉编译器4条信息:数组名是a,存放的元素是int型,数组存放的元素个数为10,元素值为0,这样便可以对数组及数组元素进行读写访问。
#include <stdio.h> #include <stdlib.h> #define N 5 void main () {int a[N] = {1 ,2 ,3 ,4 ,5 };for (int i = 0 ; i < N; i++) {printf ("%d\n" , a[i]);} printf ("%p\n" , &a); printf ("%d\n" , sizeof (a)); printf ("%d\n" , sizeof (a) / sizeof (int )); for (int i = 0 ; i < N; i++) {printf ("a[%d] = %d &a[%d] = %x\n" , i, a[i], i, &a[i]); } system ("pause" );}
4.1.1 二维数组
概念
一维数组常称为向量,二维数组,最简单的理解是”有两个下标”,如果把一维数组理解为一行数据,那么,二维数组可形象地表示为行列结构。X Y就是二维,X Y Z 就是三维 例子:int a[2][3] = {1,2,3,4,5,6} 其中第一个方括号中的元素代表行,第二个方括号中的元素代表列
查看数组在内存当中的分布。
#include <stdio.h> #include <stdlib.h> void main () {int a[3 ][5 ] = { { 1 ,2 ,3 ,4 ,5 },{6 ,7 ,8 ,9 ,10 },{11 ,12 ,13 ,14 ,15 } };printf ("%p\n" , &a);printf ("%d\n" , sizeof (a)); printf ("%d\n" , sizeof (a) / sizeof (int )); system ("pause" );}
初始化二维数组
注意:二维数组中的元素同样是给分配在一段连续的内存 初始化表达式中内层花括号代表一行,这样和一维数组中只能对前几个元素初始化不同,二维数组的初始化可以跳过某些中间元素,给后面的元素赋值。
int a[2 ][3 ] = {{1 ,2 ,3 },{4 ,5 ,6 }};
也可以这样初始化:
int a[][4 ] = {{1 ,2 ,3 ,4 }};
大括号初始化了以后,行号可以省略
两种赋值方法: #include <stdio.h> #include <stdlib.h> void main () {int a[3 ][5 ] = { { 1 ,2 ,3 ,4 ,5 },{6 ,7 ,8 ,9 ,10 },{11 ,12 ,13 ,14 ,15 } };printf ("%p\n" , &a);printf ("%d\n" , sizeof (a)); printf ("%d\n" , sizeof (a) / sizeof (int )); for (int i = 0 ; i < 3 ; i++) {for (int j = 0 ; j < 5 ; j++) {printf ("a = %d\n" , a[i][j]);} } printf ("------------------------------------------------\n" );int b[3 ][5 ] = { 0 };int c[3 ][5 ] = { 0 };for (int i = 0 ; i < 15 ; i++) {b[i / 5 ][i % 5 ] = i; } for (int i = 0 ; i < 3 ; i++) {for (int j = 0 ; j < 5 ; j++) {c[i][j] = i * 5 + j + 1 ; } } for (int i = 0 ; i < 3 ; i++){for (int j = 0 ; j < 5 ; j++) {printf ("b = %d\n" , b[i][j]);} } printf ("------------------------------------------------\n" );for (int i = 0 ; i < 3 ; i++) {for (int j = 0 ; j < 5 ; j++) {printf ("c = %d\n" , c[i][j]);} } system ("pause" );}
二维数组地址的引用 元素a[i][j]的地址是&a[i][j];二维数组的数组名代表该数组的首地址; 比如:a实际上就是&a[0][0]。二维数组元素在内存中按行存放,第一行的首地址为a[0]第二行的首地址为a[1],……,第n行的首地址为a[n-1]; &a[i][j]等价于 a[i]+j。
4.2 基础算法 选择排序法
如何看懂带算法的程序
看流程判断和循环条件
搞清楚每个语句的功能
试数
调试
模仿改
选择排序法求极值
#include <stdio.h> #include <stdlib.h> void main () {int a[10 ] = { 1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,0 };int Max = a[0 ]; for (int i = 0 ; i < 10 ; i++) {if (Max < a[i]) {Max = a[i]; } } printf ("Max(最大值)的值为:%d\n" , Max);for (int i = 0 ; i < 10 ; i++) {if (Max > a[i]) {Max = a[i]; } } printf ("最小值为:%d\n" , Max);int i = 0 ;while (i < 10 ) {i++; if (Max < a[i]) {Max = a[i]; } } printf ("while循环下Max的值为:%d\n" , Max);system("pause" ); }
选择排序方法一:
#include <stdio.h> #include <stdlib.h> void main () {int a[10 ] = { 1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,0 };int Max = 0 ;for (int i = 0 ; i < 10 - 1 ; i++) { Max = i; for (int j = i + 1 ; j < 10 ; j++) {if (a[Max] < a[j]) {int team = a[j];a[j] = a[Max]; a[Max] = team; } } for (int i = 0 ; i < 10 ; i++) {printf (" %4d" , a[i]);} printf ("\n" );} printf ("------------- 最终结果 ---------------\n" );for (int i = 0 ; i < 10 ; i++) {printf ("a 的值为:%d\n" , a[i]);} system ("pause" );}
选择排序法方法二(优化):
#include <stdio.h> #include <stdlib.h> void main () {int a[10 ] = { 1 ,2 ,3 ,4 ,5 ,6 ,7 ,8 ,9 ,0 };int Max = 0 ;for (int i = 0 ; i < 10 - 1 ; i++) {Max = i; for (int j = i + 1 ; j < 10 ; j++) {if (a[Max] < a[j]) {Max = j; } } if (Max != i) {int team = a[i];a[i] = a[Max]; a[Max] = team; for (int i = 0 ; i < 10 ; i++) {printf ("%4d" , a[i]);} } printf ("------------- 最终结果 ---------------\n" );for (int i = 0 ; i < 10 ; i++) {printf ("%4d\n" , a[i]);} system ("pause" );}
冒泡排序法 冒泡排序法求极值
#include <stdio.h> #include <stdlib.h> void main () {int a[10 ] = { 9 ,8 ,7 ,6 ,5 ,4 ,3 ,2 ,1 ,0 };for (int i = 0 ; i < 10 - 1 ; i++) {if (a[i] > a[i + 1 ]) {int team = a[i + 1 ];a[i + 1 ] = a[i]; a[i] = team; } } printf ("a 的最大值为:%d\n" ,a[9 ]);system("pause" ); }
冒泡排序法
#include <stdio.h> #include <stdlib.h> void main37 () {int a[10 ] = { 9 ,8 ,7 ,6 ,5 ,4 ,3 ,2 ,1 ,0 };for (int i = 0 ; i < 10 - 1 ; i++) {for (int j = 0 ; j < 10 - 1 - i; j++) { if (a[j] > a[j + 1 ]) {int team = a[j + 1 ];a[j + 1 ] = a[j]; a[j] = team; } } for (int i = 0 ; i < 10 ; i++) {printf ("%4d" , a[i]);} printf ("\n" );} printf ("\n------------- 最终结果 ---------------\n" );for (int i = 0 ; i < 10 ; i++) {printf ("%d\n" , a[i]);} system("pause" ); }
二分查找法 二分查找法用于快速查找信息或数据,当然还有更快的方法插值算法 二分查找法,是去一段数据的中间值,我们用中间值和我们的数据进行比较,如果我们的数大于中间值,那么小于中间值的我们就不需要进行比较。 然后我们找到需要进行比较的头和尾,再去中间值进行判断去排除。反复的循环就可以找到我们需要的数 例如: 我们有一个数组从1-12,我们需要的数值是9。 那么我们可以算出1-12的中间值为6。 6和9进行比较,9大于6那么1-6都排除, 我们重新定义7为数据的头12为数据的尾。 假设我们定义11为中间值,9是小于11的那么11-12就可以排除 我们定义7-10为头和尾进行比较。以此类推我们就可以获取到我们的值。
#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> void FindNum (int a[], int data) ;void main () {int a[1000 ] = { 0 };for (int i = 0 ; i < 1000 ; i++) {a[i] = i; printf ("i = %d\n" ,i); } int data;printf ("请输入您要查询的值:" );scanf ("%d" ,&data);FindNum(a,data); system("pause" ); } void FindNum (int a[], int data) {int head = 0 ;int foot = 1000 - 1 ;int flag = -2 ; int ci = 0 ; while (head <= foot) {int median = (head + foot) / 2 ;printf ("head 的值:%d Foot的值:%d Median的值:%d 次数:%d\n" ,head,foot,median,++ci);if (data == a[median]) {printf ("找到了 data的值为:%d\n" , data);flag = 1 ; break ;}else if (data > a[median]) { head = median + 1 ; }else { foot = median - 1 ; } } if (flag == -2 ) { printf ("找不到这个值\n" );} }