Initial commit: C language learning code

This commit is contained in:
2025-07-20 16:30:56 +08:00
commit 06e24173a6
139 changed files with 9303 additions and 0 deletions
+102
View File
@@ -0,0 +1,102 @@
#include <stdio.h>
#include <stdlib.h>
// !类型定义
/*
1.自定义数据类型(typedef)
C语言提供了一个叫做typedef的功能来声明一个已有的数据类型的新名字。比如:
typedef int Length;
使得Length 成为int类型的别名。
这样,Length这个名字就可以代替int出现在变量定义和参数声明的地方了:
Length a, b, len;
Length numbers[10];
2.Typedef
声明新的类型的名字
新的名字是某种类型的别名
改善了程序的可读性
typedef long int64_t; //! 重载已有的类型名字新名字的含义更清晰具有可移植性
typedef struct ADate {
int month;
int day;
int year;
};Date; //! Data->struct ADate,简化了复杂的名字
int64_t i = 100000000000;
Date d = [9, 1, 2005];
*/
#define LEN sizeof(struct Student)
// 定义链表节点结构体
struct Student
{
long num; // 学号
float score; // 成绩
struct Student *next; // 指向下一个节点的指针
};
int n; // 记录节点个数,这里保持原代码全局变量的方式,也可优化为局部变量通过指针传递
// 创建动态链表的函数
struct Student *creat(void)
{
struct Student *head = NULL; // 头指针,初始化为空
struct Student *p1, *p2; // p1 用于指向新创建的节点,p2 用于指向当前链表的尾节点
n = 0; // 初始化节点计数
// 动态分配第一个节点的内存
p1 = p2 = (struct Student *)malloc(LEN);
if (p1 == NULL)
{ // 检查内存分配是否成功
printf("内存分配失败!\n");
return NULL;
}
scanf("%ld,%f", &p1->num, &p1->score); // 输入第一个学生的学号和成绩
// 循环创建节点,直到输入学号为 0 结束
while (p1->num != 0)
{
n++; // 节点个数加 1
if (n == 1)
{
head = p1; // 第一个节点,让头指针指向它
}
else
{
p2->next = p1; // 不是第一个节点,将新节点连接到链表尾部
}
p2 = p1; // 更新尾节点指针,使其指向当前最后一个节点
// 动态分配下一个节点的内存
p1 = (struct Student *)malloc(LEN);
if (p1 == NULL)
{ // 检查内存分配是否成功
printf("内存分配失败!\n");
// 若内存分配失败,处理已分配的节点,避免内存泄漏(简单示例中可简化处理)
return head;
}
scanf("%ld,%f", &p1->num, &p1->score); // 输入下一个学生的信息
}
p2->next = NULL; // 将链表最后一个节点的 next 置为 NULL,标记链表结束
return head; // 返回头指针,通过头指针可访问整个链表
}
// 遍历输出链表内容的函数(可选,用于验证链表创建结果)
void printList(struct Student *head)
{
struct Student *p = head;
while (p != NULL)
{
printf("学号:%ld,成绩:%.1f\n", p->num, p->score);
p = p->next;
}
}
int main()
{
struct Student *head = creat(); // 调用创建链表函数
printList(head); // 输出链表内容
// 注意:实际使用完链表后,应编写释放内存的函数来释放动态分配的节点,避免内存泄漏
// 这里简单示例可省略,复杂场景务必添加内存释放逻辑
return 0;
}
+53
View File
@@ -0,0 +1,53 @@
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <stdbool.h>
#include <string.h>
// !枚举
/*
1.枚举
枚举是一种用户定义的数据类型,它用关键字enum 以如下语法来声明:
enum 枚举类型名字{名字0....名字;
枚举类型名字通常并不真的使用,要用的是在大括号里的名字,因为它们就是就是常量符号,它们的类型是int,值则依次从0 到n。如:
enum colors { red, yellow, green};
就创建了三个常量,red的值是0yellow是1,而green是2。
当需要一些可以排列起来的常量值时,定义枚举的意义就是给了这些常量值名字。
这样需要遍历所有的枚举量或者需要建立一个用枚举量做下标的数组的时候就很方便了
2.枚举量
声明枚举量的时候可以指定值
enum COLOR ( RED=1, YELLOW, GREEN = 5); // !YELLOW的值是2GREEN的值是5
3.枚举只是int
即使给枚举类型的变量赋不存在的整数值也没有任何warning或error
4.枚举
虽然枚举类型可以当作类型使用,但是实际上很(bu)少(hao)用
如果有意义上排比的名字,用枚举比const int方便
枚举比宏(macro)好,因为枚举有int类型
*/
enum COLOR
{
RED,
YELLOW,
GREEN
};
int main(void)
{
int color = -1;
char *colorName = NULL;
printf("输入你喜欢的颜色的代码:");
scanf("%d", &color);
switch (color)
{
case RED: colorName = "red"; break;
case YELLOW: colorName = "yellow"; break;
case GREEN: colorName = "green"; break;
default: colorName= "unknown"; break;
}
printf("你喜欢的颜色是sn", colorName);
return 0;
}
+45
View File
@@ -0,0 +1,45 @@
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <stdbool.h>
#include <string.h>
// !类型定义
/*
1.自定义数据类型(typedef)
C语言提供了一个叫做typedef的功能来声明一个已有的数据类型的新名字。比如:
typedef int Length;
使得Length 成为int类型的别名。
这样,Length这个名字就可以代替int出现在变量定义和参数声明的地方了:
Length a, b, len;
Length numbers[10];
2.Typedef
声明新的类型的名字
新的名字是某种类型的别名
改善了程序的可读性
typedef long int64_t; //! 重载已有的类型名字新名字的含义更清晰具有可移植性
typedef struct ADate {
int month;
int day;
int year;
};Date; //! Data->struct ADate,简化了复杂的名字
int64_t i = 100000000000;
Date d = [9, 1, 2005];
3.typedef int Length; // Length就等价于int类型
typedef char* Strings[IO]; // Strings是10个字符串的数组的类型
typedef struct node{
int data;
struct node *next;
}aNode;
typedef struct node aNode;//这样用aNode就可以代替
struct node
*/
int main(void)
{
return 0;
}
+86
View File
@@ -0,0 +1,86 @@
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <stdbool.h>
#include <string.h>
// !结构与函数
/*
1.结构作为函数参数
int numberofDays(struct date d)
整个结构可以作为参数的值传入函数
这时候是在函数内新建一个结构变量,并复制调用者的结构的值
也可以返回一个结构
这与数组完全不同
*/
struct data
{
int month;
int day;
int year;
};
bool isLeap(struct data d);
int numberOfDays(struct data d);
int main(void)
{
struct data today, tomorrow;
printf("Enter today's date (mm dd yyyy): ");
scanf("%i %i %i", &today.month, &today.day, &today.year);
if (today.day != numberOfDays(today))
{
tomorrow.day = today.day + 1;
tomorrow.month = today.month;
tomorrow.year = today.year;
}
else if (today.month == 12)
{
tomorrow.day = 1;
tomorrow.month = 1;
tomorrow.year = today.year + 1;
}
else
{
tomorrow.day = 1;
tomorrow.month = today.month + 1;
tomorrow.year = today.year;
}
printf("Tomorrow's date is %i-%i-%i.\n", tomorrow.month, tomorrow.day, tomorrow.year);
return 0;
}
bool isLeap(struct data d)
{
bool leap = false;
if ((d.year % 4 == 0 && d.year % 100 != 0) || d.year % 400 == 0)
{
leap = true;
}
return leap;
}
int numberOfDays(struct data d)
{
int days;
const int daysPerMonth[12] = {31, 28, 31, 30, 31, 30, 31, 31, 30, 31, 30, 31};
if (d.month == 2 && isLeap(d))
{
days = 29;
}
else
{
days = daysPerMonth[d.month - 1];
}
return days;
}
+90
View File
@@ -0,0 +1,90 @@
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <stdbool.h>
#include <string.h>
// !结构与函数
/*
1.结构作为函数参数
int numberofDays(struct date d)
整个结构可以作为参数的值传入函数
这时候是在函数内新建一个结构变量,并复制调用者的结构的值
也可以返回一个结构
这与数组完全不同
2.输入结构没
高接的方式可以一次scanf 如果我们打算写一个函数来读入结构
那么些一个函数,专门用来读入结构
但是读入的结构如何送回来呢?
记住C在函数调用时是传值的
所以函数中的p与main中的y是不同的
在函数读入了p的数值之后,没有任何东西回到main,所以y还是{0,0}
前的方案,把一个结构传入了函数,然后在函数中操作,但是没有返回回去
问题在于传入函数的是外面那个结构的克隆体,而不是指针
传入结构和传入数组是不同的
在这个输入函数中,完全可以创建一个临时的结构变量,然后把这个结构返回给调用者
void main()
{
struct point y = (0,0};
y= inputPoint();
output(y):
}
struct point inputPoint()
{
struct point temp;
scanf("%d", &temp.x);
scanf("%d",&temp.y);
return temp;
}
3.
struct date
{
int month;
int day;
int year;
} myday;
struct date *p = &myday;
(*p).month = 12;
p->month = 12;
4.
*/
struct point
{
int x;
int y;
};
struct point *getStruct(struct point *);
void output(struct point);
void print(const struct point *p);
int main(void)
{
struct point y = {0, 0};
getStruct(&y);
output(y);
output(*getStruct(&y));
printf(getStruct(&y));
return 0;
}
struct point *getStruct(struct point *p)
{
scanf("%d", &p->x);
scanf("%d", &p->y);
printf("%d %d\n", p->x, p->y);
return p;
}
void output(struct point p)
{
printf("%d %d\n", p.x, p.y);
}
void print(const struct point *p)
{
printf("%d %d\n", p->x, p->y);
}
+102
View File
@@ -0,0 +1,102 @@
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <stdbool.h>
#include <string.h>
// !结构中的结构
/*
1.结构数组
struct date dates[!00];
struct date dates[] = {
{4,5,2005},
{2,4,2005}
}
* 最外面的大括号表示数组,里面的括号表示结构体
* 结构体本质是一种数据类型,数组是这种数据类型的变量
2.结构中的结构
struct dateAndTime {
struct date sdate;
struct time stime;
};
3.嵌套的结构
struct point {
int x;
int y;
};
struct rectangle {
struct point pt1;
struct point pt2;
};
如果有变量
struct rectangle r;
就可以有:
r.pt1.x、 rpt1.y, r.pt2.x 和 rpt2.y
如果有变量定义:
struct rectang1e r, *rp;
rp = &r;
那么下面的四种形式是等价的:
r.pt1.x
rp->pt1.x
(rpt1).x
(rp->pt1).x
但是没有rp->pt1->x(因为pt1不是指针)
*/
struct time
{
int hour;
int minute;
int second;
};
struct time timeUpdate(struct time now);
int main(void)
{
struct time testTime[5] = {
{11, 59, 59},
{12, 0, 0},
{1, 29, 59},
{23, 59, 59},
{19, 12, 27}
};
for (int i = 0; i < 5; i++)
{
printf("Time is %.2i:%.2i:%.2i\n",
testTime[i].hour, testTime[i].minute, testTime[i].second);
{
testTime[i] = timeUpdate(testTime[i]);
}
printf(" ... one second later it's %.2i:%.2i:%.2i\n",
testTime[i].hour, testTime[i].minute, testTime[i].second);
}
return 0;
}
struct time timeUpdate(struct time now)
{
++now.second;
if (now.second == 60)
{
now.second = 0;
++now.minute;
if (now.minute == 60)
{
now.minute = 0;
++now.hour;
if (now.hour == 24)
{
now.hour = 0;
}
}
}
return now;
}
+73
View File
@@ -0,0 +1,73 @@
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <stdbool.h>
#include <string.h>
// !结构类型
/*
1.在函数内/外
和本地变量一样,在函数内部声明的结构类型只能在函数内部使用
所以通常在函数外部声明结构类型,这样就可以被多个函数所使用了
2.声明结构的形式
struct point{
int x;
int y;
};
struct point pl,p2;
pl和p2都是point里面有x和y的值
struct{
int x;
int y;
}pl,p2;
p1和p2都是一种无名结构,里面有x和y
struct point{
int x;
int y;
} pl,p2;
pl和p2都是point里面有x和y的值t
*对于第一和第三种形式,都声明了结构point。但是第二种形式没有声明point,只是定义了两个变量
3.结构成员
结构和数组有点像
数组用口运算符和下标访问其成员
a[0]= 10;
结构用.运算符和名字访问其成员
today.day
student.firstName
pl.x pl.y
4.结构运算
要访问整个结构,直接用结构变量的名字
对于整个结构,可以做赋值、取地址,也可以传递给函数参数
pl = (struct point)(5, 10};
相当于pl.x=5;pl.y= I0;
pl=p2;
相当于pl.x= p2.x;pl.y= p2.y;
5.结构指针
和数组不同,结构变量的名字并不是结构变量的地址,必须使用&运算符
struct date *pDate = &today;
*/
struct data
{
int month;
int day;
int year;
};
int main(void)
{
struct data today;
today = (struct data){07,31,2014};
struct data day;
day = today;
day.year = 2015;
printf("Today's date is %i-%i-%i.\n", today.year, today.month, today.day);
printf("This month is %i-%i-%i.\n", day.year, day.month, day.day);
return 0;
}
+34
View File
@@ -0,0 +1,34 @@
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
#include <math.h>
#include <stdbool.h>
#include <string.h>
// !联合
/*
1.存储
所有的成员共享一个空间
同一时间只有一个成员是有效的
union的大小是其最大的成员
2.初始化
对第一个成员做初始化
*/
typedef union {
int i;
char ch[sizeof(int)];
} CHI;
int main()
{
CHI chi;
int i;
chi.i = 1234;
for ( i=0; i<sizeof(int); i++)
{
printf("%02hhx", chi.ch[i]);
}
printf("\n");
return 0;
}