二次复习做的笔记,很基础,适合新手入门,复习巩固
1.为什么学习c语言
优点 :代码量小 速度快 功能强大 可移植性较好
缺点:危险性高 开发周期长
应用领域广:系统软件 应用软件
为学习数据结构 C++打基础
2.怎样学C语言
多思考 多上机多上机多上机
目标:能看懂程序,能调试程序
3.学习的目标
熟练掌握C语言的语法规则
理解面向过程的思想
4.学习重点
流程控制 函数 指针 动态内存分配
简单的描述:硬盘上的内容调入内存条,经过CPU的处理,如果是图像则经过显卡显示在显示器上
通过主板组在一起
编译器读取源代码 编译生成目标文件 再经过链接器链接 生成可执行文件 .exe文件是操作系统执行的
基本类型数据:整数:整型 int(4) 短整型 short int(2) 长整型 long int(8 )
浮点数(实数):单精度浮点数:float(4 ) 双精度浮点数:double(8)
字符:char (1)
复合类型数据:结构体 枚举
变量的本质就是内存中的一段存储空间
在 VC 编程环境下,操作系统不仅负责为程序分配包括内存空间在内的各种系统资源,还对 CPU 的运算任 务进行调度管理,内存条作为数据暂存介质为 CPU 提供快速的数据读写支持,而 CPU 作为运算核心负责执 行程序指令并进行各种数据处理操作,它们协同工作以确保程序的正常运行。
变量必须初始化是为了给变量赋予一个确定的初始值,避免其存储单元中存在不确定的垃圾值,从而确保程序运行时变量能按预期参与运算和操作,防止因未初始化而导致程序出现逻辑错误和不可预测的结果。
数据类型 变量名 = 要赋的值
几进制就是逢几进一
表示方法:数字后加字母B就是二进制 O是八进制 H就是十六进制
%d是十进制输出 %o是八进制 %x和%X是十六进制
整数:十进制 八进制前面加数字0 十六进制前面加0x或0X
浮点数:传统写法:float x = 3.2; 科学计数法:float x = 3.2e3; //x的值是3200
字符: 单个字符用单引号引起来 字符串用双引号引起来
整数和字符是以补码的形式转换为二进制diamagnetic存储在计算机中
实数是以IEEE754标准转化为二进制代码存储在计算机中的
字节就是存储数据的单位,并且是硬件所能访问的最小单位
字符本质上与整数的存储方式相同,ASCII码不是一个值,而是一种规定,规定了不同的字符是使用哪个整数值去表示 'A' 65 'a' 97
printf("字符串"); printf("输出控制符",输出参数) ; printf("输出控制符1 输出控制符2",输出参数1,输出参数2); printf("输出控制符 非输出控制符",输出参数) ;
scanf() 含有非输入控制符的情况 一次给多个变量赋值的情况··
%d:有符号十进制整数 %u:无符号十进制整数 %o:无符号八进制整数 %x或%X:无符号十六进制整数,%x以小写字母输出,%X以大写字母输出.
%#x中的#是一个标志字符,它会使输出结果带有0x前缀,这样可以更明确地表示输出的是十六进制数,增强了输出结果的可读性和标识性。
01组成的代码可以表示数据也可以表示指令
1 字节(Byte)= 8 位(bit)
1 KB = 1024 Byte
1 MB = 1024 KB
1 GB = 1024 MB
1 TB = 1024 GB
1 PB = 1024 TB
算术运算符 + - * / %(取余)
关系运算符 > >= < <= != ==
逻辑运算符 ! &&(且) ||(或)
赋值运算符 = += -= *= /=
优先级 算术 > 关系 > 逻辑 > 赋值
除 除数和被除数只要有一个是浮点型,则商是浮点型
自增:k = i++; 尽管是给k赋值,可是如果没有其他变化,最后输出的i的值会比原来加一
取余的运算对象必须是整数,结果是整出后的余数,其余数的符号与本除数相同
三目运算符: A ? B : C 如果A对,运行B,否则C
逗号表达式: (A , B , C , D) 功能:从左到右执行 最终表达式的值是最后一项的值
短路特性: &&左边的表达式为假 右边的表达式肯定不会执行
||左边的表达式为真 右边的表达式肯定不会执行
非零为真 零为假
强制类型转化 (数据类型)(表达式) (int)(4.5+5) 答案是9
程序代码执行的顺序
顺序
选择 if switch
if的范围问题:if和else默认的只能控制下面紧挨着的 一个 语句
控制多个需要{}起来
循环 for while do...while
float和double都不能保证可以精确的存储一个小数 循环中更新的变量不能定义为浮点数
while: for和while可以相互转换 do...while不行
do{}while(表达式) 主要用于人机交互
switch case case是程序的入口,进入后会一直执行,所以需要break退出
break用于:终止循环 终止switch 不能直接用于if,除非if属于循环内部的一个字句, 这时会退出if所在的那一层循环,即一个break只会终止一层循环(离他最近的那层循环)
continue用于跳过本次循环余下的语句
进制转换 10进制转化为n进制 : 除n取余,直至商0,余数倒序排列
N进制 转化为十进制:按权展开,逐位相加
N进制 转化为X进制:两步走N进制 → 十进制(按权展开)十进制 → X进制(除X取余,倒序排列)
如何看懂一个程序: 1.流程 2.每个语句的功能 3.试数
对一些小算法的程序:1.尝试自己去编程解决它,解决不了就看答案,2.看懂之后尝试自己去修改程序,并且知道修改之后程序的不同输出结果的含义 3.不看答案,自己独立的把答案敲出来
数组存在的意义 数组可以解决大量同类型数据的存储问题 模拟现实世界
数组从a[0]开始而不是a[1]
举例:int a[5] = {1,2,3,4,5};第一个元素存在a[0]而不是a[1]中
一维数组
为n个变量连续分配存储空间
所有的变量数据类型必须相同
所有变量所占的字节大小必须相等
未被初始化的元素默认都为0
只有在定义数组的同时才可以整体赋值,其他情况下整体赋值都是错误的
a[x] 单独拿出来a代表的是数组a第一个元素的地址
二维数组
int a[3] [4]
总共是12个元素,可以当作3行4列看待,a[0] [0]开始 a[2] [3]结束
int a[m] [n] 右下角位置的元素是a[m-1] [n-1]
//定义的格式1 int a[3][4] = { {1,2,3,4}, {5,6,7,8}, {9,10,11,12}, } //格式2 int a[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12}; //输出数组内容 int i, j; for (i = 0; i < 3;i++) { for (j = 0;j < 4;j++) printf("%d",a[i][j]); }
多维数组
不存在,因为内存是线性一维的 n维数组可以当作每个元素是n-1维数组的一维数组
逻辑上:能够完成特定功能的独立的代码块
物理上:能够接受数据(也能不接受数据),能对接受的数据进行处理,能够将数据处理的结果返回(也可能不返回任何值)
函数是个工具,他是为了解决重复问题而被设计出来的,他可以被当作一个黑匣子
int f(void) //括号中的void表示该函数不能接受任何数据,int表示返回值是int类型的数据 void g(void) //函数名前面的void表示该函数没有返回值
函数的意义
避免了重复性操作
有利于程序的模块化
如何定义函数
函数的返回值类型 函数的名字(函数的形参列表) { 函数的执行体 }
return和break的区别
break是终止循环,return是终止被调函数,向主函数返回表达式的值
函数的分类
有参函数和无参函数
有返回值函数和无返回值函数
库函数和用户自定义函数
值传递函数和地址传递函数
普通函数和主函数(主函数可以调用普通函数,普通函数不能调用主函数)
函数的声明
int a(); 写在主函数前面 函数的声明是一个语句,所以;不能丢
函数前置声明的作用:告诉编译器即将出现的若干字母代表的是一个函数;告诉编译器即将出现的若干字母所代表 的函数的形参和返回值的具体情况
对库函数的声明是通过
函数调用和函数声明的顺序:先声明或定义再调用 # include<库函数所在的文件的名字.h>来实现的
函数声明时可以不写形参
实参和形参
实参和形参个数必须相同,位置一一对应,类型应该兼容(最好相同)
如何在软件开发中合理的设计函数来解决实际问题
一个函数的功能尽量独立,单一
多学习,多模仿牛人的代码
常用的系统函数
double sqrt (double x) 求x的平方根
int abs (int x) 求x的绝对值(整数)
double fabs (double x) 求x的绝对值(实数)
变量的作用域和存储方式
按作用域: 全局变量 局部变量
在函数内部,若存在同名的全局变量和局部变量,局部变量会屏蔽全局变量
按存储方式:静态变量 自动变量 寄存器变量
指针就是地址
int i; //p是变量的名, int * 表示p变量存放的是int类型变量的地址 p = &i; //正确 p = i; //错误,类型不一致,p是int *型 i是int型 p = 55; //错误,原因同上
int * 类型就是存放int变量地址的类型
p保存了i的地址,因此p指向i
p不是i,i也不是p,或者说,修改两者中的一个不影响另一个
如果一个指针变量指向了某个普通变量,则 *指针变量 就完全等同于 普通变量 也就是说: 在所有出现*p的变量都可以替换成i; 在所有出现i的变量都可以替换成*p
在C语言中,char *p = "helloworld";
是合法的,且无需额外分配地址。
指针的作用
表示一些复杂的数据结构
快速的传递数据
使函数返回一个以上的值
能直接访问硬件
能够方便的处理字符串
是理解面向对象语言中引用的基础
指针的定义
int *p; p是指针变量,p中存储的值是指针
地址 内存单元的编号 从零开始的非负整数
指针的本质就是一个操作受限的非负整数
指针的分类
指针和数组
一维数组:
一维数组名 是个指针常量 它存放的是一维数组第一个元素的地址
下标和指针的关系
如果p是个指针变量,则 p[i]等价于*(p + 1)
确定一个一维数组需要几个参数 类型 数组开始地址 数组元素个数
p[i] = *(pArr + 1) = pArr[i]
*的含义
乘法
定义指针变量
指针运算符 该运算符放在已经定义好的指针变量的前面,如果p是一个已经定义好的指针变量 则*p表示 以p的内容为地址的变量
如何通过被调函数修改主调函数普通变量的值
1.实参必须是该普通变量的地址
2.形参必须是指针变量
3.在被调函数中通过 *形参名 = 。。。的方式可以修改主调函数相关变量的值
指针变量的运算
指针变量不能相加 相乘 相除
如果两个指针变量指向的是同一块空间中的不同存储单元,这两个指针变量才能相减
一个指针变量占四个字节(32位系统) 64位系统是八个字节
传统数组的缺点:
1.数组的长度必须事先指定,且只能是常整数,不能是变量
2.传统形式定义的数组,该数组的内存程序员无法手动释放(本函数运行完毕时,系统自动释放)
3.数组的长度不能在函数运行的过程中动态的扩充或缩小
4.在A函数定义的数组,A函数运行完毕后,该数组将无法被其他函数使用
上面四个传统数组的缺点,动态数组都能解决
构造动态函数
int i = 5; //分配了四个字节(int型),静态分配 int * p = (int *)malloc(4); * p = 5; free(p);
要使用malloc函数,需要添加malloc.h这个头文件
malloc函数只有一个形参,并且形参是整型
4表示请求系统为本程序分配四个字节
malloc函数只能返回第一个字节的地址
第二行一共分配了8个字节,p占4个字节,p所指向的内存也占4个字节
*p代表的就是一个int变量,只不过*p这个整型变量的内存分配方式和i变量的不一样
p本身所占的内存是静态分配的,p所指向的内存是动态分配的
free(p)表示把p所指向的内存给释放掉(p本身的内存是静态的,不会被释放)
动态构造一维数组
int a[5]; //如果int占四个字节的话,则本数组总共包含20个字节,每四个字节被当做了一个int变量来使用 int len; int *pArr; pArr = (int *)malloc(4 * len);//动态构造,该数组的数组名是pArr,元素类型是int类型 类似于 int pArr[len];
多级指针
int i = 5; int *p = &i; int **q = &p; int ***r = &q;//r是int ***类型,所以只能存放int **类型变量的地址
为什么需要结构体
整合数据:把不同类型的相关数据组合成整体。
方便管理:让数据组织有序,提升代码可读性与维护性。
高效传参:作为一个单元在函数间传递数据。
自定义类型:按需求创建新数据类型,增强灵活性。
定义方式
//第一种定义方式 struct Student { int age; float score; char sex; } //第二种定义方式 struct Student { int age; float score; char sex; } st2
赋值和初始化
//第一种初始化 定义的同时赋值 struct Student st = {80, 66.6, 'F'}; //第二种初始化 先定义再分别赋值 struct Student st2; st2.age = 10; st2.score = 88; st2.sex = 'F';
如何取出结构体变量中的每一个成员
1.结构体变量名.成员名
2.指针变量名->成员名(常用)
struct Student *pst = &st; //&st不能改成st //第一种方式 st.age = 10; //第二种方式 pst->age = 88; //pst->在计算机内部会被转化成(*pst).age 等价于st.age
结构体变量和结构体指针变量作为函数参数传递的问题
推荐使用结构体指针变量作为函数参数来传递
结构体变量的运算
不可以相互加减乘除,但可以相互赋值 st1 = st2;
枚举
enum weekday {};
把一个事物所有可能的取值一一列举出来
使代码更安全 书写麻烦
进制转换
补码
原码
也叫符号-绝对值码 最高位0表示正,1表示负,其余二进制位是该数组的绝对值的二进制位
简单易懂但加减运算复杂 0的表示不唯一 存在加减乘除四种运算,增加了CPU的复杂度
反码
运算不便,也没有在计算机中应用
移码
表示数值平移n位,n称为移码量,主要用于浮点数的阶码的存储
补码
正数与原码相同
负整数转二进制
先求与该负数相对应的正整数的二进制代码,然后将所有位取反,末尾加1,不够位数时,左边补1
已知二进制求十进制
如果首位时0,是正整数,普通方法求
如果首位是1,是负整数,将所有位取反,末尾加1,所得数字就是该负数的绝对值
如果全是0,则对应的十进制数字就是0
最小负数的二进制代码是多少
最大整数的二进制代码是多少
字符串的处理
链表
首节点:存放第一个有效数据的节点
尾节点:存放最后一个有效数据的节点
头节点:头节点的数据类型和首节点的类型是一模一样的
头节点是首节点前面的那个节点
头节点并不存放有效数据
设置头节点是为了方便对链表的操作
头指针:存放头节点地址的指针变量
算法
算法是依附与存储结构的,不同的存储结构,所执行的算法是不一样的
通俗定义:解题的方法和步骤
狭义定义:对存储数据的操作
对不同的存储结构,要完成某一个功能所执行的操作时不一样的
广义定义:广义的算法也叫泛型,无论数据是如何存储的,对该数据的操作都是一样的
优点:插入删除效率高 不需要一个连续空间
缺点:需要一个连续的很大的空间
位运算符
& 按位与 比如1010 和 0110 经过运算就是0010
| 按位或
~按位取反
<< 按位左移 i<<1;表示把i的所有二进制左移一位 左移n位相当于乘以2的n次方
>>按位右移
二进制全部为0的含义
数值0 字符串结束标记符 空指针NULL
NULL本质也是0,但这个零不代表数字0,而表示的是内存单元的编号零
计算机规定了以0为编号的存储单元的内容不可读,不可写
动态内存分配
文件
在C语言中用一个指针变量指向一个文件,这个指针称为文件指针,通过文件指针就可对他所值得文件进行各种操作.
#include#include int main() { // 1. 文件指针 // 用于指向文件,后续的文件操作都通过这个指针来进行 FILE *fp; // 2. 打开文件 // fopen函数用于打开文件,第一个参数是文件名,第二个参数是打开模式 // "w" 表示以写入模式打开文件,如果文件不存在则创建,如果存在则清空内容 fp = fopen("test.txt", "w"); // 检查文件是否成功打开 if (fp == NULL) { // 如果文件打开失败,输出错误信息并退出程序 perror("无法打开文件"); return 1; } // 3. 写入文件 // fprintf函数用于向文件中写入格式化数据,用法和printf类似 fprintf(fp, "这是写入文件的第一行内容。\n"); // fputs函数用于向文件中写入字符串 fputs("这是写入文件的第二行内容。\n", fp); // 4. 关闭文件 // fclose函数用于关闭文件,释放相关资源 fclose(fp); // 5. 以读取模式打开文件 // "r" 表示以只读模式打开文件,如果文件不存在则打开失败 fp = fopen("test.txt", "r"); if (fp == NULL) { perror("无法打开文件"); return 1; } // 6. 读取文件 // 6.1 使用fgets函数逐行读取文件内容 char line[100]; while (fgets(line, sizeof(line), fp) != NULL) { // 输出读取到的行 printf("%s", line); } // 重新定位文件指针到文件开头 // 以便后续再次读取文件内容 rewind(fp); // 6.2 使用fscanf函数按格式读取文件内容 char buffer[100]; while (fscanf(fp, "%s", buffer) != EOF) { // 输出读取到的单词 printf("读取到的单词: %s\n", buffer); } // 7. 关闭文件 fclose(fp); // 8. 以追加模式打开文件 // "a" 表示以追加模式打开文件,如果文件不存在则创建,如果存在则在文件末尾追加内容 fp = fopen("test.txt", "a"); if (fp == NULL) { perror("无法打开文件"); return 1; } // 9. 追加内容到文件 fputs("这是追加到文件的内容。\n", fp); // 10. 关闭文件 fclose(fp); return 0; }
auto 变量类型推演,
register 建议编译器将该变量放入CPU,
static 静态变量,
extern 声明变量,常用于多文件需要使用同一变量时
不能被重载的运算符 1、. (成员访问运算符) 2、.* (成员指针访问运算符) 3、:: (域运算符) 4、sizeof(长度运算符) 5、?: (条件运算符)
typedef
// 为 int 类型定义别名 Age typedef int Age; // 为 char 类型定义别名 Character.2 typedef char Character; // 为包含 10 个整数的数组定义别名 IntArray typedef int IntArray[10]; // 为指向 int 类型的指针定义别名 IntPointer typedef int* IntPointer; // 为结构体类型定义别名 Person typedef struct { char name[50]; int age; } Person; int main() { Person p = {"John", 25}; printf("Name: %s, Age: %d\n", p.name, p.age); return 0; }
ASCALL代码
48 0 65 A 97 a