-
2018-10-10 00:46:54
- 基本概念
- 数据:描述客观事物的符号,是计算机中可以操作的对象,是能被计算机识别,并输入给计算机处理的符号集合。
(注意:
1.数据有两个特点,一是可以输入到计算机中二是能够被计算机程序处理
2.数据不仅仅包括整型,实型等数值类型还包括字符及声音图像视频等非数值类型) - 数据元素:组成数据,有一定意义的基本单位在计算机中通常作为整体处理也被称为记录
- 数据项:一个数据元素可以由若干个数据项组成(数据项是数据不可分割的最小单位)
- 数据对象:性质相同的数据元素的集合,是数据的子集
- 数据结构:
数据元素+特定关系=数据结构
数据结构是相互之间存在一种或多种特定关系的数据元素的集合
- 逻辑结构
- 集合结构:数据元素同属于一个集合,相互之间没有关系
- 线性结构: 数据元素中一对一的关系
- 图形结构: 数据元素中多对多的关系
- 物理结构
- 定义:又叫做存储结构,是指数据的逻辑结构在计算机中的存储形式
- 顺序存储结构:把数据元素存储在地址连续的存储单元
数据间的逻辑关系与物理关系一致 - 链式存储结构:把数据元素存放在任意的存储单元里
- 抽象数据类型
- 数据类型:
计算机中内存空间是有限的不同类型的数据分配的内存空间大小不同
数据类型是指一组性质相同的值的集合及定义在此集合上的一些操作的总称
在C语言中,按照取值的不同,数据类型分为两类即原子型和结构型 - 抽象数据类型:是对已有的数据类型进行抽象
抽象数据类型是指一个数据模型及定义在该模型上的一组操作
更多相关内容 -
老九学堂C语言
2021-05-20 07:05:40源自:6-12 综合练习老九学堂C语言#include #include #include #include int main(){int i; //循环变量,多次使用int count = 5; //存放当前娘娘的总数int currDay = 0;//游戏当前进行到了第几天int choice; //用来...源自:6-12 综合练习
老九学堂C语言
#include
#include
#include
#include
int main()
{
int i; //循环变量,多次使用
int count = 5; //存放当前娘娘的总数
int currDay = 0;//游戏当前进行到了第几天
int choice; //用来存放用户的选择
int tempCount; //临时变量,用来存放好感度低于60的个数
int index = -1; //用来存放删除、查找时的索引
char name[8]; //用来存放用户输入的姓名
//姓名数组,最多容纳6个字符串,每个字符串的最大长度为8个字符(英文)
char names[6][8] = {"西施", "貂蝉", "王昭君", "杨玉环", "赵飞燕"};
//级别数组,最多容纳5个字符串,每个字符串的最大长度为8个字符(英文)
char levelNames[5][8] = {"贵人", "嫔妃", "贵妃", "皇贵妃", "皇后"};
//用来存放每个妃子的等级,与levelNames联用。-1表示未启用
int level[] = {0, 2, 0, 0, 0, -1};
//用来存放每个妃子的好感度,-1表示未启用
int loves[] = {100, 100, 100, 100, 100, -1};
printf("姓名\t等级\t好感度\n");
printf("-----------------------\n");
for(i = 0; i < count; i++){
printf("%s\t%s\t%d\n", names[i], levelNames[level[i]], loves[i]);
}
//如何按好感动来冒泡排序
return 0;
}
提问者:正在学习ingC
2019-11-24 10:17
-
老九学堂C语言笔记
2021-01-14 17:06:14P1 1.1 计算机中的程序:为了让计算机执行某些操作或解决某个问题而编写的一系列有序指令的集合。 P2 1.2 算法:算法是一个定义明确的计算过程,可以以一些值或一组值作为输入并产生一些值或一组值作为输出。...P1 1.1
计算机中的程序:为了让计算机执行某些操作或解决某个问题而编写的一系列有序指令的集合。
P2 1.2
算法:算法是一个定义明确的计算过程,可以以一些值或一组值作为输入并产生一些值或一组值作为输出。因此算法就是将输入转为输出的一系列计算步骤。
(1) 枚举法(穷举法)
(2) 迭代法
(3) 递归法
P3 1.3
C语言应用范围:文字处理程序及电子表格,编译器,操作系统,网络游戏等等。
C语言特点:
1.结构化的程序设计语言
(1)层次清晰,便于按模块化的方式组织程序,易于调试和维护
(2)结构化的缺点也很明显,程序的可重用性差
2.语言简洁,灵活方便
3.可移植性好(C语言的编译程序便于移植)
4.功能强大(既可用于系统软件开发,也适用于应用软件开发)P4 1.4
C语言程序的基本结构:
① main()函数是c程序处理的起点/入口(只有一个)
② main()函数可以返回一个值,也可以不返回值。如果某个函数没有返回值,那么在他前面就是关键字void
注:C语言程序中的一个语句可以跨越多行,并且用分号通知编译器该语句已结束。P5 1.5
1.编译:
· 形成目标代码/文件。目标代码是编译器的输出结果,常见扩展名为“.o”或“.obj”
2.连接:
· 将目标代码跟C函数库相连接,并将源程序所用的库代码与目标代码合并形成最终可执行的二进制机器代码(可执行程序)
3.执行:
· 在待定的及其环境下运行c应用程序
P8 2.2
计算机执行程序时,存放组成程序的指令和程序所操作的数据的地方叫计算机的内存,也成为了主存或随机访问存储器
P9 2.3
变量:
计算机中一块特定的内存空间(一个数据存储空间的表示),由一个或多个连续的字节组成;不同数据存入具有不同内存地址的空间,相互独立。变量的命名:
通过变量名可以简单快速地找到在内存中存储的数据。C语言变量名命名规则:
①C语言规定变量名(标示符)只能由字母、数字、下划线3中字符组成,且第一个字符必须为字母或下划线;
②变量名不能包含除_以外的任何特殊字符。如:%、#、逗号,空格等;
③不可以使用保留字。
P12 2.6
char字符型变量,char类型是否有符号取决于编译器。
eg:声明及初始化
char sex = ‘m’;常用的ASCII码汇总表:
P13 2.7
转义字符:
scanf函数:
scanf是C函数库中最通用的一个函数,可以读取不同格式的数据。#include <stdio.h> int main() { int num; printf("请输入数量:"); scanf("%d",&num); return 0; }
P17 3.2
· (1)自动类型转换(隐式类型转换)(系统自动实现):
原则:把表示范围小的类型的值转换到表示范围大的类型的值(将短的数据类型转换为长的数类型,精度低的向精度高的转换,提高运算精度)。
short(char)->int->unsigned->long->float->double
· (2)强制类型转换(人为控制):
语法:(类型名)变量或数值。
eg:(double)’A’
强制类型转换运算符为单目运算其优先级与结合性和“!”、“++”、“–”一致。
eg:(int)1.8+2.5 //将double型数据1.8强制转换为int型数据1,表达式的值为3.5
eg:(int)(1.8+2.5) //将表达式“1.8+2.5”的double型值4.3强制转换为int型数据4
强制类型转换与隐式类型转换一样,也只是针对计算过程中临时数据的类型进行转换,并不实际改变变量的类型。P18 3.3
运算符:
① 赋值运算符
单等号=
计算顺序:从右向左
② 算术运算符
算术运算符可以进行算术运算
一元运算符:++、–
二元运算符:+、-、/、%
③ 关系运算符
关系运算符可以比较大小、高低、长短
<、>、>=、<=、==、!=
C语言中,0表示假,1(非零)表示真
④ 逻辑运算符位运算符
sizeof运算符:
· · 使用sizeof运算符可以获得数据类型占用内存空间的大小
基本用法:sizeof(type name)
结果以字节为单位#include <stdio.h> int main() { printf("sizeof(int)=%d\n", sizeof(int)); printf("sizeof(double)=%d\n", sizeof(double)); printf("sizeof(char)=%d\n", sizeof(char)); return 0; }
P19 3.4
优先级:
P22 3.7
· · switch结构
(1) switch后的表达式只能是整型或字符型
(2) case后常量表达式的值不能相同
(3) case后允许多多条语句,不需要大括号
(4) 如果不添加break语句,需要特别注意执行顺序
(5) case和default子句的先后顺序可以自行变动
小总结:- 表达式是操作数和运算符的集合;
- 赋值运算符执行顺序是从右到左,优先级最低;
- sizeof运算符用来得到某一数据类型占用的字节数;
- 关系表达式的计算结果为逻辑真(非0)和逻辑假(0);
- 处理条件分支判断的常用结构有三种:
单支:if结构
双支:if-else结构
多支:if-else if-else结构
switch结构
P24 3.8
· · while循环三要素:
1、循环变量的初值;
2、循环变量的判断;
3、循环变量的更新(循环变量:可以控制循环次数的变量)
累加:1、需要一个变量保存累加和2、循环累加
特点:先判断,后执行P26 4.4
· · 补充:使用循环模拟实现玩家对战,双方初始HP均为100,每次攻击减少5—15HP,HP最先到零或以下的被KO。
#include<stdio.h> #include<stdlib.h> #include<time.h> //时间头文件 #include<windows.h> int main() { //随机函数 srand(time(NULL)); //使用时间作为种子,产生不一样的随机数字 printf("随机数字:%d\n", rand()); //rand的取值范围是0-32767 int hp1 = 100, hp2 = 100; //双方玩家的初始血量 int att1, att2; int i = 1; //对战的轮数 while (hp1 >= 0 && hp2 >= 0)//当两个玩家都活着的时候,继续进行对战过程 { //默认1p首先攻击 att1 = rand() % 11 + 5; //5-15之间的攻击 att2 = rand() % 11 + 5; //玩家1攻击,玩家2掉血 hp2 -= att1; //玩家2攻击,玩家1掉血 hp1 -= att2; if (hp1 <= 0 || hp2 <= 0) { break; } printf("**************************************************\n"); printf("第%d轮:\n", i); printf("玩家1攻击力:%d,玩家2剩余血量:%d\n", att1, hp2); printf("玩家2攻击力:%d,玩家1剩余血量:%d\n", att2, hp1); i++; Sleep(500); //每隔500毫秒打印一次 } printf("KO!~游戏结束,玩家1的血量:%d\t玩家2的血量:%d\n", hp1, hp2); return 0; }
P27 4.5
do{
循环操作
}
while(循环条件);· · 特点:先执行,在判断。
先执行一遍循环操作;符合条件,循环继续执行;否则循环退出。
while和 do-while循环的区别:
(1) 执行顺序不同;
(2) 初始情况不满足循环条件时,while循环一次都不会执行;do-while循环不管任何情况至少执行一次P29 5.2
语法:
for(表达式1;表达式2:表达式3:)
{
语句;
}
表达式1,通常是为循环变量赋初值,可省略
eg:i=0或cnt=20或count=1
表达式2:循环条件,是否继续执行循环,可省略
eg:i<10或cnt==20或count>=5
表达式3:更新循环变量的值,可省略
eg:i++或cnt_+=2或count—
分号,用来分隔三个表达式不可省略! For(::)是死循环const:常量(C语言里面常量命名时字母要大写)
P30 5.3
break语句的作用:调出循环,执行循环之后的语句
P31 5.4
· · continue语句的作用:跳过本次循环,继续下次循环
· · break和continue对比:
① break可用于switch结构和循环结构中
② continue只能用于循环结构中
· · 作用:
break语句终止某个循环,程序跳转到循环块外的下一条语句。
continue跳出本次循环,进入下一次循环P32 5.5
· · 循环结构总结
相同点:多次重复执行一个或多个任务时考虑使用循环结构来解决问题。
区别:除了语法不同,判断和执行的顺序也不同
使用情况也不同
(1) 循环次数确定的情况下,通常选用for循环;
(2) 循环次数不确定的情况时,通常选用while和do-while循环P33 5.6
· · rand() 取值范围是:0—32767
P34 6.1
· · 什么是数组:
数组是一个变量,由数据类型相同的一组元素组成。(内存中的一串连续的空间)
数组只有一个名称,即标识符(用来表示数组的变量名);
元素的下标标明了元素在数组中的位置,从0开始;
数组中的每个元素都可以通过下标来访问;
数组长度固定不变,避免数组越界;· · 数组的结构和基本要素:
① 标识符:数组的名称,用于区分不同的数组
② 数组元素:向数组中存放的数据
③ 元素下标:对数组元素进行编号
④ 元素类型:数组元素的数据类型P35 6.2
数组的使用:一维数组的初始化
//正确:后面的元素个数与声明一致int years[6]={11,22,33,44,55,66};
//正确:后面的5个元素未初始化,默认值为0
int months[12]={1,3,5,7,8,10,12};
//正确:元素个数为2
iny days[]={1,15};
//错误:未知元素个数
int array[]={};
一维数组的动态赋值:
动态地从键盘录入信息并赋值
宏定义:#define N 5 //定义数组的容量P37 6.4
例:
循环录入5个整型数组,进行降序排列(从大到小)后输出结果。
(比如输入23,90,9,25,16)方案:使用冒泡排序
冒泡排序的基础原理:遍历和交换。
特点:
1、需要比较多轮(数组长度-1轮)
2、每一轮比较的次数比上一轮-1次(初始值N-1次)
(数组长度-1)-当前的轮数=N-i-1
第一轮循环:(比较了数组长度-1次)
某个数字小于后面的数字,那么就交换,最小的数字就冒到了最后#include<stdio.h> #define N 5 int main() { int i, j; //循环变量//i控制轮数,j控制每一轮的次数 int temp; //用来交换的临时变量 int nums[N] = { 16,25,9,90,23 }; for (i = 0; i < 5; i++) //外层循环控制轮数 { //内层循环控制每轮的次数 for (j = 0; j < N - i - 1; j++) { //如果当前值小于后面一个值,就交换 if (nums[j] < nums[j + 1]) { temp = nums[j]; nums[j] = nums[j + 1]; nums[j + 1] = temp; } } } printf("排序后的结果是:\n"); for (i = 0; i < N; i++) { printf("%d\t", nums[i]); } return 0; }
逆序:
1····2····3····4····5····6
i···························N-i-1
·····1···············N-i-1
第一个元素和最后一个元素交换
第二个元素和倒数第二个元素交换for (i = 0; i < N / 2; i++) { temp = nums[i]; nums[i] = nums[N - i - 1]; nums[N - i - 1] = temp; }
P38 6.5
数组元素的删除和插入
删除的逻辑:- 查找要删除数字的下标
- 从下标开始,后面的一个覆盖前面一个数字
- 数组的总长度-1
#include <stdio.h> #define N 5 int main() { int count = 5; //表示数组元素的个数 double powers[] = { 42322,45771,40907,41234,40767 }; double deletePower; //用户要删除的战力值 int deleteIndex=-1; //要删除战力值的下标,赋一个不可能的值用来判断 int i; //循环变量 double insertPower; //新插入的战力值 printf("请输入要删除的战力值:"); scanf_s("%lf", &deletePower); for (i = 0; i < count; i++) { if (deletePower == powers[i]) { deleteIndex = i; //记录下当前的下标 break; //找到了要删除的战力值后跳出循环 } } if (-1 == deleteIndex) //根据判断(是否找到),执行后续的操作 { printf("没有找到,删除失败\n"); } else //从下标开始,后面一个覆盖前面一个数字 { for (i = deleteIndex; i < count - 1; i++) { powers[i] = powers[i + 1]; } count--; //删除后数组总长度-1 } printf("删除后的结果为:\n"); for (i = 0; i < count; i++) { printf("%.2lf\t", powers[i]); } printf("\n"); //删除之后进行插入 printf("请输入新战力值:"); scanf_s("%lf", &insertPower); powers[count] = insertPower; //count在删除后为4,此时代表4号元素 count++; //插入操作完毕之后,数组总长度+1 for (i = 0; i < count; i++) { printf("%.2lf\t", powers[i]); } return 0; }
总结:
- 数组是可以在内存中连续存储多个元素的结构;
- 数组中的所有元素必须属于相同的数据类型;
- 数组必须先声明,然后才能使用;
- 声明一个数组只是为该数组留出内存空间,并不会为其赋任何值;
- 数组的元素通过数组下标访问;
- 一维数组可用一个循环动态初始化,而二维数组可用嵌套循环动态初始化,二维数组可以看做是由一维数组的嵌套而构成的。
字符串处理函数
· · 字符串处理函数被定义在头文件“string.h”,调用编译指令#include <string.h>,将该头文件包含到本程序中。
1. strcat函数:字符串连接函数
· · strcat(字符数组名1,[字符数组名2|字符串])
· · 作用:把字符数组2或字符串拼接到字符数组1的有效字符数组之后。参数1必须是字符数组,参数2可以是字符数组也可以是字符串,字符数组1应该足够大,以便容纳连接后的字符数组2,(字符串)连接时,字符数组1的”\0”被写入的第一个字符覆盖,只保留字符数组2的”\0”。#include <stdio.h> #include <string.h> int main() { char a[20] = "I"; char b[] = " am"; puts(a); strcat_s(a, b); puts(a); strcat_s(a, " happy"); puts(a); return 0; }
2. strcpy函数:字符串复制函数
· · strcpy(字符数组名1,[字符数组名2|字符串])
· · 作用:将字符数组2或字符串连同“\0”一起复制到字符数组1中。
参数1必须是字符数组,参数2则可以是字符数组也可以是字符串,字符数组1应该足够大,以便容纳复制后的字符数组2(字符串)3. strcmp函数:字符串比较函数
· · strcmp([字符数组名1|字符串1],[字符数组2 | 字符串2])
· · 作用:将两个字符串自左至右逐个字符比较(按ASCII码值大小比较),直到出现不同的字符或遇到“\0”为止。
当字符串1 = 字符串2时,函数的返回值为0。
当字符串1 > 字符串2时,函数的返回值为正整数。
当字符串1 < 字符串2时,函数的返回值为负整数。#include <stdio.h> #include <string.h> #define USER_NAME "admin" #define PASSWORD "admin" int login(char userName[], char password[]); int main() { char userName[25], password[25]; printf("用户名:"); fgets(userName,25,stdin); printf("密码:"); fgets(password, 25, stdin); if(login(userName, password) == 0) { printf("登陆成功!\n"); } else { printf("登录失败!\n"); } return 0; } int login(char userName[], char password[]) { if ((strcmp(userName, USER_NAME) != 0 || strcmp(password, PASSWORD) != 0)) { return 0; } //验证合法 return 1; }
4. strlen函数:测试字符串长度函数
· · strlen([字符数组名|字符串])
· · 作用:统计字符串的有效字符个数,遇见(不包括)第一个“\0”结束,该函数的返回值为字符串的有效字符个数。5. strlwr函数:字符串小写函数
· · strlwr(字符数组名)
· · 作用:将字符数组中的大写字母转换成小写字母,并存储。6. strupr函数:字符串大写函数
· · strupr(字符数组名)
· · 作用:将字符数组中的小写字母转换成大写字母,并存储。· · 例:找出二维数组的鞍点,即其值为所在行中最大、所在列中最小的元素(一个二维数组也可能没有鞍点)
#include <stdio.h> int main() { int a[3][4]; int i, j, k, max, maxj; //k用于检查某行中数值最大的元素是否在所在列中数值最小 //的元素,以控制同列元素的行下标,maxj用于接收鞍点元素的列下标 printf("请输入二位数组:\n"); for (i = 0; i < 3; i++) { for (j = 0; j < 4; j++) { scanf_s("%d", &a[i][j]); } } for (i = 0; i < 3; i++) { max = a[i][0]; //假设当前行的第一个元素数值最大 maxj = 0; //用maxj记录当前行第一个元素的列下标 for (j = 0; j < 4; j++) //遍历二维数组的每一行 { if (a[i][j] > max) { max = a[i][j]; //用当前行数值更大的元素更新max maxj = j; //用maxj记录该元素的列下标 } } for (k = 0; k < 3; k++) { if (max > a[k][maxj]) //用当前行最大的元素和同列中其他元素比较 break; } if (k >= 3) //如果是自然退出,则输出鞍点值,程序直接跳出整个循环, //如果是直接跳出,说明啊a[i][maxj]不是鞍点,程序不执行if语句, //直接执行最外层for循环,进入下一行重复寻找鞍点的工作 { printf("该二维数组的鞍点为:a[%d][%d]=%d\n", i, maxj, max); break; } } if (i >= 3) //通过判断循环控制变量i的当前值,来确定程序流程是直接跳出 //还是自然跳出最外层for循环结构 //如果是直接跳出,说明已找到并输出鞍点,不执行if语句 //(if(k>=3)语句是自然退出) //如果是自然退出的,说明最终没有找到鞍点,执行if语句 //(if(k>=3)语句是直接跳出) printf("该二维数组没有鞍点\n"); return 0; }
P43 8.1
指针:
指针是一个值为内存地址的变量(或数据对象)
基本用法:数据类型 * 指针变量名
指针变量存放的是变量的地址,地址作为一个整数值,在内存中以二进制补码的形式存储。
几个小概念:
① 地址:内存中每个存储单元的编号
② 变量:内存中某个特定的存储单元
③ 变量的地址:某一变量所在的存储单元的地址编号
④ 变量的名称:为该存储单元所定义的名称,便于程序设计
⑤ 变量的值:存放在特定存储单元中的数据
⑥ 变量的指针:变量的地址
⑦ 指针变量:存放地址的变量
⑧ 指向变量的指针变量:存放某个特定变量地址的指针变量,通过该指针变量可以指向特定的变量。
例如:int * ptr_num; char * ptr_name; float * money_ptr; double * p_price;
· · 注:在头文件<stdio.h>中,NULL被定义为常量,int * ptr_num=NULL;
指针的初值设为空,表示指针不指向任何地址。
取地址符&:
num····················ptr_num
1024 <— — — — 0028FF44#include <stdio.h> int main() { int num=1024; int * ptr_num; //取num变量的地址赋值给ptr_num ptr_num=# printf("num的变量地址是:%p\n",&num); return 0; }
%p:指针类型数据占位符
%x:16进制占位符间接运算符
num···········ptr_num
1024<········0028FF44
0028FF44int num=1024; int * ptr_num; ptr_num = # *ptr_num = 1024;
指针使用示例:
#include <stdio.h> void main() { itn num=1024; //整型变量 int* ptr_num; //整形指针变量 //取num的地址复制给ptr_num变量 ptr_num=# printf("num的值为:%d\n",num); printf("num的内存地址为:%p\n",&num); printf("ptr_num的值为:%p\n",ptr_num); printf("ptr_num的内存地址为:%p\n".&ptr_num): printf("ptr_num指向的值为:%d\n",*ptr_num); }
P45 8.3
指针小结:
指针同样是一个变量,只不过该变量中的存储的是另一个对象的内存地址。如果一个变量存储另一个对象的地址,则称该变量指向这个对象。
指针变量可赋值,指针的指向在程序执行中可以改变。
指针p下执行中某时刻指向变量x,在另一时刻也可以指向变量y
注:
(1)指针变量的命名规则和其他变量的命名规则一样;
(2)指针不能与现有变量同名;
(3)指针可存放C语言中的任何基本数据类型、数组和其他所有高级数据结构的地址;
(4)若指针已声明指向某种类型数据的地址,则它不能用于存储其他类型数据的地址;
(5)应为指针定一个地址后,才能在语句中使用指针.P46 9.1
指针与数组
数组:存储在一块连续的内存空间中,数组名就是这块连续内存空间的首地址。(比如:int num[10],num的值与num[0]值相同的)
指针的算术运算
1.指针的递增和递减(++、–)注:一个类型为T的指针的移动,以sizeof(T)为移动单位。
·
使用指针访问数组元素的方式:
#include <stdio.h> int main() { int i; double score[] = { 99,55,66,77,88 }; double* ptr_score = score; //使用指针访问数组元素 for (i = 0; i < 5; i++) { //printf("%.2lf\t", ptr_score[i]);//第一种当访问方式 //printf("%.2lf\t", *ptr_score);//相当于访问了第0个元素 printf("%.2lf\t", *(ptr_score+i));//第二种访问方式 //printf("%.2lf\t", *ptr_score++);//第三种访问方式 } return 0; }
第一种:数组名就是一个地址,已经是一个指针,把地址的值赋值给另外一个指针时,另外一个指针仍然把它当做数组来操作。
第三种:循环一次之后,指针指向最后一个元素的地址,如果要再次访问数组元素,要重置指针的位置。
2.指针加上或减去某个整数值
小结:
数组的第 i + 1 个元素可表示为:
· 第 i + 1 个元素的地址:&num[ i ] 或num + i
· 第 i + 1 个元素的地址:num[ i ] 或 *(num + i)为指向数组的指针赋值:
· int * ptr_num = num; 或 int * ptr_num = &num[ 0 ];指针变量可以指向数组元素
· int * ptr_num = &num[ 4 ]; 或 int * ptr_num = num + 4;P47 9.2
使用指针实现数组逆序
#include <stdio.h> #define N 5 int main() { int array[N] = { 15 ,20 ,35 ,40, 50 }; int temp; int i; int* ptr_array_start = array;//指向数组首元素的指针 int* ptr_array_end = array + N - 1;//指向数组末元素的指针 while (ptr_array_start<= ptr_array_end) { //首尾交换,指针分别进行更新 temp = *ptr_array_start; *ptr_array_start = *ptr_array_end; *ptr_array_end = temp; //首元素指针向后移动 ptr_array_start++; //末元素指针向前移动 ptr_array_end--; } printf("交换后的数组顺序为:\n"); ptr_array_start = array; for (i = 0; i < N; i++) { printf("%d\t", *(ptr_array_start + i)); } return 0; }
P48 9.3
二维数组与指针
#include <stdio.h> int main() { //数组名就是数组的首地址(数组首元素地址) //二维数组的理解:是由n个1维数组所组成 int i, j; double score[5][3] = { {56,66,77},{53,62,71},{52,61,73} ,{56,69,75} ,{57,60,76} }; for (i = 0; i < 5; i++) { for (j = 0; j < 3; j++) { //printf("%.1lf\t", *(score[i] + j)); printf("%.1lf\t", *(*(score + i) + j)); } printf("\n"); } printf("***********************\n"); //********************************************** double(*ptr_score)[3] = score; for (i = 0; i < 5; i++) { for (j = 0; j < 3; j++) { printf("%.1lf\t", *(*(ptr_score + i) + j)); } printf("\n"); } return 0; }
P50 11.1 函数
· · 函数定义:是完成特定任务的独立程序代码,语法规则定义包含了函数的结构和使用方式。
· · 函数的定义是对函数功能的确立,包括指定函数名、返回值类型、 形参及其类型、函数体等,是一个完整的独立的函数单位;
所有函数都是平行的,即所有函数的定义是分别进行且是相互独立的,函数不能嵌套定义;
· · 函数的声明是告诉编译器一个函数的作用域,返回值类型、函数名、可以接受的参数个数、参数类型及其顺序等信息,以便编译器执行安全检查;
函数的种类:
① 内置函数
由C语言系统提供;需要在程序前包含定义函数的头文件。#include <stdio.h> #include <ctype.h> int main() { //常用内置函数 printf("%d\n", isupper('a')); printf("%d\n", islower('a')); printf("%d\n", isalpha(97)); //如果传入的是数字,表示的是ASCII码 printf("%d\n", isdigit('9'));//返回字符是否为数字 int i;9 for (i = 0; i < 127; i++) { printf("%c,", i); } return 0; }
ceil函数:进一
floor函数:去尾
如果是负数,规律相反#include <stdio.h> #include <math.h> int main() { printf("%.2lf\n", ceil(98.01)); printf("%.2lf\n", floor(98.9)); return 0; }
② 自定义函数
不带参数和带参数P52 11.3
常用的内置函数
system函数常见用法:
- 冻结屏幕,便于观察程序的执行结果
system("pause");
- 清屏操作
system("cls");
- 修改背景色及前景色
system("color 4E");
- 设置自动关机:
#include <stdio.h> #include <stdlib.h> void main() { system("shutdown /r /t 180"); //system("shutdown /a"); //取消关机 }
P53 12.1
内置函数补充
mallco()
① malloc的全称是memory allocation。中文叫动态内存分配,当无法知道内存具体位置的时候,想要绑定真正的内存空间,就需要用到动态的分配内存。
② 分配长度为num_ bytes字节的内存块。
③ 函数原型:extern void * malloc(unsigned int num_bytes)。
④ 如果分配成功则返回指向被分配内存的指针(此存储区中的初始值不确定),否则返回空指针NULL。
⑤ 当内存不再使用时,应使用free()函数将内存块释放(原始内存中的数据保持不变)。#include <stdio.h> #include <stdlib.h> int main() { int* num; int i; //为前面的指针动态分配了20个字节(5个整型)的空间 num = (int *)malloc(sizeof(int) * 5); //等价于:int nums[] //为指针动态分配空间后,指针就变成了数组 num[4] = 9; for (i = 0; i < 5; i++) { printf("%d\n", num[i]); } free(num);//用完释放内存 num = NULL; return 0; } /*****************************************************************/ #include <stdio.h> #include <stdlib.h> void main() { int* num; int i; //作用与malloc类似 //不需要强制转换,直接返回数组 //两个参数,默认初始化数组元素 num = (int*)calloc(5, sizeof(int)); num[4] = 9; for(i = 0; i < 5; i++) { printf("%d\n", num[i]); } free(num);//用完释放内存 num = NULL; }
注:关于free函数
- 必须是通过malloc、calloc或realloc(重新分配内存)分配内存的指针;
- 释放的指针必须是初始分配的地址,进行运算后需要恢复
realloc()
① 原型:extern void * realloc(void * mem_address, unsigned int newsize);
② 用法:#include <stdlib.h>有些编译器需要#include <alloc.h>
③ 功能:改变mem_address所指内存区域的大小为newsize长度
④ 说明:如果重新分配成功则返回指向被分配的指针,否则返回空指针NULL。
⑤ 当内存不再使用时,应使用内存free()函数将内存块释放(原始内存中的数据保持不变)malloc , calloc , realloc:
P54 12.2
自定义函数
函数三要素:
- 返回值类型
- 函数名
- 参数列表
自定义函数的完整写法:
#include <stdio.h> //函数原型 int sum(int, int); int main() { ..... } //函数定义 int sum(int num1, int num2) { //函数实现的代码 }
注:
- 函数原型与函数定义的头部类似,最后以分号结尾
- 函数原型中的参数名称可以省略,只写参数类型
带返回值的函数:
C语言中的返回值:
① 关键字:return;
② 只能返回一个值,不能返回多个值;
③ 返回值类型必须与原类型中的返回值匹配;
④ return会立刻终止函数并返回,可返回空值。P56 13.1
形式参数和实际参数
P58 13.3
递归:函数调用自己的过程称为递归
递归需要满足的两个条件
- 有反复的执行过程(调用自身)
- 有跳出反复执行过程的条件(出口)(用return返回)
递归例子
(1)
阶乘:n!=n* (n-1) * (n-2) *...* 1(n>0) /**************************/ int recursive(int i) { int sum=0; if(0==i) return (1); else sum=i*recursive(i-1); return sum; }
(2)汉诺塔问题
//汉诺塔 void hanoi(int n,int p1,int p2,int p3) { if(1==n) cout<<"盘子从"<<p1<<"移到"<<p3<<endl; else { hanoi(n-1,p1,p3,p2); cout<<"盘子"<<p1<<"移到"<<p3<<endl; hanoi(n-1,p2,p1,p3); } }
递归补充:
P59 14.1
变量的作用域和生存期
#include <stdio.h> void main() { int num1 = 99; {//代码块--域 int num2 = 199; printf("%d\n", num1 + num2); } printf("%d\n", num1 + num2); }
错误:变量num2没有被声明(在函数第一次使用)
注意:- 变量只存在于定义他们的语句块中
- 变量在一个语句块内声明叫创建,在这个块结束时销——自动变量
- 变量存在的时间称为变量的生存期
变量的作用域决定了变量的可访问性
#include <stdio.h> void main() { int count = 0; do { int count = 0; count++; printf("count = %d\n", count); } while (++count < 5); printf("count=%d\n", count); }
局部变量:
#include <stdio.h> void changeNum() { //局部变量 int num1 = 5, num2 = 8; num1 = 155; num2 = 288; //nums是局部变量 //函数执行完毕时,会自动销毁函数内部定义的变量 } void main() { int num1 = 5, num2 = 8; changeNum(); printf("num1=%d,num2=%d\n", num1, num2); }
全局变量
(系统自动分配默认值)
int count = 0; void changeNum() { count++; } void main() { count++; changeNum(); printf("count = %d\n",count); }
P60 14.2
变量的存储类型
#include <stdio.h> #include <stdlib.h> int counter();//用来计算本函数被调用了多少次 int counter() { //静态存储 static int count = 0;//第一次执行会分配空间,以后就不再分配空间了--本句只会被执行一次 count++; return count; } int main() { int count = 0; counter(); counter(); counter(); count = counter();//第四次调用 printf("count = %d\n",count); return 0; }
全局变量的作用域只在当前源文件
小结:
变量的生存期
- 变量的存储方式:动态存储(自动,寄存器)、静态存储(静态和外部)
- 由变量的存储方式不同而产生的特性称为变量的生存期(变量的存在时间)
- 基本类型的静态变量系统默认赋初值为0
- 静态变量的生存期为整个源程序,作用域只是定义它的文件
- 函数被调用时,其中的局部静态变量的值保留前次被调用的结果
#include <stdio.h> #include <stdlib.h> void report_count(); void counter(int num); int count = 0; //文件作用域,外部链接 int main() { int value; //自动变量 register int i;//将循环变量设置为寄存器存储模式 printf("请输入循环的次数,按0退出:"); while (scanf_s("%d", &value) == 1 && value > 0) { count++; for (i = value; i >= 0; i--) counter(i); printf("请输入任意数字,0退出:"); } report_count(); } void report_count() { printf("循环执行了%d次\n", count); } extern int count; //引用式声明,外部链接 static int total = 0;//静态定义,内部链接 void counter(int);//函数原型 void counter(int num) { //局部静态变量 static int subTotal = 0; if (num <= 0) { printf("第%d轮循环执行完毕\n", count); printf("局部静态变量subTotal和全局静态变量total:\n"); printf("subTotal:%d\ttotal:%d\n", subTotal,total); subTotal = 0;//每次内循环结束后重置为0 } else { subTotal += num; total += num; } }
P61 15.1
按值传递的机制
按值传递:
给函数传递变元(参数)时,变元(参数)值不会直接传递给函数,而是先制作变元(参数)值的副本,存储在线上,再使用这个副本可用于函数而不是使用初始值
引用传递:
指在调用函数时将实参的地址传递到函数中,那么在函数中对参数所进行的修改,将影响到实际参数
P62 15.2
注:
- 数组作为函数实参时,只传递数组的地址(首地址),并不传递整个数组的空间。
- 当用数组名作为实参调用函数时,数组首地址指针就被传递到函数中。
小技巧:
量数组的大小
int num[]={ 1, 2, 3, 4, 5, 6, 7 }; printf("num数组的元素个数是:%d\n", sizeof(num) / sizeof(num[0]));
P63 15.3
自定义头文件
一般放一些重复使用的代码,例如函数声明,变量声明,宏的定义等。
#ifndef MYHEADER_H_INCLUDED #define MYHEADER_H_INCLUDED //代码部分 #endif//MYHEADER_H_INCLUDED
注:
- MYHEADER_H_INCLUDED为一个唯一的标号,命名规则跟变量的命名规则一样,长根据他所在的头文件名来命名
- 代码含义:如果没有定义MYHEADER_H_INCLUDED,则定义MYHEADER_H_INCLUDED,并编译下面的代码部分,知道遇到#endif
总结
- 根据变量的作用域可以将变量划分为:局部变量和全局变量;
- 根据变量的存储类型(决定生存期)将变量划分为:自动变量、寄存器变量、静态变量、外部变量;
①静态局部变量的生存期为整个源程序,但其作用域为定义该变量的函数
②静态全局变量的生存期为整个源程序,但其作用域为定义该变量的源文件 - 传值调用,在被调函数中改变形参值,知识改变其副本值,而不会影响调用函数中实参值;
- 采用传址调用方式时,传递的是变量的地址值,这样在被调函数中,对形参的操作实际上操作的是实参本身;
- 数组作为函数传递时。实际采用传址方式。
P64 16.1
· · 字符串:
①.一个或多个字符的序列称为字符串
②.C语言中形如’‘My heart is still’’
③.双引号不是字符串的一部分,仅用来告知编译器括起来的是字符C语言中的字符串:使用字符数组存储
注:
- 字符串的最后一个元素一定是空字符"\0"
- 空字符不要和NULL混淆;
- 空字符是字符串的终止符,而NULL只一个符号,标识不引用任何内用的内存地址
· · 字符串与字符数组
字符串和字符数组的区别:最后一位是否是空字符
注:声明存储字符串的数组时,数组大小至少比所存储的字符数多1,因为编译器会自动在字符串常量的末尾添加空字符"\0"。
P65 16.2
gets/puts函数补充:
gets(name1);//scanf("%s",name1);输入字符串 puts(name1);//printf("%s\n",name1);输出字符串
注:
-
gets函数不对接受字符串的buffer进行边界检测,会造成越界,从而产生bug
-
可以使用fgets(name,n,stdin);代替gets,20表示最多读入n-1个字符(stdin:标准的输入流 // 可以通过屏幕得到,in即input(输入));
-
fgets会默认给最后一个元素设置为"\n"(在使用fgets函数接收字符串时,可以使用"\0"替换字符数组的最后一位"\n")。
P66 16.3
小结:
- 所有的字符串都是字符数组,反之不成立
- 三种方式录入字符串;
scanf("%s",name);
gets(name);
fgets(name,n,stdin);
P67 17.1
常用字符串处理函数
在p38有详细介绍P69 17.3
练习
需求说明:实现字符串的加密与解密; 加密方式:将字符串中每个字符加上它在字符串中的位置和一个偏移量5
//实现字符串的加密与解密 //加密方式:将字符串中每个字符加上它在字符串中的位置和一个偏移量5 //例如:xuetang9中,第一个字符x在字符串中的位置为0,那么对应的密文是'm'+0+5 #include <stdio.h> #include <stdlib.h> #include <string.h> #define KEY 5 //偏移量/秘钥 char* encrypt(char[]); char* dencrypt(char[]); int main() { char password[50] = "abcdefg"; encrypt(password); printf("加密后的字符串为:%s\n", password); dencrypt(password); printf("解密后的字符串为:%s\n", password); return 0; } char* encrypt(char password[]) { int i = 0; int count = strlen(password);//字符串长度 for (; i < count; i++) { //将字符串中每个字符加上它在字符串中的位置和一个偏移量5 password[i] = password[i] + i + KEY; } return password; } char* dencrypt(char password[]) { int i = 0; int count = strlen(password);//字符串长度 for (; i < count; i++) { //将字符串中每个字符加上它在字符串中的位置和一个偏移量5 password[i] = password[i] - i - KEY; } return password; }
p70 17.4
将指针指向字符串
可以指向常量字符串,也可以指向存储字符串的字符数组
#include <stdio.h> #include <string.h> int main() { const char* words = "My heart is still."; words += 9; puts(words); return 0; } //在字符数组里面,指针是常量
数组和指针
数组形式和执行形式的不同
- 初始化字符数组时会把静态存储区的字符串拷贝到数组中
- 初始化指针只把字符串的地址拷贝给指针
#include <stdio.h> int main() { char str1[] = "For The Horde";//相当于把右边的字符串给了左边的,左边和右边是两块独立的内存空间,在修改左边内存的时候,右边内存时候是不变的 const char* str2 = "For The Horde";//相当于把右边的真实地址直接给了左边,左边就不是右边复制过去的,在操作str2的时候,相当于指向右边的内存空间 printf("字符串常量的地址是:%p\n", "For The Horde"); printf("字符数组的首地址:%p\n", str1); printf("字符指针的取值:%p\n", str2); return 0; }
P71 18.1
结构:
定义:结构是一种构造数据类型,由若干数据项组合而成struct StructName { //结构成员 DataType var1; DataType var2; //.... }
注:
- 结构定义并不预留内存(结构本身不占内存)
- 结构定义一般放在程序的开始部分(头文件声明之后)
- 结构定义仅用来描述结构的形式,使用结构需要声明结构变量
#include <stdio.h> #include <stdlib.h> #include <string.h> struct Hero { int id; char name[50]; //英雄的名称 int level; //英雄的等级 int hp; //英雄的血量 int mp; //英雄的魔法值 char skill[50]; //英雄的技能 }; int main() { //使用结构体 //struct Hero hero1 = { 2,"祥林嫂",10,1000,200,"疯狂呢喃" };//结构的存储逻辑跟数组相似 //这两种赋值方式都是可以的 struct Hero hero1; hero1.id = 1; strcpy_s(hero1.name, "德玛西亚之力"); hero1.level = 5; hero1.hp = 500; hero1.mp = 100; strcpy_s(hero1.skill, "大保健"); printf("%d\t%s\t%d\t%d\t%d\t%s\n", hero1.id, hero1.name, hero1.level, hero1.hp, hero1.mp, hero1.skill); return 0; }
使用结构1
先定义结构,再声明结构变量#include<stdio.h> struct Hero { char* name; int level; char* job; char* skill; }; void main() { //声明结构变量 struct Hero jackieChan; jackieChan.names = "JackieChan"; jackieChan.levels = 25; jackieChan.jobs = "战士"; jackieChan.skills = "醉拳"; } //声明类型为Hero结构的变量,将会为变量jackieChan分配内存,大小是大于或等于所有成员变量的大小之和
使用结构2:
- 定义结构类型的同时,声明结构变量
#include <stdio.h> struct Hero { char* name; int level; char* job; char* skill; }jackieChan,laola,guofurong;
- 直接声明结构变量
#include <stdio.h> struct //直接声明结构变量 { char* name; int level; char* job; char* skill; }jackieChan,laola,guofurong;
- 嵌套结构
#include <stdio.h> struct Martial { int id; //门派id char name[50]; //门派名称 int count; //门派的人数 int type; //门派的类型:1正派,2中立,3邪派 }; struct Player { int id; char name[50]; //玩家名称 char pass[50]; //玩家的登录密码 char sex; //玩家性别 struct Martial martial; //玩家所属门派 }; int main() { //玩家 //玩家有所属门派(种族、阵营) struct Player player = { 1,"和尚洗头用飘柔","123456",'f',{1,"洛克萨斯",500,3} }; printf("%s\t%s\t%c\t%s\t", player.name, player.pass, player.sex, player.martial.name); return 0; }
P73 18.3
指向结构的指针
- 一个指针指向结构时,成为结构指针变量
- 结构指针变量中的值是所指向的结构变量的首地址
一般形式:
struct结构名称 * 结构指针变量名;访问结构成员的一般形式:
①(*结构指针变量).成员变量名
②结构指针变量->成员变量名typedef:
可以为某一类型自定义名称typedef unsigend char Byte;
Byte btValue1;
注:typedef并没有创造任何新类型,只是为某个已存在的类型增加一个方便使用的标签#include <stdio.h> struct Martial { int id; //门派id char name[50]; //门派名称 int count; //门派的人数 int type; //门派的类型:1正派,2中立,3邪派 }; struct Player { int id; char name[50]; //玩家名称 char pass[50]; //玩家的登录密码 char sex; //玩家性别 struct Martial martial; //玩家所属门派 }; int main() { //玩家 //玩家有所属门派(种族、阵营) struct Player player1 = { 1,"和尚洗头用飘柔","123456",'f',{1,"洛克萨斯",500,3} }; struct Player player2 = { 2,"Dm_7","234567",'m',{1,"地瓜派",500,3} }; struct Player* ptr_player2 = &player2; //普通访问方式 printf("%s\t%s\n", player2.name, player2.martial.name); //使用指针访问 printf("%s\t%s\n", (*ptr_player2).name, (*ptr_player2).martial.name); printf("%s\t%s\n", ptr_player2->name, ptr_player2->martial.name); return 0; }
实战:
头文件
#ifndef HOTEL_H_INCLUDED #define HOTEL_H_INCLUDED #include <stdio.h> #include <stdlib.h> #include <conio.h> typedef struct _myTime { int year; int month; int day; }MyTime; typedef struct _hero { char* name; //英雄名称 char sex; //英雄性别 char* job; //英雄职业 int life; //英雄生命值 double speed; //攻击速度 const char* abillity;//英雄的特殊能力 MyTime pubTime; //英雄的上线时间 }Hero; //打印结果 //计算平均生命值 void ShowAvg(); void Input();//动态录入内容 void Show();//显示英雄的详细信息 #endif//HOTEL_H_INCLUDED
源文件:
#include "hotel.h" Hero heros[100] = { {"影流之主劫", 'm', "刺客", 579, 0.644, "位移", {2012, 8, 15}}, {"琴瑟仙女娑娜", 'F', "法师", 482, 0.644, "减速、治疗", {2010, 9, 20}}, {"疾风剑豪", 'm', "战士", 517, 0.67, "护盾、位移", {2013, 12, 23}} }; int count = 3;//当前的英雄总数 void Input() { //首先录入内容 //第一个录入完毕后,询问是否继续录入? char answer = 'y'; do { if (count == 100) { printf("英雄的栏位已满,请到游戏商城购买!"); break; } printf("\n当前录入第%d位英雄的信息:\n", count + 1); printf("英雄名称:"); heros[count].name = (char*)malloc(50); scanf_s("%s", heros[count].name); printf("性别:"); fflush(stdin); //清空缓冲区 heros[count].sex = getchar(); fflush(stdin); printf("职业:"); heros[count].job = (char*)malloc(50); scanf_s("%s", heros[count].job); heros[count].life = 1000; heros[count].speed = 0.655; heros[count].abillity = "上天、入地"; heros[count].pubTime.year = 2016; heros[count].pubTime.month = 4; heros[count].pubTime.day = 9; count++;//录入完毕后,英雄总数+1 printf("是否继续录入英雄的信息?(y/n)"); answer = _getch();//用户按下键后就立即触发下面语句,不会再让用户敲回车了 fflush(stdin); } while (answer == 'y' || answer == 'Y'); } void ShowAvg() { int lifeOfSum = 0; double avg = 0; int i; for (i = 0; i < count; i++) { lifeOfSum += (heros + i)->life; } //计算平均值 avg = lifeOfSum * 1.0 / count; printf("生命值的平均值为:%.2lf\n", avg); } void Show() { //如何知道结构数组的大小呢? //int len = sizeof(heros) / sizeof(Hero); //数组元素使用指针时,动态赋值需要首先分配内存 //printf("请输入名称:"); //heros[0].name = (char *)malloc(50);// char name[50] //scanf("%s", heros[0].name); //printf("结构数组的元素个数:%d\n", len); int i; printf("\n"); for (i = 0; i < count; i++) { printf("%s\t%s\t%d-%d-%d\n", (heros + i)->name, heros[i].job, heros[i].pubTime.year, heros[i].pubTime.month, heros[i].pubTime.day); } }
主函数:
#include <stdio.h> #include <stdlib.h> #include "hotel.h" extern Hero heros[100]; int main() { Input(); Show(); printf("%s\n", heros[0].name); return 0; }
p75 19.1
结构数组
定义:元素为结构体类型的数组称为结构数组所谓结构数组,是指数组中的每个元素都是一个结构体。在实际应用中,C语言结构体数组常被用来表示一个拥有相同数据结构的群体
struct Stu { char* name; int age; char* job; char* skill; }stu1[25]; //或者struct Stu stu1[25];
struct Stu { char* name; int age; char* job; char* skill; }stu1[] = { {"郭芙蓉",29,"打杂的","排山倒海"}, {"吕秀才",30,"账房","子曾经曰过"} };
P76 19.2
结构作为函数参数的三种方式:
1. 传递结构成员
2. 传递结构
①优点:函数处理的是原始数据的副本,保护了原始数据
②缺点:老版本不支持,传递结构浪费时间和存储空间
(一般用来处理小型结构数据)
3. 传递结构的地址①优点:程序的执行速度快,效率高(为了追求效率,此方案常用)
②缺点:无法保护数据,函数中的操作有可能会意外影响原结构中的数据1.传递结构成员
struct Account { char* bankName; //银行名称 char* userName; //用户名称 double limit; //账户额度 double billAmount; //当月账单 }; //计算并返回当月应还款 double GetRepayment(double m1,double m2) { return m1 - m2; } struct Account zsAcc; zsAcc.bankName = "招商银行"; zsAcc.userName = "郭达斯坦森"; zsAcc.limit = 50000; zsAcc.billAmount = 35000; double result = GetRepayment(zsAcc.limit,zsAcc.billAmount); printf("本月应还款:%.2lf\n",result);
2.传递结构本身
//信用卡账户 struct Account { char* bankName; //银行名称 char* userName; //用户名称 double limit; //账户额度 double billAmount; //当月账单 }; //计算并返回当月应还款 double GetRepayment(struct Account account) { return account.limit - account.billAmount; } struct Account zsAcc; zsAcc.bankName = "招商银行"; zsAcc.userName = "郭达斯坦森"; zsAcc.limit = 50000; zsAcc.billAmount = 35000; double result = GetRepayment(zsAcc); printf("本月应还款:%.2lf\n",result);
3.传递结构指针
//Account.h #pragma once #ifndef ACCOUNT_H_INCLUDED #define ACCOUNT_INCLUDED #include <stdio.h> #include <stdlib.h> typedef struct _account { const char* bankName; //银行名称 const char* userName; //用户名称 double limit; //账户额度 double billAmount; //当月账单金额 }Account; //得到某个账户当月应还款数 //传递结构变量时,是复制整个结构变量的值到函数中(效率很低) //double GetRepayment(Account account); //参数传递的是结构指针-传地址 double GetRepayment(Account* account); #endif//ACCOUNT_H_INCLUDED //Account.cpp #include "Account.h" double GetRepayment(Account* account) { return account->limit - account->billAmount; } //main.cpp #include <stdio.h> #include <stdlib.h> #include "Account.h" int main() { Account account = { "建设银行","杰克逊",30000,28000 }; double result = GetRepayment(&account); printf("应还款:%.2lf", result); return 0; }
实战项目:模拟玩家购买游戏道具
/* 商品——名称,单价,库存量,描述 玩家——编号,名称,密码,金钱,【背包】 背包——玩家编号、商品[10]、道具数量、最大道具数 模拟玩家购买游戏道具 1、玩家选择要购买的道具 2、玩家同意交易后扣除相应的游戏币 3、对应商品库存-1 4、玩家背包中增加商品或该商品数量+1 */ #include <stdio.h> #include <stdlib.h> #include <string.h> //商品结构 typedef struct _prop { int id; //道具的唯一编号 char name[50]; //道具名称 double price; //道具单价 int stock; //库存量:如果在背包中,表示此道具的叠加数量 char desc[200]; //道具的功能描述 }Prop; //背包结构 typedef struct _bag { int playerId; //所属玩家的编号 int count; //当前背包中,道具的数量 int max; //当前背包的插槽总数 Prop props[8]; //当前背包中的道具数组 .bag.max = }Bag; //玩家结构 typedef struct _player { int id; //玩家编号 char name[50]; //用户名/昵称 char pass[50]; //密码 double gold; //玩家金币-人性显示:可以将100000铜币转换成银币、金币显示 double sysee; //元宝数量 Bag bag; //玩家的背包 }Player; Prop* props; Player* players; int propsCount = 0; int playersCount = 0; //交易函数 //参数1:参与交易的玩家指针-为了方便修改玩家交易后的金币数 //参数2:玩家购买商品的id void Trade(Player* player, int propId); void Init(); void ShowProps(); void ShowPlayers(); void Trade(Player* player, int propId) { int i; //需要判断:商品的库存、玩家的金币余额、玩家的背包空间 Prop* tradeProp = NULL;//要购买的商品指针 for (i = 0; i < propsCount; i++) { if (propId == props[i].id) { tradeProp = &props[i];//tradeProp = props + i break; } } if (tradeProp->stock <= 0) { printf("地主家都没有余粮!商店都被买空啦!\n"); return; } if (player->gold < tradeProp->price) { printf("钱包都是瘪的,这里可是看钱的社会!\n"); return; } if (player->bag.count >= player->bag.max && player->bag.count != 0) { printf("背包已满,交易失败!\n"); return; } //满足交易条件,执行交易的业务操作 //1、商品库存-1 tradeProp->stock--; //2、玩家金币-商品单价 player->gold = player->gold - tradeProp->price; //3、玩家背包道具增加 //判断玩家背包中是否已有该商品,如果没有该商品,该商品添加到背包中即可 //如果有该商品,背包中的该商品数量+1 for (i = 0; i < player->bag.count; i++) { //如果要购买的商品id跟背包中某个商品的id相同 if (propId == player->bag.props[i].id) { player->bag.props[i].stock++; break; } } if (i == player->bag.count)//如果没有该商品,该商品添加到背包中即可 { //向背包中创建一个商品-复制一份要交易的商品信息到背包中 int newIndex = player->bag.count; player->bag.props[newIndex].id = tradeProp->id; player->bag.props[newIndex].price = tradeProp->price; player->bag.props[newIndex].stock = 1; strcpy(player->bag.props[newIndex].name, tradeProp->name); strcpy(player->bag.props[newIndex].desc, tradeProp->desc); player->bag.count++; } } void Init() //用来初始化游戏数据 { //第一步:初始化数据 static Prop propArray[] = { {01,"双倍经验卡",3000,10,"双击666"}, {02,"腐烂的道袍",5000,8,"只可远观不可亵玩"}, {03,"生锈的铁剑",8000,10,"新手专用"}, {04,"无极袍",13000,5,"刀枪不入,水火不侵"}, {05,"直升一级丹",83000,10,"吃了以后保准还想再吃..."} }; propsCount = sizeof(propArray) / sizeof(Prop); props = propArray; //设定指针指向 static Player playerArray[]= { {1, "超级毛毛虫", "123456", .gold = 50000, 8, .bag.max = 6}, {2, "塔罗奥特曼", "123456", .gold = 150000, 8, .bag.max = 6}, {3, "元始天尊之徒", "123456", .gold = 500000, 8, .bag.max = 6}, {4, "星河", "123456", .gold = 1150000, 8, .bag.max = 6} }; playersCount = sizeof(playerArray) / sizeof(Player); players = playerArray; } int main() { //初始化游戏数据 Init(); printf("\n*******************交易前*******************\n"); //第二步:打印这些数据 ShowProps(); printf("\n"); ShowPlayers(); Trade(&players[2], 3); Trade(&players[1], 3); Trade(&players[1], 3); Trade(&players[0], 3); Trade(&players[0], 3); printf("\n*******************交易后*******************\n"); ShowProps(); printf("\n"); ShowPlayers(); return 0; } void ShowProps() { int i; if (props == NULL) return; printf("%-5s%-18s%-7s\t\t库存\t\t商品介绍\n", "编号", "名称", "单价"); for (i = 0; i < propsCount; i++) { printf("%-5d%-18s%-7.1lf\t\t%d\t\t%s\n", props[i].id, props[i].name, props[i].price, props[i].stock, props[i].desc); } } void ShowPlayers() { int i, j; if (players == NULL) return; printf("编号\t%-16s金币\t\t元宝\n", "名称"); for (i = 0; i < playersCount; i++) { printf("%d\t%-16s%.0lf\t\t%.0lf\n", players[i].id, players[i].name, players[i].gold,players[i].sysee); for (j = 0; j < players[i].bag.count; j++) { printf("背包中的装备:\t\t%s\t数量:%d\n\n", players[i].bag.props[j].name, players[i].bag.props[j].stock); } printf("\n"); } }
总结:
- 结构是由若干数据项组合而成的复杂数据对象,这些数据项称为结构的成员
- 要在程序里使用结构,需要声明结构变量
- 访问结构成员的操作要用圆点运算符" . "
一般形式为:结构变量名.成员名 - 可以通过指针结构的指针访问结构成员
常用形式为:结构指针变量->成员名 - 数组元素的类型为结构的数组称为结构数组
- 结构作为函数参数有三种不同的方式:
①结构成员的值传递给函数参数
②整个结构作为参数传递
③结构指针变量做函数的参数
- (1)enum(枚举)
枚举是 C 语言中的一种基本数据类型,它可以让数据更简洁,更易读。
//游戏道具类型枚举——武器、道具、消耗品、卡片、碎片 typedef enum _proptype { Weapon, Armor, Con, card, Frag }PropType;
(2)union(联合体)
union
联合名
{
成员表
};
联合体也是一种自定义类型,可以通过它来创建变量。联合体占用的内存等于最长的成员占用的内存。联合体使用了内存覆盖技术,同一时刻只能保存一个成员的值,如果对新的成员赋值,就会把原来成员的值覆盖掉union{//联合(多选1) int minAttack; //如果是武器,就对应攻击力 int minDefence; //如果是防具,就对应防御力 int minPower; //如果是血瓶等消耗品,就对应增加的能量值 }; union{//联合(多选1) int maxAttack; int maxDefence; int maxPower; };
(3)COORD
表示在字符在控制台屏幕上的坐标,可以实现光标随方向键的移动key = getch();//无回显接收某个按键 getchar() fflush(stdin); if(key == VK_UP || key == 72)//用户按了上键 { Y--; } else if(key == 39 || key == 77)//右 { X++; } else if(key == 40 || key == 80)//下 { Y++; } else if(key == 37 || key == 75)//左 { X--; }
-
魔塔_java编写魔塔_老九学堂魔塔_魔塔java项目_魔塔谁发明的_魔塔开发_
2021-09-29 07:52:07用Java编写的魔塔项目,来着老九学堂某师兄,如有侵权,还望告知,受理后会在24小时内删除 -
Xuetang9:老九学堂课程测试
2021-03-30 23:23:59Xuetang9:老九学堂课程测试 -
【老九学堂】【C++】C++发展史
2020-10-21 21:11:16为了让小伙伴们在学习过程中,能收获更多的知识,达到真正的零基础入门和深入了解C++,老九君特地收集了有关C++发展相关的一些资料供大家查阅和学习: C++语言发展大概可以分为三个阶段: 第一阶段从80年代到...为了让小伙伴们在学习过程中,能收获更多的知识,达到真正的零基础入门和深入了解C++,老九君特地收集了有关C++发展相关的一些资料供大家查阅和学习:
C++语言发展大概可以分为三个阶段:
第一阶段从80年代到1995年。这一阶段C++语言基本上是传统类型上的面向对象语言,并且凭借着接近C语言的效率,在工业界使用的开发语言中占据了相当大份额;
第二阶段从1995年到2000年,这一阶段由于标准模板库(STL)和后来的Boost等程序库的出现,泛型程序设计在C++中占据了越来越多的比重性。当然,同时由于Java、C#等语言出现和硬件价格的大规模下降,C++受到了一定的冲击;第三阶段从2000年至今,由于以Loki、MPL等程序库为代表的产生式编程和模板元编程的出现,C++出现了发展历史上又一个新的高峰,这些新技术的出现以及和原有技术的融合,使C++已经成为当今主流程序设计语言中最复杂的一员。
以下是C++发展年代列表:
1967 年,Simula 语言中第一次出现了面向对象 (OO) 的概念,但由于当时软件规模还不大,技术也还不太成熟,面向对象的优势并未发挥出来。
1980 年,Smalltalk-80 出现后,面向对象技术才开始发挥魅力。
1979 年,Bjarne Stroustrup 借鉴 Simula 中 "Class" 的概念,开始研究增强 C 语言,使其支持面向对象的特性。B.Stroustrup 写了一个转换程序 "Cfront" 把 C++ 代码转换为普通的 C 代码,使它在各种各样的平台上立即投入使用。1983 年,这种语言被命名为 C++。
1986 年,B.Stroustrup 出版了 《The C++ Programming Language》第一版,这时 C++ 已经开始受到关注, B.Stroustrup 被称为 C++之父(Creator of C++)。
1989 年,负责 C++ 标准化的 ANSI X3J16挂牌成立。1990 年,B.Stroustrup 出版了 《The Annotated C++ Reference Manual》(简称 ARM),由于当时还没有 C++ 标准,ARM 成了事实上的标准。
1990 年, Template(模板) 和 Exception(异常) 加入到了 C++ 中, 使 C++ 具备了泛型编程(Generic Programming)和更好的运行期错误处理方式。
1991 年,负责 C++ 语言国际标准化的技术委员会工作组 ISO/IEC JTC1/SC22/WG21 召开了第一次会议,开始进行 C++ 国际标准化的工作。从此,ANSI 和 ISO 的标准化工作保持同步,互相协调。
1993 年,RTTI(运行期类型识别) 和 Namespace(名字空间) 加入到 C++ 中。1994 年, C++ 标准草案出台。B.Stroustrup 出版了《The Design and Evolution of C++》(简称 D&E)。本来,C++ 标准已接近完工,这时 STL(标准模板库) 的建议草案被提交到标准委员会,对 STL 标准化的讨论又一次推迟了 C++ 标准的出台。
1998 年,ANSI 和 ISO 终于先后批准 C++ 语言成为美国国家标准和国际标准。
2000 年,B.Stroustrup 推出了 《The C++ Programming Language》特别版(Special Edition),书中内容根据 C++ 标准进行了更新。语言的发展是一个逐步递进的过程,C++ 是直接从 C 语言发展过来的,而 C 语言是从 B 语言发展过来的,B 语言是 BCPL 的一个解释性后代,BCPL 是 Basic CPL。其中最有趣的是 CPL 中 C 的由来,由于当时这个语言是剑桥大学和伦敦大学合作开发的,在伦敦的人员加入之前,C 表示剑桥、伦敦人员加入之后,C 表示 Combined 组合。还有一种非正式的说法,C 表示 Christopher,因为 Christopher 是 CPL 背后的主要动力。
最初导致C++诞生的原因是在Bjarne博士等人试图去分析UNIX的内核的时候,这项工作开始于1979年4月,当时由于没有合适的工具能够有效的分析由于内核分布而造成的网络流量,以及怎样将内核模块化。同年10月,Bjarne博士完成了一个可以运行的预处理程序,称之为Cpre,它为C加上了类似Simula的类机制。在这个过程中,Bjarne博士开始思考是不是要开发一种新的语言,当时贝尔实验室对这个想法很感兴趣,就让Bjarne博士等人组成一个开发小组,专门进行研究。
当时不是叫做C++,而是C with class,这是把它当作一种C语言的有效扩充。由于当时C语言在编程界居于老大的地位,要想发展一种新的语言,最强大的竞争对手就是C语言,所以当时有两个问题最受关注:C++要在运行时间、代码紧凑性和数据紧凑性方面能够与C语言相媲美,但是还要尽量避免在语言应用领域的限制。在这种情况下,一个很自然的想法就是让C++从C语言继承过来,但是我们的Bjarne博士更具有先见之明,他为了避免受到C语言的局限性,参考了很多的语言,例如:从Simula继承了类的概念,从Algol68继承了运算符重载、引用以及在任何地方声明变量的能力,从BCPL获得了//注释,从Ada得到了模板、名字空间,从Ada、Clu和ML取来了异常。
C++语言既保留了C语言的有效性、灵活性、便于移植等全部精华和特点,又添加了面向对象编程的支持,具有强大的编程功能,可方便地构造出模拟现实问题的实体和操作;编写出的程序具有结构清晰、易于扩充等优良特性,适合于各种应用软件、系统软件的程序设计。用C++编写的程序可读性好,生成的代码质量高,运行效率仅比汇编语言慢10%~20%。
C++语言具有以下特点:
C++是C语言的超集。它既保持了C语言的简洁、高效和接近汇编语言等特点,又克服了C语言的缺点,其编译系统能检查更多的语法错误,因此,C++比C语言更安全。
C++保持了与C语言的兼容。绝大多数C语言程序可以不经修改直接在C++环境中运行,用C语言编写的众多库函数可以用于C++程序中。
支持面向对象程序设计的特征。C++既支持面向过程的程序设计,又支持面向对象的程序设计。
1.C++程序在可重用性、可扩充性、可维护性和可靠性等方面都较C语言得到了提高,使其更适合开发大中型的系统软件和应用程序。
2.C++设计成静态类型、和C同样高效且可移植的多用途程序设计语言。
3.C++设计成直接的和广泛的支援多种程序设计风格(程序化程序设计、资料抽象化、面向对象程序设计、泛型程序设计)。
4.C++设计成给程序设计者更多的选择,即使可能导致程序设计者选择错误。
5.C++设计成尽可能与C兼容,籍此提供一个从C到C++的平滑过渡。
6.C++避免平台限定或没有普遍用途的特性。
7.C++不使用会带来额外开销的特性。
8.C++设计成无需复杂的程序设计环境。出于保证语言的简洁和运行高效等方面的考虑,C++的很多特性都是以库(如STL)或其他的形式提供的,而没有直接添加到语言本身里。
遇到问题,可加老九君个人QQ:614940318,请备注来自CSDN
老九学堂免费C、C++、Java课程地址: https://study.163.com/courses-search?keyword=老九学堂
徐老师线下全栈就业班开始报名啦~
零基础开讲,8个月,Java全栈学习,终身推荐就业
-
老九学堂 学习 C++
2021-01-29 21:59:28第一天 c++应用范围:文字处理程序及电子表格、编译器 c++保留了C语言原有的所有优点,增加了面向对象机制,对C语言的功能做了扩充。 对C语言的扩充: 变量的定义可以出现在程序中的任何行 提供了标准输入输出流... -
【老九学堂】【C++】编码&命名规范
2020-10-15 11:54:501.命名规范 关于命名规范我们常用于本地变量名、全局变量名、预处理指令名称、函数名称、命名空间名称、类名、成员变量名称、成员函数名称。 1.1 通用命名规范. ...在开发的时候命名尽量使用描述性的命名。... -
老九学堂 学习 C++ 第七、八天
2021-02-13 21:59:428.1面向对象 所谓面向对象就是基于对象概念,以对象为中心,以类和继承为构造机制,来认识、理解、刻画客观世界和设计、构建相应的软件系统(模拟现实)。面向对象的编程方法有四个基本特征:分别是抽象、封装、继承... -
老九学堂 学习C++ 第九天
2021-02-24 22:04:5410.1 复制构造函数 例: 自定义string类,以简化字符串的操作 注: 如果不重载赋值运算符,对象str1的内容直接复制到新对象str2中,对于没有指针的简单类来说这足够了,但当我们拥有作为数据成员的指针时,逐字节... -
【老九学堂】【初识C语言】位运算符
2020-10-19 19:58:47位运算是指按二进制进行的运算。在系统软件中,常常需要处理二进制位的问题。C语言提供了6个位操作运算符。这些运算符只能用于整型操作数,即只能用于带符号或无符号的char,short,int与long类型。... -
老九学堂C++代码
2019-08-30 21:49:09老九学堂 课时98 的代码上传 第98课时时长80几分钟,例程代码也是全部课中最多的,这份代码是按照讲师讲解来敲的,经测试和视频效果一样,可放心学习 打开MyCppWorkSpace---dizhu2---default.workspace(用 code ... -
【老九学堂】【Java】Java环境之JDK配置
2020-10-23 11:11:51请备注来自CSDN 老九学堂免费C、C++、Java课程地址: https://study.163.com/courses-search?keyword=老九学堂 徐老师线下全栈就业班开始报名啦~ 零基础开讲,8个月,Java全栈学习,终身推荐就业 -
【老九学堂】【初识C语言】编码规范
2019-08-08 10:23:361 排版规则 程序应采用缩进风格编写,每层缩进使用一个制表位(TAB),类定义、方法都应顶格书写;...老九学堂免费C、C++、Java课程地址: https://study.163.com/courses-search?keyword=老九学堂 -
【老九学堂】【C++】经典排序算法
2019-08-08 11:38:281.冒泡排序 1.1.概述 冒泡排序(Bubble Sort),是一种计算机科学领域的较简单的排序算法。...老九学堂免费C、C++、Java课程地址: https://study.163.com/courses-search?keyword=老九学堂 -
【老九学堂】【Java】初级编码规范
2019-08-07 12:20:54例如老九学堂的项目是这样命名的: 包名 一级为com; 包名 二级为xuetang9; 包名 三级为班级编号,prot001; 包名 四级为小组名,如crazy; 包名 五级按功能模块划分等,如oofood; 所以包名为: ... -
老九学堂 学习 C++ 第四天
2021-02-01 17:49:28循环 while循环: while(循环条件) { 循环操作语句 } 循环三要素:循环变量的初值、循环变量的判断、循环变量的更新 do while循环: ...初始情况不满足循环条件时,while循环一次都不会执行,do-while循环不管任何... -
【老九学堂】【初识C语言】编译过程
2019-08-08 10:26:30C源代码 编译---->形成目标代码,目标代码是在目标机器上运行的代码。 连接---->将目标代码与C函数库相连接,并...老九学堂免费C、C++、Java课程地址: https://study.163.com/courses-search?keyword=老九学堂 -
老九学堂 学习 C++ 第五天
2021-02-02 18:22:50指针 基本概念:指针(pointer)是一个值为内存地址的变量(或数据对象) 声明及初始化指针变量 基本用法:数据类型 * 指针变量名 int * ptr_num; char * ptr_name; float * money_ptr;...int* p的写法偏向于地址,即 ... -
【老九学堂】【初识C语言】C语言基本数据类型
2020-10-15 20:48:191.概述 C 语言包含的数据类型如下图所示: C语言中的基本数据类型有整形、字符型、浮点型:单精度型、双精度型;枚举类型、数组等。...整形分为整形常量和整形变量,常量就是我们平时所看到的准确的数字,例如... -
【老九学堂】【Java】常用dos命令
2019-08-07 11:34:58dos常用基本命令 1.dir (directory)查看某个盘或文件下的目录(所以文件及文件夹); **格式:**dir [盘符:]...老九学堂免费C、C++、Java课程地址: https://study.163.com/courses-search?keyword=老九学堂 -
【老九学堂】【C++】数组与指针
2019-08-08 11:54:20不知道在通过前面的内容学习后,是否有很多小伙伴都会认为数组和指针是等价的,数组名表示数组的首地址呢?...老九学堂免费C、C++、Java课程地址: https://study.163.com/courses-search?keyword=老九学堂 -
【老九学堂】【C语言进阶】内置函数补充
2019-08-08 09:28:04原型: 用法: #include 有些编译器需要#include 功能: 改变mem_address所指内存区域的大小为newsize长度。...老九学堂免费C、C++、Java课程地址: https://study.163.com/courses-search?keyword=老九学堂 -
【老九学堂】【Java】对象访问及其原理
2019-08-07 09:49:43Java中的对象访问,一般会涉及到 Java栈、Java堆、方法区 这三个内存区域。 比如下面这句代码: ...老九学堂免费C、C++、Java课程地址: https://study.163.com/courses-search?keyword=老九学堂 -
【老九学堂】【Java】Eclipse中常用操作快捷键
2019-08-07 12:26:47Eclipse快捷键大全 Ctrl + 1 快速修复 Ctrl + D 删除当前行 ... 复制当前行到下一行(复制增加) ...老九学堂免费C、C++、Java课程地址: https://study.163.com/courses-search?keyword=老九学堂 -
【老九学堂】【Java】随机数详解
2019-08-07 10:41:39在我们的Java课程中通过游戏案例,我们通过随机数来对每次的攻击伤害值进行了一个赋值,那么Java中还有哪些方法可以...老九学堂免费C、C++、Java课程地址: https://study.163.com/courses-search?keyword=老九学堂