C学习
小知识:
goto: 跳到指定位置
#include <stdio.h>
int main()
{
int a;
scanf_s("%d", &a);
if (a > 0) {
printf("no\n");
}
else
{
printf("yes\n");
goto A;//跳到 A 后面语句
}
A: printf("%d", a);
return 0;
}
强制转换:(填类型)10/3
itoa用法:
itoa(res, str, 10); //数字转为字符串(整型,字符串,进制)
● ltoa():将长整型值转换为字符串。
● ultoa():将无符号长整型值转换为字符串。
● gcvt():将浮点型数转换为字符串,取四舍五入。
● ecvt():将双精度浮点型值转换为字符串,转换结果中不包含十进制小数点。
● fcvt():指定位数为转换精度,其余同ecvt()。
-
‘\0’ :是字符串的结尾符
length = sizeof(array)/sizeof(array[0]); :求 int 数组长度
scanf(“%[ ^\n]”, str); :(非回车)获取字符集,遇到 回车时,停止获取
无前缀方式:
printf(“%o”,num) //无前缀o的8进制数
printf(“%d”,num) //无前缀0d的10进制数
printf(“%x”,num) //无前缀0x的小写16进制数
printf(“%X”,num) //无前缀0X的大写16进制数
有前缀方式:
printf(“%#o”,num) //有前缀o的8进制数
printf(“%#d”,num) //有前缀0d的10进制数
printf(“%#x”,num) //有前缀0x的小写16进制数
printf(“%#X”,num) //有前缀0X的大写16进制数
字符串
-
sizeof() 包含\0 strlen() 不包含\0
-
strcpy(str3, str1); str1 拷贝到 str3
-
strncpy(str3, str1, n); str3[n] = “\0”; n 是拷贝限制数,最后要加结束符,防止出现异常
-
strcat(str1, str2); 连接 str1 与 str2
-
strcmp(str1, str2) str1与str2 相同,返回0,否则1
指针
间接访问:
char a;
char *p = &a;
printf("请输入一个字符:");
scanf("%c", &a);
printf("%c\n", *p); //输出变量 a
指向数组的指针:(数组名是标记数组第一个元素的位置)(p+1 是地址(单个数组元素)+1)
char a[] = "abcd";
char *p = a;
printf("%c %c %c\n", *p, *(p+1), *(p+2));//输出 a b c
指针数组
例如: int *p[n]
:指针数组是一个数组,每个数组元素存放一个指针变量
int main(int argc, char *argv[]) {
char *p[3] = {
"李锦彪",
"黄欣宇",
"锦欣宇"
};
int i;
for(i = 0; i<3;i++){
printf("%s\n", p[i]);//加 *p 是取字符,不加取字符串
}
return 0;
}
数组指针
例如: int (*p)[5];
:数组指针是一个指针,它指向的是一个数组
int main(int argc, char *argv[]) {
int p[3] = {1,2,3};
int *p1 = p;//指针p1 指向p的第一个元素地址
int i;
for(i = 0; i<3;i++){
printf("%d\n", *(p1+i));
}
return 0;
}
int main(int argc, char *argv[]) {
int p[3] = {1,2,3};
int (*p1)[3] = &p;//取数组 p 的地址给 数组指针p1
int i;
for(i = 0; i<3;i++){
printf("%d\n", *(*p1+i));
}
return 0;
}
二维数组和指针
数组名是第一个元素的地址
例如: 二维数组arry[m] [n] , *arry 指向二维数组第一个元素地址
*(arry+1) 指向二维数组的第二行第一个元素的地址
int main(int argc, char *argv[]) {
int p[3][4] = {0};
int i,j,k=0;
for(i = 0; i<3;i++){
for(j = 0; j<4;j++){
p[i][j] = k++;
}
}
printf("*(p+1) : %p\n",*(p+1));
printf("p[1] : %p\n", p[1]);
printf("&p[1][0]: %p\n", &p[1][0]);
printf("*(*(p+1)+3): %d\n", *(*(p+1)+3));
printf("p[1][3]: %d\n", p[1][3]);
return 0;
//结论:*(p+i) == p[i]
// *(*(p+i)+j) == p[i][j]
// *(*(*(p+i)+j)+k) == p[i][j][k]
}
二维数组与指针 ( 一个 * 是取地址, ** 解引用 )
int main(int argc, char *argv[]) {
int temp[2][3] = {{1,2,3},{4,5,6}};
int (*p)[3] = temp;
//输出temp[1][0]
printf("**(p+1) : %d\n",**(p+1));
printf("**(temp+1) : %d\n", **(temp+1));
printf("temp[1][0] : %d\n", temp[1][0]);
//输出temp[1][2]
printf("*(*(p+1)+2) : %d\n",*(*(p+1)+2));
printf("*(*(temp+1)+2) : %d\n", *(*(temp+1)+2));
printf("temp[1][2] : %d\n", temp[1][2]);
return 0;
}
/*
**(p+1) : 4
**(temp+1) : 4
temp[1][0] : 4
*(*(p+1)+2) : 6
*(*(temp+1)+2) : 6
temp[1][2] : 6
*/
void 指针
:称之为通用指针,就是可以指向任意类型的数据。也就是说,任何类型的指针都可以赋值给void指针
int main(int argc, char *argv[]) {
int num = 1024;
int *pi = #
char *ps = "lijinbiao";
void *pv;
pv = pi;
printf("pi:%p, pv:%p\n",pi,pv);
printf("pv:%d\n",*(int *)pv); //使用void指针要强制类型转换
pv = ps;
printf("ps:%p, pv:%p\n",ps,pv);
printf("pv:%s\n",(char *)pv);
return 0;
}
/*
pi:000000000062FE04, pv:000000000062FE04
pv:1024
ps:0000000000404000, pv:0000000000404000
pv:lijinbiao
*/
null指针
建议:当你还不清楚要将指针初始化为什么地址时,请将它初始化为null;在对制作进行解引用时,先检查该指针是否为null。这种策略可以为你今后编写大型程序节省大量的调试时间
指向指针的指针
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-AiReqK4l-1650532107500)(C:\Users\15751083927\AppData\Roaming\Typora\typora-user-images\image-20220224195144476.png)]
int main(int argc, char *argv[]) {
char n[] = "abc";
char (*p)[] = &n;
char (**pp)[] = &p;
printf("%s\n",*p);
printf("%s\n",**pp);
return 0;
}
/*
abc
abc
指针数组和指向指针的指针
好处:
避免重复分配内存
只需要进行一处修改
int main(int argc, char *argv[]) {
char *cbook[] = {//指针数组
"李锦彪",
"黄欣宇",
"锦欣宇"};
char **bybook;
char **lilove[3];
bybook = &cbook[2];
lilove[0] = &cbook[0];
lilove[1] = &cbook[1];
lilove[2] = &cbook[2];
printf("bybook:%s\n",*bybook);
printf("lilove:\n");
int i;
for(i=0;i<3;i++){
printf("%s\n",*lilove[i]);
}
return 0;
}
/*输出结果:
bybook:锦欣宇
lilove:
李锦彪
黄欣宇
锦欣宇
数组指针和二维指针
int main(int argc, char *argv[]) {
int arry[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
int (*p)[4] = arry;
int i,j;
for(i=0;i<3;i++){
for(j=0;j<4;j++){
printf("%4d", *(*(p+i)+j));
}
printf("\n");
}
return 0;
}
/*
1 2 3 4
5 6 7 8
9 10 11 12
常量和指针
使用const 关键字修饰,使变量变为常量,即不可修改
const int price = 520;
const char str = "asdfj";
函数
void print_c(); //函数声明
void print_c(){ //函数定义
printf(" ****** \n");
printf("** **\n");
printf("** \n");
printf("** \n");
printf("** **\n");
printf(" ****** \n");
}
int main(int argc, char *argv[]) {
print_c(); //函数调用
return 0;
}
参数和指针
数组函数要有下标
#include <stdio.h>
#include <stdarg.h>
int sum(int n, ...);// n 是参数个数 ... 表示不确定几个参数
int sum(int n, ...){
int i, sum=0;
va_list vap; // 定义参数列表
va_start(vap, n); //开始 输入值
for(i=0;i<n;i++){
sum += va_arg(vap, int); // va_arg 获取每个参数的值(类型(int,char))
}
va_end(vap); //关闭列表
return sum;
}
int main(int argc, char *argv[]) {
int result;
result = sum(1,2,3,3);
printf("result = %d\n", result);
result = sum(10,2,3,4,5,6,7,8,99);
printf("result1 = %d\n", result);
return 0;
}
指针函数 函数指针
指针函数 :类型 *函数名 (参数)
不要返回局部变量的指针
#include <stdio.h>
#include <stdarg.h>
char *getWord(char c);
char *getWord(char c){
switch(c){
case 'A': return "Apple"; // 返回的是字符串的第一个地址
case 'B': return "Banana";
case 'C': return "Cat";
case 'D': return "Dog";
default: return"None";
}
}
int main(int argc, char *argv[]) {
char input;
printf("请输入一个字母:");
scanf("%c", &input);
printf("%s\n", getWord(input));
return 0;
}
/* 不能返回局部变量 如下:
char *getWord(char c){
char str1[] = "Apple";
char str2[] = "Banana";
char str3[] = "Cat";
char str4[] = "Dog";
char str5[] = "None";
switch(c){
case 'A': return str1;
case 'B': return str2;
case 'C': return str3;
case 'D': return str4;
default: return str5;
}
}
函数指针: 类型名 (*函数名)(参数)
int square(int);
int square(int num){
return num*num;
}
int main(int argc, char *argv[]) {
int num;
int(*fp)(int); //函数指针
printf("请输入一个整数:");
scanf("%d", &num);
fp = square;
printf("%d * %d = %d", num, num,(*fp)(num));
return 0;
}
int add(int, int);
int sub(int, int);
int calc(int (*fp)(int, int), int, int); //函数指针作为参数
int add(int a, int b){
return a+b;
}
int sub(int a, int b){
return a-b;
}
int calc(int (*fp)(int, int), int a, int b){ //int (*fp)(int, int) 函数指针
return (*fp)(a, b);
}
int main(int argc, char *argv[]) {
printf("3 + 5 = %d\n", calc(add, 3, 5));
printf("3 - 5 = %d\n", calc(sub, 3, 5));
return 0;
}
#include <stdio.h>
int add(int, int);
int sub(int, int);
int calc(int (*fp)(int, int), int, int);
int (*select(char))(int, int);
int add(int a, int b){
return a+b;
}
int sub(int a, int b){
return a-b;
}
int calc(int (*fp)(int, int), int a, int b){ //int (*fp)(int, int) 函数指针
return (*fp)(a, b);
}
int (*select(char op))(int, int){
switch(op){
case '+' : return add;
case '-' : return sub;
}
}
int main(int argc, char *argv[]) {
int a,b;
char op;
int (*fp)(int, int);
printf("请输入一个式子:");
scanf("%d%c%d", &a, &op, &b);
fp = select(op);
printf("%d %c %d = %d\n", a, op, b, (calc(fp, a, b)));
return 0;
}
局部变量 全局变量
不要大量使用全局变量
// extern 关键字 告诉编译器,这个变量我在后面定义了,别急着报错
#include <stdio.h>
void func();
void func(){
extern count; // extern 关键字 告诉编译器,这个变量我在后面定义了,别急着报错
count++;
}
int count = 0;
int main(int argc, char *argv[]) {
func();
printf("%d\n", count);
return 0;
}
作用域和链接属性
代码块作用域
int main(void) {
int i =100; // i1
{
int i = 110; // i2
{
int i = 120; //i3
printf("i = %d\n", i); // i = 120
}
// i = 110
{
int i = 130; //i4
printf("i = %d\n", i); // i = 130
}
printf("i = %d\n", i); // i = 110
}
printf("i = %d\n", i); // i = 100
return 0;
}
原型作用域
void func(int a, int b, int c);
函数作用域
函数作用域 只适用于goto语句的标签,作用将goto语句的标签限制在同一个函数内部,以防止出现重名标签。(不建议使用goto)
链接属性
external(外部的): 多个文件中声明的同名标识符表示同一个实体
internal(内部的):单个文件中声明的同名标识符表示同一个实体
none(无) :声明的同名标识符被当作独立不同的实体
只有具备文件作用域的标识符才能拥有external或internal的链接属性,其它作用域的标识符都是none属性
static :内部使用,可以保护全局变量
生存期和储存类型
静态存储期
具有文件作用域的变量属于静态存储期,函数也属于静态存储期。属于静态存储期的变量在程序执行期间将一直占据储存空间,直到程序关闭才释放
动态存储期
具有代码块作用域的变量一般情况下属于自动存储期。属于自动存储期的变量在代码块结束时将自动释放存储空间。
存储类型
auto
在代码块中声明的变量默认的存储类型就是自动变,使用关键字auto来描述
// 用auto提示覆盖前面的 i
int i;
int main(void){
auto int i;
return 0;
}
register(寄存器变量)
将一个变量声明为寄存器变量,那么该变量就有可能被存放于CPU的寄存器中。
static(静态局部变量)
//有static
void func();
void func(){
static int count = 0;
printf("ciount = %d\n", count);
count++;
}
int main(void){
int i;
for(i = 0; i< 10; i++){
func();
}
return 0;
}
/*
ciount = 0
ciount = 1
ciount = 2
ciount = 3
ciount = 4
ciount = 5
ciount = 6
ciount = 7
ciount = 8
ciount = 9
*/
//没有static
void func();
void func(){
int count = 0;
printf("ciount = %d\n", count);
count++;
}
int main(void){
int i;
for(i = 0; i< 10; i++){
func();
}
return 0;
}
/*
ciount = 0
ciount = 0
ciount = 0
ciount = 0
ciount = 0
ciount = 0
ciount = 0
ciount = 0
ciount = 0
ciount = 0
extern
告诉编译器在其他地方定义了
typedef
为数据类型定义一个别名
递归
#include <stdio.h>
long fact(int num);
long fact(int num){
long result;
if(num>0){
result = num * fact(num-1);
}
else
{
result = 1;
}
return result;
}
int main(void) {
int num;
printf("请输入:");
scanf("%d",&num);
printf("%d\n", fact(num));
return 0;
}
汉诺塔
#include <stdio.h>
void fact(int n, char x, char y, char z);
void fact(int n, char x, char y, char z){
if(n == 1){
printf("%c --> %c\n", x, z);
}
else
{
fact(n-1, x, z, y);
printf("%c --> %c\n", x, z);
fact(n-1, y, x, z);
}
}
int main(void) {
int n;
printf("请输入汉诺塔层数:");
scanf("%d",&n);
fact(n, 'X', 'Y','Z');
return 0;
}
快速排序
分治法
#include <stdio.h>
void quick_sort(int array[], int left, int right);
void quick_sort(int array[], int left, int right){
int i = left, j = right;
int temp;
int pivot; // 基准点
pivot = array[(left + right) / 2];
while(i <= j){
//与基准点的大小对比,决定排序方式
//从左到右找到大于等于基准点的元素
while(array[i] > pivot){
i++;
}
//从右到左找到小于等于基准点的元素
while(array[j] < pivot){
j--;
}
//如果i <= j,则互换
if(i <= j){
temp = array[i];
array[i] = array[j];
array[j] = temp;
i++;
j--;
}
}
if(left < j){
quick_sort(array, left, j);
}
if(i < right){
quick_sort(array, i, right);
}
}
int main() {
int array[] = {11,22,5,8,9,465,45};
int i, length;
length = sizeof(array) / sizeof(array[0]); // 获得数组长度
quick_sort(array, 0, length-1);
printf("排序后的结果是:");
for ( i = 0; i < length; i++) {
printf("%d ", array[i]);
}
return 0;
}
动态内存
malloc(申请动态内存空间)
函数原型:
void *malloc(size_t size);
malloc函数向系统申请分配size个字节的内存空间,并返回一个指向这块空间的指针。
#include <stdio.h>
#include <malloc.h>
int main() {
int *ptr;
ptr = (int *)malloc(sizeof(int));
if(ptr == NULL){
printf("分配内存失败!\n");
exit(1);
}
printf("请输入一个整数:");
scanf("%d", ptr);
printf("你输入的数是:%d\n", *ptr);
return 0;
}
还可以申请一块任意内存的空间:
void arrmalloc(){
int *ptr = NULL;
int num;
printf("请输入带录入整数的个数:");
scanf("%d", &num);
ptr = (int *)malloc(num * sizeof(int));
for (int i = 0; i < num; i++) {
printf("请录入第 %d 个整数:", i+1);
scanf("%d", &ptr[i]);
}
printf("你录入的整数是:");
for (int i = 0; i < num; i++) {
printf("%d ", ptr[i]);
}
putchar('\n');
free(ptr);//用完注释掉
}
初始化内存空间 在 <string.h> 里
memset :使用一个常量字节填充内存空间
memcpy :拷贝内存空间
memmove :拷贝内存空间
memcmp :比较内存空间
memchr :在内存空间中搜索一个字符
void memm(){
int *ptr = NULL;
ptr = (int *)malloc(N * sizeof(int));
if(ptr == NULL){
exit(1);
}
memset(ptr, 0, N * sizeof(int));
for (int i = 0; i < N; i++) {
printf("%d ", ptr[i]);
}
putchar('\n');
free(ptr);
}
free(释放动态内存空间)
函数原型:
void free(void *ptr);
释放ptr参数指向的内存空间
#include <stdio.h>
#include <malloc.h>
void maloc();
void maloc(){
int *ptr;
int num = 123;
ptr = (int *)malloc(sizeof(int));
if(ptr == NULL){
printf("分配内存失败!\n");
exit(1);
}
printf("请输入一个整数:");
scanf("%d", ptr);
printf("你输入的数是:%d\n", *ptr);
//内存泄漏, 没有及时释放
ptr = #
printf("你输入的数是:%d\n", *ptr);
free(ptr); //释放空间
}
int main() {
maloc();
return 0;
}
void callocs(){
int *ptr1 = NULL;
int *ptr2 = NULL;
//第一次申请得申请空间
ptr1 = (int *) malloc(20 * sizeof(int));
//进行若干次操作后发现ptr1申请的内存空间不够用
//第二次申请内存空间
ptr2 = (int *) malloc(20 * sizeof(int));
//将prt1 拷贝到ptr2中
memcpy(ptr2, ptr1, 10);
free(ptr1);
//对ptr2申请的内存空间进行若干操作
free(ptr2);
}
calloc(申请并初始化一系列内存空间)
函数原型:
void *calloc(zise_t nmemb, size_t size);
该函数在内存中动态的申请nmemb个长度为size的连续内存空间(即申请的总空间尺寸为 nmemb * size),这些内存空间全部被初始化为 0。
realloc(重新分配内存空间)
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-XKsU0PoM-1650532107502)(C:\Users\15751083927\AppData\Roaming\Typora\typora-user-images\image-20220302171057450.png)]
void reallocs(){
int num;
int count = 0;
int *ptr = NULL; //注意必须初始化为NULL
do{
printf("请输入一个整数(输入-1表示结束):");
scanf("%d", &num);
count++;
ptr = (int *) realloc(ptr, count * sizeof(int));
if(ptr == NULL){
exit(1);
}
ptr[count-1] = num;
}while(num != -1);
printf("输入的整数分别是:");
for (int i = 0; i < count; i++) {
printf("%d ",ptr[i]);
}
free(ptr);
}
宏定义
#include <stdio.h>
#define MAX(x, y) (((x) > (y)) ? (x):(y))
int main() {
int x,y;
scanf("%d %d", &x,&y);
printf("%d\n", MAX(x, y));
return 0;
}
结构体
struct 结构体名称{
结构体成员
。。。。
。。。
};
#include <stdio.h>
struct Book{ //定义一个结构体
char title[128];
char author[40];
float price;
unsigned int date;
char publisher[40];
}/* book 在这定义是全局变量*/;
int main() {
struct Book book; //在这定义是局部变量
printf("请输入书名:");
scanf_s("%s", book.title); //使用 . 获取成员
printf("请输入作者:");
scanf_s("%s", book.author);
printf("请输入售价:");
scanf_s("%f", &book.price);
printf("请输入出版日期:");
scanf_s("%d", &book.date);
printf("请输入出版社:");
scanf_s("%s", book.publisher);
printf("数据录入完毕!");
printf("书名:%s\n", book.title);
printf("作者:%s\n", book.author);
printf("售价:%f\n", book.price);
printf("日期:%d\n", book.date);
printf("出版社:%s\n", book.publisher);
return 0;
}
**嵌入结构体: **
#include <stdio.h>
struct Date{
int year;
int month;
int day;
};
struct Book{ //定义一个结构体
char title[128];
char author[40];
float price;
struct Date date;//嵌入一个结构体
char publisher[40];
}/* book 在这定义是全局变量*/
book = {
"李锦彪",
"黄欣宇",
999,
{2020, 7, 11},
"徐州"
};
int main() {
//struct Book book; //在这定义是局部变量
printf("书名:%s\n", book.title);
printf("作者:%s\n", book.author);
printf("售价:%.2f\n", book.price);
//访问到哪,要去到最底层
printf("日期:%d-%d-%d\n", book.date.year, book.date.month, book.date.day);
printf("出版社:%s\n", book.publisher);
return 0;
}
结构体指针
[外链图片转存失败,源站可能有防盗链机制,建议将图片保存下来直接上传(img-P9JOTeHv-1650532107503)(C:\Users\15751083927\AppData\Roaming\Typora\typora-user-images\image-20220303165313657.png)]
#include <stdio.h>
struct Date{
int year;
int month;
int day;
};
struct Book{ //定义一个结构体
char title[128];
char author[40];
float price;
struct Date date;//嵌入一个结构体
char publisher[40];
}/* book 在这定义是全局变量*/
book = {
"李锦彪",
"黄欣宇",
999,
{2020, 7, 11},
"徐州"
};
int main() {
//struct Book book; //在这定义是局部变量
struct Book *pt;
pt = &book;
printf("书名:%s\n", pt->title); //解引用 指针 -> 变量名
printf("作者:%s\n", pt->author);
printf("售价:%.2f\n", (*pt).price); // 解引用 (*指针).变量名
//访问到哪,要去到最底层
printf("日期:%d-%d-%d\n", (*pt).date.year, (*pt).date.month, (*pt).date.day);
printf("出版社:%s\n", (*pt).publisher);
return 0;
}
传递结构体变量
#include "stdio.h"
struct Date{
int year;
int month;
int day;
};
struct Book{
char title[128];
char author[40];
float price;
struct Date date;
char publisher[40];
};
void getInput(struct Book *book);
void printbook(struct Book *book);
void getInput(struct Book *book){
printf("请输入书名:");
scanf("%s", book->title);
printf("请输入作者:");
scanf("%s", book->author);
printf("请输入售价:");
scanf("%f", &book->price);
printf("请输入出版日期:");
scanf("%d-%d-%d", &book->date.year, &book->date.month, &book->date.day);
printf("请输入出版社:");
scanf("%s", book->publisher);
}
void printbook(struct Book *book){
printf("书名:%s\n", book->title);
printf("作者:%s\n", book->author);
printf("价钱:%.2f\n", book->price);
printf("出版日期:%d-%d-%d\n", book->date.year, book->date.month, book->date.day);
printf("出版社:%s\n", book->publisher);
}
int main(void){
struct Book b1,b2;
printf("请录入第一本书的信息.。。\n");
getInput(&b1);
printf("\n");
printf("请输入第二本书的信息。。。\n");
getInput(&b2);
printf("\n\n录入完毕,现在开始打印验证。。。\n\n");
printf("打印第一本书的信息\n");
printbook(&b1);
printf("\n\n打印第二本书的信息\n");
printbook(&b2);
return 0;
}
动态申请结构体
#include <malloc.h>
#include "stdio.h"
#include "stdlib.h"
struct Date{
int year;
int month;
int day;
};
struct Book{
char title[128];
char author[40];
float price;
struct Date date;
char publisher[40];
};
void getInput(struct Book *book);
void printbook(struct Book *book);
void getInput(struct Book *book){
printf("请输入书名:");
scanf("%s", book->title);
printf("请输入作者:");
scanf("%s", book->author);
printf("请输入售价:");
scanf("%f", &book->price);
printf("请输入出版日期:");
scanf("%d-%d-%d", &book->date.year, &book->date.month, &book->date.day);
printf("请输入出版社:");
scanf("%s", book->publisher);
}
void printbook(struct Book *book){
printf("书名:%s\n", book->title);
printf("作者:%s\n", book->author);
printf("价钱:%.2f\n", book->price);
printf("出版日期:%d-%d-%d\n", book->date.year, book->date.month, book->date.day);
printf("出版社:%s\n", book->publisher);
}
int main(void){
struct Book *b1, *b2;
// 动态申请结构体
b1 = (struct Book *)malloc(sizeof(struct Book));
b2 = (struct Book *)malloc(sizeof(struct Book));
if(b1 == NULL || b2 == NULL){
printf("内存分配失败");
exit(1);
}
printf("请录入第一本书的信息.。。\n");
getInput(b1);
printf("\n");
printf("请输入第二本书的信息。。。\n");
getInput(b2);
printf("\n\n录入完毕,现在开始打印验证。。。\n\n");
printf("打印第一本书的信息\n");
printbook(b1);
printf("\n\n打印第二本书的信息\n");
printbook(b2);
//有申请就有释放
free(b1);
free(b2);
}
单链表
头插法
#include <malloc.h>
#include "stdio.h"
struct Book{
//信息域
char title[128];
char author[40];
//指针域
struct Book *next;
};
void getInput(struct Book *book){
printf("请输入书名:");
scanf("%s", book->title);
printf("请输入作者:");
scanf("%s", book->author);
}
//当我们需要在函数内部申请内存并通过变量传出时。往往使用二级指针
void addBook(struct Book **head){ //二级指针,为了让head原本指向的NULL,指向别处
struct Book *book, *temp;
//申请一个新的节点
book = (struct Book *)malloc(sizeof(struct Book));
if(book == NULL){
printf("失败");
exit(1);
}
//获取输入
getInput(book);
//判断是否为空的单链表
if(*head != NULL){
temp = *head; //原先 head 指向的地址 存在temp里
*head = book; //head 指向book
book->next = temp;//book 指向 刚才head 存在temp里的地址
}else{
*head = book; //head 指向新的节点
book->next = NULL; //节点指向 NULL
}
}
void printlibrary(struct Book *library){
struct Book *book;
int count = 1;
book = library;
while(book != NULL){
printf("Book%d: \n", count);
printf("书名:%s\n", book->title);
printf("作者:%s\n", book->author);
book = book->next;
count++;
}
}
void release(struct Book *head){
while (head != NULL){
head = head->next;
free(head);
}
}
int main(void){
//头节点保存下个信息域的地址
struct Book *head = NULL; //指向第一个节点的指针变量;指向head里存的东西
int ch;
while(1){
printf("请问是否输入(Y/N):");
do{
ch = getchar();
} while (ch != 'Y' && ch != 'N');
if(ch == 'Y'){
//相当于传入指向head的指针
addBook(&head);//传递head的地址
}else{
break;
}
}
printf("请问书否要打印图书信息(Y/N):");
do{
ch = getchar();
} while (ch != 'Y' && ch != 'N');
if(ch == 'Y'){
printlibrary(head);
}
release(head);
return 0;
}
链表
#include "stdio.h"
#include "stdlib.h"
typedef struct node{
int value[2];
struct node *next; // 定义头指针
}Node;
typedef struct list{
Node *head;
Node *tail;
}List;
void add(List *pList, int a, int b);
void print(List *plist);
int main(void){
int n, m, a, b;
List list;
list.head = list.tail = NULL;
scanf("%d %d", &n, &m);
for (int i = 0; i < n + m; ++i) {
scanf("%d %d", &a, &b);
add(&list, a, b); //调用函数增加链表内容,传 list 的指针
}
//输出
print(&list);
//搜索
Node *p;
printf("请输入要查找的数:");
scanf("%d", &n);
int temp = 0;
for (p = list.head;p;p=p->next){
if (p->value[0] == n){
temp = 1;
printf("查找到了\n");
break;
}
}
if (temp == 0){
printf("没有查找到\n");
}
//删除
Node *q;
printf("请输入要删除的数:");
scanf("%d", &n);
for (q=NULL, p = list.head;p;q=p,p=p->next){//q 比 p 慢一步
if (p->value[0] == n){
if (q){ //q 是否为空
q->next = p->next;
} else{
list.head = p->next;
}
free(p);
printf("已经删除\n");
print(&list);
break;
}
}
//释放
for (p = list.head;p;p=q){
q = p->next;
free(p);
}
printf("释放完成\n");
return 0;
}
void add(List *pList, int a, int b){
//增加一个节点
Node *p = (Node *)malloc(sizeof(Node));//申请空间
p->value[0] = a; //赋值给 p 节点
p->value[1] = b;
p->next = NULL;
// 查找已有链表的最后那个节点指针
Node *last = pList->head; // 为遍历做准备 last 等于第一个(头节点)
if (last){ //head 不为空
// 遍历
while (last->next){
last = last->next;
}//遍历结束之后,last 就是最后那个
//连接到 p 节点
last->next = p;
}else{ // head 为空, head 指向第一个
pList->head = p;
}
}
void print(List *pList){
Node *p;
for (p = pList->head; p ; p = p->next) {
printf("%d %d\n", p->value[0], p->value[1]);
}
printf("\n");
}
静态链表
#include "stdio.h"
#include "stdlib.h"
#include "string.h"
typedef struct link{
int data; //数据域
int cur; //游标
}component;
void reserveArr(component *array); //创建备用链表
int mallocArr(component *array); //提取备用空间
int initArr(component *array); //初始化静态链表
void show(component *array, int body); //输出链表
int main(){
int body;
component array[11]; //定义一个数组
body = initArr(array);
printf("静态链表、\n");
show(array, body);
return 0;
}
int initArr(component *array){
int body, tempbody, j;
reserveArr(array); // 调用函数创建备用链表
body = mallocArr(array); //调用函数提取备用空间
tempbody = body; //声明一个变量把它当指针使,指向链表的最后一个节点,因为链表为空,所以和头节点重合
for (int i = 0; i < 11; ++i) {
j = mallocArr(array); //从备用链表中拿出空闲的分量
array[tempbody].cur = j; //将申请的空闲分量链接在链表的最后一个节点后面
array[j].data = i; //给新申请的分量数据域初始化
tempbody = j; //将指向链表最后一个节点的指针后移
}
array[tempbody].cur = 0; //新的链表最后一个节点的指针设为0
return body;
}
void reserveArr(component *array){ //创建备用链表
for (int i = 0; i < 11; ++i) {
array[i].cur = i+1; //每个数组分量链接到一起
}
array[10].cur = 0; //链表最后一个节点的游标为0
}
//提取备用空间
//若备用链表为空,则返会分配的节点下标,否则返回0(当分配最后一个节点时,该节点的有标志为0)
int mallocArr(component *array){
int i = array[0].cur;
if (array[0].cur){
//array[0].data = 0;
array[0].cur = array[i].cur;
}
return i; // 返回的是array[0]对应 游标
}
void show(component *array, int body){
int tempbody = body; //tempbody准备遍历使用
while (array[tempbody].cur){
printf("%d--%d\n", array[tempbody].data, array[tempbody].cur);
tempbody = array[tempbody].cur;
}
//输出最后一组
printf("%d---%d\n", array[tempbody].data, array[tempbody].cur);
}
initArr(component *array); //初始化静态链表
void show(component *array, int body); //输出链表
int main(){
int body;
component array[11]; //定义一个数组
body = initArr(array);
printf(“静态链表、\n”);
show(array, body);
return 0;
}
int initArr(component *array){
int body, tempbody, j;
reserveArr(array); // 调用函数创建备用链表
body = mallocArr(array); //调用函数提取备用空间
tempbody = body; //声明一个变量把它当指针使,指向链表的最后一个节点,因为链表为空,所以和头节点重合
for (int i = 0; i < 11; ++i) {
j = mallocArr(array); //从备用链表中拿出空闲的分量
array[tempbody].cur = j; //将申请的空闲分量链接在链表的最后一个节点后面
array[j].data = i; //给新申请的分量数据域初始化
tempbody = j; //将指向链表最后一个节点的指针后移
}
array[tempbody].cur = 0; //新的链表最后一个节点的指针设为0
return body;
}
void reserveArr(component *array){ //创建备用链表
for (int i = 0; i < 11; ++i) {
array[i].cur = i+1; //每个数组分量链接到一起
}
array[10].cur = 0; //链表最后一个节点的游标为0
}
//提取备用空间
//若备用链表为空,则返会分配的节点下标,否则返回0(当分配最后一个节点时,该节点的有标志为0)
int mallocArr(component *array){
int i = array[0].cur;
if (array[0].cur){
//array[0].data = 0;
array[0].cur = array[i].cur;
}
return i; // 返回的是array[0]对应 游标
}
void show(component *array, int body){
int tempbody = body; //tempbody准备遍历使用
while (array[tempbody].cur){
printf(“%d–%d\n”, array[tempbody].data, array[tempbody].cur);
tempbody = array[tempbody].cur;
}
//输出最后一组
printf(“%d—%d\n”, array[tempbody].data, array[tempbody].cur);
}