C语言基础笔记

1-二进制:计算机内部只能用二进制(B)表达,传输,计算信息,八进制(Q),十进制(D),十六进制(H)都是工具,其规则都是从0开始,低位满了向上进一,注意其内存存储最大范围

2-原码补码:原码是为了表达负数引进的概念,在计算机内并不存在,在n位二进制的最高位使其等于1(表示负号)或0(表示正号),剩下的n-1位计算其绝对值配上符号位表示正负数
补码是为了用加法实现减法由于计算机内部是通过逻辑运算来实现算术运算其内部使用成本较低的加法器,补码是在原码的基础上,若原码为正数,则补码也为正数,若原码为负数则其补码除符号位外,按位取反,末位加一,计算机的加减乘除取余都是通过加法(加法器)实现
原码变补码和补码变原码遵循同样的规则:对于负数,除符号位外,按位取反,末位加1
对于正数,原码与补码相同

3-五大部件:输入输出设备,内存,算逻部件,控制器
内存:用来存储指令和数据,是软件运行的唯一场所,是由大量字节组成的存储空间分为ROM(只读内存,保存如计算机启动程序)和RAM(读写内存,短暂保存输入的数据)
算逻部件:即是ALU是CPU的组成部分
控制器:是计算机最核心的设备,能识别二进制指令,控制协调其它设备

4-内存概念:内存是由多个字节组成的一维,线性,连续的存储空间
字节:是计算机内存,外存分配存储空间的基本单位(1B=8b,一字节等于八位二进制),对于内存中的众多字节,计算机通过编号进行管理,编号与字节一一对应,参与编号的二进制位数,决定了计算机系统能直接管理,访问的空间大小,每一个字节有一个4字节编号其俗称指针,地址
数据总线:其根数与CPU字节长度相同,决定计算机能同时处理的二进制位数
地址总线:其根数是计算机系统用来对字节进行编号管理的二进制位数
内存中每个字节的编号并不在内存里,编号体现在代码中,在地址总线上

5-内存分配与垃圾数据:内存的最前端和最后端存储一些重要指令和数据不能分配给用户程序使用,每次定义新的变量要初始化否则它还是会有值(遗留的无意义垃圾数据)

6-C中的常见数据类型:两个要素,1,识别方式,2,长度,定义的数据类型必须两个要素都齐全且清晰,才能构成有效数据类型
char-1B-ASCII; short-2B-补码; int-4B-补码; long-4B-补码;
float-4B-浮点; double-8B-浮点;输入的浮点数被默认位double类型
字节编号 * 大小为4B 也就是指针
1B=8b(一字节等于八位二进制位)1G=1024MB,1MB=1KB,1KB=1024B
在这里插入图片描述

7-内存印象图:定义的数由十进制通过计算机转化成二进制将其存储在内存空白区,内存中还可以存储表示"位置"(地址,字节编号),如 short 12901 = 32 65H,假设在内存中以3A2B6532为字节处开始其先占用2B的内存空间,为了表示这个int类型的数据在内存中的位置,我们要记录这个数占用的字节的编号信息,计算机将数据所占的第一个字节的编号(首地址)保存在内存的其它字节中,即此处的若数据类型为 * 则该数据将在内存中占4B的空间,且其内容被当作 字节编号 对待,这使星号指向了某一个存储空间,因此叫指针
指针两个要素;1,首地址 多个存储空间第一个字节的编号2,指类,指针所指向的空间的数据类型

8-运算符:单目运算符,双目运算符,逻辑运算符,三目运算符
赋值运算符其运算过程由右向左,两个相邻赋值运算符后者比前者的优先级要高,自增和自减的本质也是赋值运算,条表中的滞后自增自减,先用原值判断,判断完后,立刻自增自减,且滞后自增自减遇到逗号时立刻自增自减
++i;先对i加1,再用加1后的值参与后续运算
i++;先用i的值参加后续所有运算,然后对i加1
短路运算:通过&&或||配合指针
在这里插入图片描述
9-数据类型转换:自动类型转换,某次输入的两个数的类型不一样时,C语言会自动转换其类型遵循原则,短类型向长类型转换,有符号转向无符号类型
强制类型转换,运算符:(数据类型名称)表达式,如(double)1,注意强制类型转换不会改变转变的变量原本的值,只在某次运算中有用

10-for语法:for(初始值;条表;步长){
循环体
}
运行顺序:初始化-判断条表真假-进行循环体-步长运算-判断条表—
条表:条件表达式其值为两种 0 或 非0 for中为真(非0)则进循环体,为假跳出
当我们遇到两层及两层以上的for循环时,用变量跟踪一步步看,注意for内循环体内赋值对下一个循环体的影响

11-数组的概念 定义及语法:数组的概念:多个内存变量元素,共同使用同一名称,并用下标进行区分,且数组是从0开始的,到n-1结束,数组内每一个元素都是一个独立的变量
定义,数组与变量一样,都必须 先定义 ,再引用,定义数组的语句,与数组元素引用的语句,有不同的规定,不可混用,类型与变量名称缺一不可 语法: type arrayName [非浮点常量(表达式)]
数组类型 数组名[非浮点常量(或表达式0)] 方括号内表示数组元素的个数
[ ]内期待的是一个常量,不可取变量赋值在代入,C89标准无法通过编译
但是我们可以通过预处理#define给一个常量名,接下来它在整个主函数内都是常量,也可放在数组中定义长度

12-数组元素的引用***数组引用与数组定义的语法不同,用数组下标引用元素时,下标可以是变量,也可以是由变量或变量组成的表达式***
下标越界,当定义一个数组如 arr[10],这时注意只有0到9十个变量元素,如果在引用时肆意操作,出现了arr[ -1]或arr[11],这时会出现非常严重的 下标越界错误,但这时编译器不会显示错误并会执行,这时会产生非法内存问,一定要小心注意定义的下标和引用的下标

13-数组元素赋初值:此操作仅在定义中操作,紧随定义赋初值,定义还是需注意识别方式(类型名称)和长度,如 arr[3] = {1,2,4};a[0]=1,a[1]=2,a[2]=4
在赋初值时如果给的有效元素个数小于定义的数组总申请的元素空间数,则从第0个开始到有效元素结束,剩下的都被定义为0

14-sizeof:sizeof是一个单目运算符,不是函数,可以用来求 类型名称,变量名称,数组名称,表达式的类型的长度,并计算某数组申请总元素的个数 sizeof(int)=4,sizeof(32+42.09)=8,int a[100} ;sizeof(a) = 400,
计算申请总元素个数,int a[]={,,}sizeof(a)/sizeof(int) 即该数组的元素个数

15-数组处理数据的特点:从下标为0的第一个元素开始存放,连续存放数据,且如果在处理存储于数组中的数据时,存在增加,删除等操作必须满足前两个原则
数组的遍历:将储存在数组中的数,无缺失,无重复的访问一遍

16-二维数组定义及特点: 定义一个三行四列的数组 如 int m[3][4]
其共有3*4=12个元素,每个元素都是 int类型
但由于内存是一维线性的,所以二维数组在内存中也是一维的!
二维数组赋初值:如int[2][2] = { {1,2},{2,4}},靠近类型名称的是组数,远离的是每组内含有的元素个数,

17-字符数组与字符串:字符串是以0结束的字符数组
关于0: 0-结束标志, ‘0’-字符0, “0”-“字符0”
每个字符串最后存在一个看不见的0作为结尾,这里是一个不可输入的0
C语言对字符串存在一个基本原则: 遇0则止,0是0结束标志

求字符串长度的函数:strlen函数它包含在string.h内
使用方法,strlen(字符串)

18-指针的两个要素:首地址,即相关变量在内存中所占用的多个字节连续存储空间中的第一个字节的编号,每个指针的数据长度永远都是4B的
指类:指针(首地址)所指向的内存空间的数据类型,首地址只能表示内存中一个字节的编号,无法获知更多的指针指向的空间的信息,必须通过指类来确定指针所指向的空间的数据类型

tip: 如 short *p 意为定义了名为p的指针,它(指针)是四字节编号,它所指向的空间(指类)位 short类型,是两个字节
short **q意为定义了一个名为q的指针,指针是四字节编号,它的意思是定义了一个指针, 它指向了一个 已经指向了short类型的空间的指针

19-与指针相关的两个运算符:& 和 *

&:在关于***指针使用中, &意为取地址,&的右边必须是一个左值(变量)***
如 int a = 10;p = &a ,&a它将a的空间的首地址复制一份
并赋值给指针p的空间,此时p指向了a

注意,使用&运算符时,两边的指类必须保持一致

间接访问(指向运算)*:与&同优先级,且与&运算符同优先级,与&取地址运算互为逆运算, 连续两次执行时,相互抵消
使用:*指针,如 *p = 30,意为将30赋值给p指针所指向的空间
*p = **r + *q,意为,将r所指向的指针, 所指向的空间的值,与q所指向的空间的值求和,并赋值给p所指向的空间

tip:在定义指针时, int *p,此时星号只是定义符,并不对指针进行指向操作

它是变量为指针类型的说明符
&运算符使指针升阶(一阶变为二阶,取出的地址就是指针)

运算符使指针降阶(二阶变为一阶,指向了具体的空间)

20-指针的运算:1,指针与整形量相加减
指针加减整型量,其结果仍为指针, p为指针, p + 1即是,指向p所指向的空间的下一个指类元素空间,即指向关系的移动量,指向的移动距离是指针的指类空间长度 如 char *p; p + 1;此时新指针向后移动了一个字节,表现为用%p打印出的新指针的地址增加了一个字节

2,指针与指针相减 条件:两个指针的指类必须相同
指针减指针,其结果的绝对值是,两个指针所指向的空间之间的指类元素个数

如 int score[10] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10} ;
int *p = &score[2]; int *q = &score[6];
q - p = 4

tip: 使用%p可以打印对应表达式地址值所对应的16进制数

指针与指针不可以进行加法运算,C语言拒绝此运算

21-指针与字符串及关于字符串的函数
字符串常量的本质是指针,即是该字符串的首地址常量(指针常量)
%s的本质,%s需要一个 char *类型的数据,且从这个指针所指向的字节处开始,向后做“遇0则止”的字符输出

strcpy()函数:用来将第二个参数作为首地址所指向的空间开始遇0则止的字符串,复制到第一个参数作为首地址所指向的字节开始的连续空间中
如:char str1[10] = {1,2}; char str2[10];
strcpy(str2, str1) 此处将str1内的数值复制到str1,若str1非空则从0开始覆盖

strcat ()函数:从第二个字符串指向的空间开始,遇到0结束,将这段字符串连接到第一个字符串的末尾,第二的字符串的第一个字符覆盖第一个字符串的0结束标志
如:char str1[10] = {1,2}; char str2[10] = {4,5,6};
strcat(str1,str2)此处将str2内接到str1里

strcmp()函数:比较字符串的大小,是比较ASCII码值得大小,两个字符串从第一个字符开始比较,若相同,则比较下一个字符,直到遇到0结束标志,只要有一次字符大小(ASCII码值)不同,则结束比较
比较完后会给出一个返回值,有三种情况,若返回值为0,则str1所指向的串等于str2所指向得串,若大于0,则s1指向的串大于s2指向的串,若小于0,则s1指向的串小于s2指向的串
char str1 = ”a” ,char str2 = “ABCD”
此处strcmp(str1,str2)

strchr()函数:若ch存在于str所指向的字符串中,则函数返回ch在str中第一次出现的位置(16进制地址值),若ch不在str中,则返回NULL
如 p = strchr(“abcdefefg”,‘e’);此时p将指向下标为4的的字符e,此时p的值就是e的地址,若p = strchr(p + 1, ‘e’);此时可以查找到第二个‘e’的位置

tip:汉字字符串颠倒结果与想象的不一样,一汉字为两字节,由于一个内存中是一个字节一个字节存储数据的,逆序颠倒汉字字符串会使部分字节丢失颠倒打印出的值与想象不符

22-字符串的输入 输出函数
关于格式符:C的原则,1,对一开始的多个空白符号(空格,tab,回车)一律忽略 2,从第一个非空白符号开始认位是用户输入的有效数据
3当再次遇到一个空白符号,则表明本次数据输入结束,并且,将最后遇到的空白符号,扔到 键盘缓冲区
4%s遵循这样的规则,因此用%s是无法从键盘输入含有空格和tab字符的字符串

gets()函数:gets()函数专门用来接收字符串的函数,gets()函数对于用户输入的所有字符都当成字符串的组成部分,回车例外,回车意为此次输入结束,如果一开始就输入一个回车,则输入的是一个空串
flushall();用来清空键盘缓冲区

tip:scanf和gets不可以混用,如果scanf写在前面,会将输入数据输入完毕后的第一个空白字符(包括回车)当成结束符,且扔到键盘缓冲区,接下来用gets时,上次键盘缓冲区内的空白字符会被gets接收,在使用gets前,可以使用fiushall()函数清空键盘缓冲区内残留数据

%s与puts()函数的区别: print发("%s",s); == puts(s);
唯一差距救赎puts()函数会自动换行

23-函数的基本概念
函数的三个基本功能:接收参数,加工程序,传回返回值
函数的分类:1,是否为主函数,C有且只有一个主函数,是整个程序的入口
2,已编好的系统函数(库函数),用户自定义函数
3,主调函数和被调函数

24-函数的产生及引用过程
函数的产生: 声明 定义 调用

int jc(int n); //函数的声明

int jc(int n){    //函数的定义
	int sum = 1;
	int i;
	for(i = 1; i <= n; i++) {
		sum *= i;
	}
	return sum;
}

函数声明注意项-函数名称的确定,函数参数的说明,函数返回值的说明
函数名称的本质:该函数的入口地址常量(指针常量)
函数参数:需要确定参数个数及每个参数的数据类型,带参和无参(void)
函数返回值:只能返回一个值,使用时确定是否需要返回值

24-形参与实参
在函数调用时,出现 实际参数,而函数定义时,在函数首部出现 形式参数
确定***实参:函数调用时,()中用 , 分隔的多个表达式称为实参***
实参有三种,常量,变量,表达式
确定***形参:函数定义时,出现在函数首部,用 , 分隔的多个变量为形参***
形参只能是 变量(甚至不包含数组)

形参和实参的关系:两者必须满足4个要求, 个数相同, 按位置关系对应, 类型一致,且是 值传递(将实参表达式的值复制一份,赋值给形参变量)
被调函数对形参变量所做的任何更改,不会影响实参的值,实参和形参之间是单向传值传递关系

25-全局变量和局部变量
全局变量定义及特点:在函数体之外定义,全局变量在主函数运行之前,就已经被定义了,程序执行之前,全局变量所需空间已申请好
全局变量在书写顺序上只能被其后定义的函数所引用,全局变量在定义后,未赋初值前,其值为0

局部变量定义及特点:在函数体内部定义的变量,包括函数的形参变量,在定义该变量的函数被调用时,才申请空间
在函数体内定义的局部变量,其初始值是垃圾数据
形参变量的值总是确定的,取决于实参表达式的值

tip:全局变量能被所有函数引用和更改,但这样做违反了软件工程的 模块独立性 原则,所以***全局变量前往往
跟随一个关键词 const(只读)***,则此时可以被多个函数所读取,而又不能被更改,大大降低了函数间的联系,提高了函数独立性

26-变量的存储类型
共有四种:自动存储类型,静态存储类型,寄存器存储类型,外部存储类型
自动存储类型是C语言默认的变量存储类型 此处***主要区分自动存储类型(auto)和静态存储类型(static)***

区别1:自动存储类变量在定义它的函数被调用前,才申请空间,而静态存储类变量在主函数执行前就已申请好空间
区别2:自动存储类变量在定义它的函数运行结束后,释放其空间,而静态存储类变量在整个函数结束后,一次性释放空间
区别3:自动存储类变量的值具有 独立性,静态存储类变量空间的值将在多次函数的调用过程中被连续变化,具有 累加效应
区别4:自动存储类变量定义后,赋值前其初值为垃圾数据,而静态存储类变量在定义后,赋值前其初值为0
区别5:静态存储类变量可以修饰局部变量,静态存储类局部变量只能被定义它的函数引用,而不能被其他函数引用

27-编写函数的三个问题
思考1:函数的名称是什么?
思考2:该函数需不需要参数,如果需要,那么需要几个参数,以及是什么类型的参数?
思考3:该函数有无返回值,如果有,那么返回值的类型是什么?
上述三个思考的答案,需要追溯到 函数的功能 我们要用函数实现什么?

28-结构体-1
结构体的声明:如果某校要登记新生的信息,则起码有 姓名,性别,入校成绩,入校年龄等信息
这时使用结构体能轻松录入

结构体声明示例 结构体的声明实际上是定义了一个新的数据类型

struct STUDENT_INFORMATION {
		char stid[9];
		char name[15];
		char sex;
		int age;
		int score;
}

对 struct STUDENT_INFORMATION a, b[50], *p的理解:
此处 b是一个拥有50个struct STUDENT_INFORMATION实例元素的数组 b[0] - b[49]就是独立的50个类似a的结构体实例
此处 p是一个能够指向struct STUDENT_INFORMATION实例的指针变量,其指类就是struct STUDENT_INFORMATION

结构体使用的两个基本步骤:1,声明结构体的数据类型 2,用结构体类型作为数据类型,定义新的实例(数组,指针)
通过上述两步后,通过对实例成员的引用,实现对实例的引用

29-结构体-2
访问结构体成员及赋初值
在struct STUDENT_INFORMATION a, b[50], *p中,要求对b数组的一个元素所代表的学生赋值如下信息:
00001 张三 男 18 80则应:
strcpy(b[0].name, “张三”);
strcpy(b[0].stid, “00001”);
b[0].sex = 1;
b[0].age = 18;
b[0].score = 80; 这样完成了最基本的赋值 注意的是 字符串需要用strcpy拷贝功能,头文件需要需要#include <string.h>

通过指针引用其所指向的实例的诸成员: p->age 意为:p所指向的实例的age成员 .运算符与->的运算优先级相同
. 与 -> 的差别: 实例.成员 指针.成员

复合结构体:
struct DATE { struct STU_INF {
short year; char stuid[9];
char month; char stuname[21];
char day; char sex;
} struct DATE stubirth;
}
这里定义了两个结构体 对struct STU_INF a;而言 a有四个成员, a.stuid,a.stuname,a.sex和a.stubirth 其中的a.stubirth自己有三个成员为
a.stubirth.year, a.stubirth.month, 和a.stubirth.day

tip:按照结构体的内存映象图,一个结构体的长度,应该是该结构体所有成员长度之和,但事实上,此说法由于内存对齐模式存在偏差

30-宏定义与用户字定义类型
普通宏替换: #define 用户标识符 字符 如#define PI 3.1415926 定义后 整个程序中的PI就成为了3.1415926
宏的最大特点:只替换,不计算 如果出现 #define a 3+4 此后的a为3+4 并不是计算后的数值,此操作归于预处理操作

用户自定义类型:基本语法- typedef 已有类型名称 新类型名称(们)
如 typedef int INTEGER 此后int a 等同于 INTEGER a typedef所产生的新数据类型必须满足变量名命名原则
typedef int A,B,C; 这样有了新类型A B C 可以定义 A a; B b[10]; C *p; 等同于 int a, b[10], *p

typedef与struct:若 typedef struct STI STI; 则STI a等同于 struct STI a;

typedef struct STUDENT_INFORMATION {
		char stid[9];
		char name[15];
		char sex;
		int age;
		int score;
}STI

这里的STI是新数据类型名称 上面代码将产生一个新数据类型 STI 就是struct STUDENT_INFORMATION
注意 struct STI {…}STI 这里前面的STI指的是结构体名称,后面的struct指的是 已定义了一个结构体实例含5个成员它叫STI

define与tyedef的差异:
#define CP char * CP a1,b1,c1;
typedef char *cP cP a2,b2,c2;
上述六个变量分别为什么类型?
对cP a2,b2,c2;来说 这三个变量都是 char *类型

而a1是char*类型 b1和c1都是char类型

31-动态存储分配
先了解静态存储分配:是C语言变量或数组默认的一种存储分配方式 如int a[20] 此时这个数组a只有20个元素 使用时不可更改
为了提高程序的适用性和可用性 C提供了一种动态存储分配手段
malloc作用:申请size字节的内存空间,并返回这个空间的首地址,若申请失败(已无内存可分配)则返回NULL
free作用:释放一个指向已分配好空间的指针所指向的空间
使用函数 malloc(),和free();进行动态存储分配 此处需要头文件 malloc.h的支持
对于用malloc()函数申请的空间,必须使用free()函数进行释放

使用方法:int *p;p = (int *)malloc(sizeof(int) * 250); 可以看成申请了一个拥有250个int元素的数组p

相当申请了一个整型变量空间,此后可以通过对 *p实现对这段空间的引用(赋值 运算)

for(i = 0; i < 3; i++) {
	p = (int *) malloc(sizeof(int) * 100);
}
for(i = 0; i < 3; i++) {
	free(p);
}

这个程序存在极为严重的内存泄漏问题,上半部分当第一次运行后,已经申请了一个p所指向的400B空间,然而第二次运行时,会出现新的p指向的空间,第一次申请的空间此时无法被使用,也无法被释放,整个程序结束后,只有一个可用的空间,其余两个无法使用与释放造成了内存泄漏,在下半部分中,系统只会释放一次也就是上半部分最后一次申请的空间,接下来程序无法找到可释放的p空间,释放空间失败,会造成操作系统崩溃,在实际工作中极为严重

32-链表

typedef struct POINT { 
	int row;
	int col;
	struct POINT *next;
}POINT;

POINT a, b, c, d, *p;

创建这个POINT类型的新结构体后,并对它赋值:a.row=1, a.col=2, b.row=3, b.col=4, c.row=5, c.col=6, d.row=7, d.col=8;
且a.next=&b, b.next=&c, c.next=&d, d.next=NULL; 这时我们创建了一个带头结点单向不循环链表,链表的每一个节点,由两部分组成:数据域和链域;
在这里插入图片描述

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值