Day17_堆变量、qsort等函数使用

本文介绍了堆中变量的生命周期管理、malloc、calloc、realloc函数的使用,以及字符串的复制和解析。通过实例展示了如何安全地分配、使用和释放堆内存,并提供了atoi、atof等字符串转换函数的应用。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >



堆中变量的生命周期由程序控制
为了使用堆中变量,需要一组标准函数,为了使用这些标准函数,需要包含stdlib.h文件

malloc可以从堆中分配多个连续的字节
---------------------------------------------------------
  1 #include <stdio.h>
  2 #include <stdlib.h>
  3
  4 int main()
  5 {
  6         int num=0;
  7         int *p_num=(int *)malloc(3*sizeof(int));
  8         if(p_num)
  9         {
 10                 for(;num<=2;num++)
 11                 {
 12                         //printf("%d\n",p_num[num]);
 13                         printf("%d\n",*(p_num + num));
 14                 }
 15                 free(p_num);//释放变量
 16                 p_num= NULL;//消灭野指针
 17         }  
 18         return 0;
 19 }
---------------------------------------------------------
malloc返回值记录了首字节地址
如果分配失败则返回值是NULL
分配好的变量就可以当成数组使用

当结束对堆中变量的使用后必须使用free函数释放这些变量
free函数需要首字节的地址作为参数
任何堆中的变量只能释放一次

malloc分配的地址如果没有在函数中被使用free释放掉,则可以被赋值给返回值
这种时候必须有其它函数负责释放这部分变量 

calloc函数也可以从堆中分配多个变量。分配完成后把所有变量内容清0
calloc函数需要两个参数,一个表示单个变量的大小,另一个表示变量的个数

realloc函数可以调整堆中分配变量的个数
realloc函数需要两个参数,第一个参数表示原来的首字符地址,第二个参数表示调整后的总字节个数
 例:p_str2=(int *)realloc(p_str,10*sizeof(int));
新地址可能和老地址不一样
realloc函数也可能失败,如果失败则返回null;

函数指针用来和函数配对(记录函数地址)
 例:typedef int (*p_func)(int, int);
     p_func p_add=add,p_sub=sub;
可以使用函数指针调用函数
函数名称可以用来表示函数的地址

qsort是一个标准函数,可以用来对多个数据进行顺序调整
---------------------------------------------------------
  1 #include <stdio.h>
  2 #include <stdlib.h>
  3
  4 int comp(const void *p_num,const void *p_num1)
  5 {
  6         const int *p_val=(const int*)p_num;
  7         const int *p_val1=(const int*)p_num1;
  8         if(*p_val > *p_val1)
  9         {
 10                 return 1;
 11         }
 12         else if(*p_val < *p_val1)
 13         {
 14                 return -1;
 15         }
 16         else
 17         {
 18                 return 0;
 19         }
 20 }
 21 int comp1(const void *p_num,const void *p_num1)
 22 {
 23         const int *p_val=(const int*)p_num;
 24         const int *p_val1=(const int*)p_num1;
 25         if(*p_val > *p_val1)
 26         {
 27                 return -1;
 28         }
 29         else if(*p_val < *p_val1)
 30         {
 31                 return 1;
 32         }
 33         else
 34         {
 35                 return 0;
 36         }
 37 }
 38
 39 int main()
 40 {
 41         int arr[]={80,90,10,20,30,40,50,60},num=0;
 42         //qsort(arr,8,sizeof(int),comp);
 43         qsort(arr,8,sizeof(int),comp1);
 44         for(num=0;num<=7;num++)
 45         {
 46                 printf("%d ",arr[num]);
 47         }
 48         printf("\n");
 49         return 0;
 50 }
---------------------------------------------------------
atoi可以把字符串中的整数转换成整数数据
atof可以把字符串中的带小数点的数字转换成double数据
以上两个函数需要包含stdlib.h头文件

sqrt函数可以计算一个数字的平方根
需要包含math.h头文件
编译时需要使用-lm选项

pow函数可以计算一个数字的幂
需要包含math.h头文件
编译时需要使用-lm选项

输出缓冲区显示在屏幕上的条件
1.遇到\n字符
2.函数结束时
3.输出缓冲区满了
4.使用fflush(stdout)语句强制显示

sleep函数可以让当前进程休眠n秒(时间长度由参数决定)
 应该包含unistd.h头文件
时间不精确

sprintf可以把变量内容打印在字符串中
sscanf可以从字符串中读数据并记录在变量中
---------------------------------------------------------
  1 #include <stdio.h>
  2
  3 int main()
  4 {
  5         char ch='a';
  6         int num=19;
  7         float fnum=4.8;
  8         char buf[20]={};
  9         sprintf(buf,"%c %d %g",ch,num,fnum);
 10         printf("%s\n",buf);
 11         ch=0;
 12         num=0;
 13         fnum=0.0f;
 14         sscanf(buf,"%c %d %g",&ch,&num,&fnum);
 15         printf("%d %c %g\n",num,ch,fnum);
 16         return 0;
 17 }
---------------------------------------------------------
fprintf/fscanf可以对文件进行格式化读写操作


预习:
 1.栈
 2.队列
 3.链表
作业:
 1.人员信息管理系统增加删除功能

练习:写一个自己的mystrcpy函数
  1 #include <stdio.h>
  2 #include <stdlib.h>
  3 char *mystrcpy(const char* p_ch)
  4 {
  5         int num=0;
  6         char *p_ret=NULL;
  7         while(*(p_ch+num))//*(p_ch+num) == p_ch[num]
  8         {
  9                 num++;//用来计算字符的长度
 10         }
 11         num++;
 12         p_ret=(char *)malloc(num*sizeof(char));//把从堆中申请到到空间首地址赋予p_ret;
 13         if(p_ret)//如果成功的话p_ret就不为空,执行下面内容
 14         {
 15                 num=0;
 16                 while(*(p_ch+num))
 17                 {
 18                         *(p_ret+num)=*(p_ch+num);//按位把字符赋值给p_ret;
 19                         num++;
 20                 }
 21         }
 22         return p_ret;//返回p_ret;
 23 }
 24
 25 int main()
 26 {
 27         char *p_ch=mystrcpy("abc");//mystrcpy函数返回的p_ret是个指针,把这个赋值给p_ch
 28         if(p_ch)
 29         {
 30                 printf("%s\n",p_ch);
 31                 free(p_ch);//释放
 32                 p_ch=NULL;//消灭野指针
 33         }
 34         return 0;
 35 }



#define _CRT_SECURE_NO_WARNINGS #include <stdio.h> #include <stdlib.h> #include <string.h> #include <time.h> #define MAX_BARCODE_LENGTH 20 #define MAX_NAME_LENGTH 50 #define MAX_MANUFACTURER_LENGTH 50 #define N 100 #define FILENAME "products.dat" // 前置声明 struct Product; void input_product(); void browse_product(); void query_product(); void modify_product(); void delete_product(); void sort_product(); void statistics_product(); void sell_product(); // 日期结构体 struct Date { int year; int month; int day; }; // 保质期结构体 struct ShelfLife { int months; }; // 商品结构体 struct Product { char barcode[MAX_BARCODE_LENGTH]; char name[MAX_NAME_LENGTH]; float price; int stock; struct Date productionDate; struct ShelfLife shelfLife; char manufacturer[MAX_MANUFACTURER_LENGTH]; }; // 输入验证函数 int is_valid_date(int y, int m, int d) { if (y < 1900 || y > 2100) return 0; if (m < 1 || m > 12) return 0; int days[] = { 31,28,31,30,31,30,31,31,30,31,30,31 }; if ((y % 4 == 0 && y % 100 != 0) || y % 400 == 0) days[1] = 29; return d > 0 && d <= days[m - 1]; } // 输入模块 void input_product() { FILE* fp; struct Product products[N]; int count = 0; char ans = 'y'; // 读取现有数据 fp = fopen(FILENAME, "rb"); if (fp) { count = fread(products, sizeof(struct Product), N, fp); fclose(fp); } while (ans == 'y' || ans == 'Y') { struct Product newProduct; int valid = 0; // 条形码查重 do { printf("商品条形码: "); scanf("%19s", newProduct.barcode); for (int i = 0; i < count; i++) { if (strcmp(products[i].barcode, newProduct.barcode) == 0) { printf("该条形码已存在!\n"); valid = 0; break; } valid = 1; } } while (!valid); // 其他输入 printf("商品名称: "); scanf("%49s", newProduct.name); printf("定价: "); while (scanf("%f", &newProduct.price) != 1 || newProduct.price <= 0) { printf("无效价格,请重新输入: "); while (getchar() != '\n'); } printf("库存数量: "); while (scanf("%d", &newProduct.stock) != 1 || newProduct.stock < 0) { printf("无效库存,请重新输入: "); while (getchar() != '\n'); } do { printf("生产日期(年 月 日): "); scanf("%d %d %d", &newProduct.productionDate.year, &newProduct.productionDate.month, &newProduct.productionDate.day); } while (!is_valid_date(newProduct.productionDate.year, newProduct.productionDate.month, newProduct.productionDate.day)); printf("保质期(月数): "); while (scanf("%d", &newProduct.shelfLife.months) != 1 || newProduct.shelfLife.months < 0) { printf("无效保质期,请重新输入: "); while (getchar() != '\n'); } printf("生产厂家: "); scanf("%49s", newProduct.manufacturer); products[count++] = newProduct; printf("继续输入吗?(y/n)"); while (getchar() != '\n'); scanf("%c", &ans); } // 写入文件 fp = fopen(FILENAME, "wb"); if (fp) { fwrite(products, sizeof(struct Product), count, fp); fclose(fp); } } // 浏览模块 void browse_product() { #ifdef _WIN32 system("cls"); #else printf("\033[2J\033[H"); #endif FILE* fp = fopen(FILENAME, "rb"); if (!fp) { printf("暂无商品数据\n"); return; } printf("%-20s %-20s %-10s %-10s %-15s %-10s %-30s\n", "条形码", "名称", "价格", "库存", "生产日期", "保质期", "厂家"); struct Product p; while (fread(&p, sizeof(struct Product), 1, fp) == 1) { printf("%-20s %-20s %-10.2f %-10d %04d-%02d-%02d %-10d %-30s\n", p.barcode, p.name, p.price, p.stock, p.productionDate.year, p.productionDate.month, p.productionDate.day, p.shelfLife.months, p.manufacturer); } fclose(fp); } // 新增排序比较函数 int compare_by_barcode(const void* a, const void* b) { return strcmp(((struct Product*)a)->barcode, ((struct Product*)b)->barcode); } int compare_by_price(const void* a, const void* b) { float diff = ((struct Product*)a)->price - ((struct Product*)b)->price; return (diff > 0) ? 1 : ((diff < 0) ? -1 : 0); } // 修改后的排序函数 void sort_product() { FILE* fp = fopen(FILENAME, "rb"); if (!fp) { printf("暂无商品数据\n"); return; } // 获取记录总数 fseek(fp, 0, SEEK_END); long file_size = ftell(fp); int count = file_size / sizeof(struct Product); fseek(fp, 0, SEEK_SET); // 读取全部数据 struct Product* products = malloc(file_size); fread(products, sizeof(struct Product), count, fp); fclose(fp); // 选择排序方式 printf("请选择排序方式:\n"); printf("1. 按条形码排序\n2. 按价格排序\n"); int choice; scanf("%d", &choice); if (choice == 1) { qsort(products, count, sizeof(struct Product), compare_by_barcode); } else if (choice == 2) { qsort(products, count, sizeof(struct Product), compare_by_price); } // 临时文件写入排序结果 FILE* tmp = fopen("temp.dat", "wb"); fwrite(products, sizeof(struct Product), count, tmp); fclose(tmp); // 替换原文件 remove(FILENAME); rename("temp.dat", FILENAME); free(products); printf("排序完成!\n"); }
05-29
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值