当前位置:网站首页>C学习完结

C学习完结

2022-04-23 19:23:00 L-xykeen

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进制数

字符串

  1. sizeof() 包含\0 strlen() 不包含\0

  2. strcpy(str3, str1); str1 拷贝到 str3

  3. strncpy(str3, str1, n); str3[n] = “\0”; n 是拷贝限制数,最后要加结束符,防止出现异常

  4. strcat(str1, str2); 连接 str1 与 str2

  5. 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 = &num;
	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 = &num;
    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);
}


版权声明
本文为[L-xykeen]所创,转载请带上原文链接,感谢
https://blog.csdn.net/jin_xinyu/article/details/124326638