C语言学习笔记
为今年考研打基础,重新系统的学习C语言
由于之前学习过JAVA,因此本博客只记录自己在学习中所需记录的知识点。
1、数据类型
数据类型 | 字节数(64位) |
---|---|
short | 2 |
int | 4 |
long | 8 |
char | 1 |
float | 4 |
double | 8 |
注:原生C语言中不含有,利用“零”和“非零”表示。C99中含有Boolean类型变量,但要引入 stdbool.h 文件
2、内存释放
相关应用程序再将自身占用的内存空间释放时,是将该内存空间的操作权限返还给操作系统,内存空间数据不做改变。因此在程序中变量必须要进行初始化,否则再分配内存空间给该变量时,可能会将前程序的垃圾数据赋值给该变量。
3、什么是ASCII码以及字符存储的本质
字符存储的本质也是二进制,而ASCII码就是二进制与字符之间的映射。
char j = 'A';
printf("%d \n",j); //输出为65
4、printf函数
printf(“字符串”)
printf(“输出控制符 输出控制符…”,输出参数1,输出参数2…)
输出控制符包括:%d、%ld、%c、%f、%lf、%#X(带0x的十六进制数)
5、scanf函数
scanf(“输入控制符”,输入参数)
功能:将从键盘输入的字符转化为输出控制符所规定格式的数据,然后 存入输出参数地址的变量中。
注:当一次给多个变量赋值时,每个变量以回车结束。当输出控制符与非输出控制符混杂时,非输出控制符必须鸳鸯输入。
int i;
scanf("%d", &i);
printf("%#X", i); //输出为0x64
int j;
scanf("m%d",&j); //此时键盘输入第一个字符必须是m。
//输入m123n时,输出为123
6、数组
(1)C语言中定义一个数组,其在内存中的存储是连续的,并且一个数组所存储数据的数据类型相同。
(2)数组初始化时,若未将所有数据给予初值,则未给予初值的数据为0。当只进行数组变量声明而未进行初始化时,该数组中数据为垃圾数据。
int a[5] = {1, 2, 3};
for (int i=0; i<5; i++){
printf("a[%d] = %d\n", i, a[i]);
}
/*输出结果
a[0] = 1
a[1] = 2
a[2] = 3
a[3] = 0
a[4] = 0
*/
int a[5];
for (int i=0; i<5; i++){
printf("a[%d] = %d\n", i, a[i]);
}
/*
a[0] = 8
a[1] = 0
a[2] = 18
a[3] = 0
a[4] = 11484480
*/
// 基于以上结论,可以利用如下代码实现数组清零初始化
int a[5] = {0};
(3)数组名的含义:数组名是一个指针,他指向当前数组首元素
# include <stdio.h>
# include <stdlib.h>
int main(void)
{
int a[5] = {1, 2, 3, 4, 5};
printf("%#X\t%#X\n", a, &a[0]);
system("pause");
return 0;
}
// 输出:0X61FE00 0X61FE00
(4)数组下标的含义:确定一个数组元素需要两个元素:数组首元素地址及改元素相对于首元素地址的偏移量
# include <stdio.h>
# include <stdlib.h>
int main(void)
{
int a[5] = {1, 2, 3, 4, 5};
printf("%d\t%d\n", *(a+1), a[1]);
system("pause");
return 0;
}
// 输出: 2 2
7、函数
C语言中自定义函数需要放在调用位置前或将其在开头进行声明。# include <***.h> 就是对对应头文件中定义函数的声明。
# include <stdio.h> // 利用头文件进行相关函数的声明
void function(void); // 对自定义函数的声明,若无声明,则编译器无法通过编译
int main(void)
{
function();
return 0;
}
void function(void)
{
printf("A");
}
8、指针
(1)初识指针
int * p;
int i;
/*
p是变量的名字,int * 表示 p 变量存放的是 int 数据类型的变量地址;
int * p 应该这样理解:定义了一个 int * 类型的变量,变量名为 p;
*p = i p = &i;
*/
(2)野指针
int * p;
int i = 5;
*p = i;
int * p; 在内存中开辟了一块内存空间给当前程序,该内存空间在当前程序未进行初始化时,会存有垃圾数据,而声明为指针类型变量后,该程序会将当前垃圾数据作为一个地址(即现在 p 指向一个不明内存地址);而 *p = i;就会把这个不明内存中数据进行修改,不是我们所希望的将 p 指向 i。正确的做法是 p = &i;
(3)静态内存所存在的问题
1、以静态数组为例,我们在定义一个数组时,必须在定义的时候规定其数组的长度(例如 int a[5]),而当这个数组定义完毕后,他的长度就不能进行改变了,即不能进行动态扩充。
2、我们没有权限去控制内存空间释放的时间,释放内存的权限在于操作系统,只有当该函数运行结束后,为该函数分配的内存空间会被自动释放。
3、我们无法调用某运行结束的函数中所声明的变量,因为该变量已经随函数运行结束而被释放。
4、如何动态定义一个数组
# include <stdio.h>
# include <stdlib.h>
# include <malloc.h>
int main(void)
{
int length;
printf("请输入您所需数组长度:\n");
scanf("%d", &length);
int * pArr = (int *) malloc(sizeof(int) * length); // 利用 malloc 函数声明了指定长度的存储 int 类型变量的内存空间
printf("请为元素赋值:\n");
for(int i = 0; i < length; i++)
{
scanf("%d", &pArr[i]);
}
printf("数组所包含元素:\n");
for(int i = 0; i < length; i++)
{
printf("%d\n", pArr[i]);
}
system("pause");
}
9、结构体
(1)为什么要有结构体?
参考 JAVA 中的类,目的是便于模拟现实世界,将具体事务抽象出相关属性封装至一个新的数据结构中,便于操作。
(2)如何定义结构体
// 方法一(最最常用的方法)
struct Student
{
int age;
char sex;
};
// 方法二
// 不推荐使用,该定义方法直接将变量进行声明,当想再次定义新变量时可能会出现错误
struct Student
{
int age;
char sex;
}stu;
// 方法三
// 不实用,没有对应数据变量类型名,后续无法进行定义
struct
{
int age;
char sex;
}std;
(3)如何进行结构体初始化
// 以第一种定义方法为例
# include <stdio.h>
# include <stdlib.h>
struct Student
{
int age;
char sex;
}; // 注意:此处有分号。将以上语句理解为定义一个新的数据类型即可
int main(void)
{
struct Student std1 = {20, 'F'}; // 定义时直接初始化
printf("std1.age = %d, std1.sex = %c\n", std1.age, std1.sex);
struct Student std2; // 先定义,然后逐个赋值
std2.age = 21;
std2.sex = 'M';
printf("std2.age = %d, std2.sex = %c\n", std2.age, std2.sex);
struct Student std3; // 利用指针进行操作
struct Student * p;;
p = &std3;
p -> age = 22; // 在计算机内部会被处理为 (*p).age = 22;
p -> sex = 'M';
printf("std3.age = %d, std3.sex = %c\n", p -> age, p -> sex);
system("pause");
return 0;
}
10、枚举
将一件事物所有可能的取值进行封装,增强程序的安全性。其内部按照整型变量进行存储,第一个元素为0、第二个为1,以此类推。
# include <stdio.h>
# include <stdlib.h>
enum WeekDay
{
Mon, Tues, Wed, Thur, Fri, Sat, Sun
};
int main(void)
{
enum WeekDay day = Mon;
printf("%d", day); // 输出:0
system("pause");
}
杂记
1、Linux 下 make 的使用
首先建立 makefile(其他文件名也可,使用 make -f filename 即可,不添加 -f 默认搜索 makefile 文件进行执行)文件,在其中编写相关依赖及所需执行的 gcc 代码,然后运行 make 即可。
2、typedef 用法
作用:为数据类型的名字起一个别名,多用于结构体中,可简化变量声明时的工作量。
# include <stdio.h>
# include <stdlib.h>
typedef int ZHENGXING; // 为 int 数据类型起了个别名 ZHENGXING
typedef struct Student
{
int stdNo;
char sex;
}* pSTD, STD; // 为 struct Student * 起别名为:pSTD
// 为 struct Student 起别名为:STD
int main(void)
{
ZHENGXING i = 1;
printf("i = %d\n", i);
STD std; // 等价于 struct Student std;
pSTD pStd = &std; // 等价于 struct Student * pStd = &std;
pStd->sex = 'F';
printf("%c\n", pStd->sex);
system("pause");
return 0;
}