当前位置: 首页 > wzjs >正文

哈尔滨无障碍网站建设建网站找谁

哈尔滨无障碍网站建设,建网站找谁,青苹果乐园免费观看日本,南昌做建网站的内容提要 指针 void与void*的区别 内存操作 综合案例:学生成绩管理系统2.0 回顾 二级指针: 指向另一个指针的指针。二级指针等效于指针数组,不等效于二维数组 常量指针: 语法: const int* p; 特点&#xff1…

内容提要

  • 指针

    • void与void*的区别

  • 内存操作

  • 综合案例:学生成绩管理系统2.0

回顾

二级指针:

指向另一个指针的指针。二级指针等效于指针数组,不等效于二维数组

常量指针:

语法:

 const int* p;

特点:

  • 指针的指向可变,指向的数据不可变

指针常量

语法:

 int* const p;

特点:

  • 指针的指向不可变,指向的数据可变

常量指针常量

语法:

 const int* const p;

特点:

  • 指针的指向不可变,指向的数据不可变

内存的动态分配:
  1. malloc() 内存分配到堆区,需要初始化,清零使用memset或者realloc或者bzero(非标准库)

  2. calloc() 内存分配到堆区,默认已经完成了初始化

  3. realloc() 针对malloc、calloc、realloc分配的内存进行扩容,扩容后会保留原数据,空余位置需要初始化

  4. free() 释放分配的内存,也可以使用realloc(p,0)

野指针产生的场景:
  • 指针未初始化

  • 访问已经释放了的指针

  • 函数中返回局部变量的地址

  • 指针的越界访问

空指针:

值为NULL的指针,初始化的时候可以给指针赋值为NULL,内存释放后,需要对指针置空(NULL)

空悬指针:

野指针的一种特殊表现,指针指向的内存已经被释放,指针还未置空(NULL)

指针

void与void*的区别

定义
  • void:表示“无类型”,用于函数返回值或参数

     void func(void); // 不过一般简写为 void func();   无返回值无参数
  • void*:通用指针类型(万能指针),可指向任意数据类型,但需要强制类型转换后才能解引用

     void* ptr = malloc(4);// int* p = (int*)ptr;// *p = 10;​float* p1 = (float*)ptr; // 强制类型转换*p = 20;
注意事项
  • void*不能直接解引用(如:*ptr会报错)

  • 函数返回void*需要外部接收的时候明确类型

示例
 #include <stdlib.h>​/*** 定义一个返回值为void*类型的指针函数*/void* process_data(void* p){// 例如// 处理int类型时:return (int*)p;// 处理double类型时:return (double*)p;// 实际应用中需要配套数据类型表示参数return p; // 直接返回原指针}​int main(int argc,char*argv[]){// 演示int类型处理int m = 10;int* p_int = &m;// 必须进行显示类型的转换(保证类型安全)int* result_int = (int*)process_data(p_int);*result_int = 20; // 安全操作printf("Integer value:%d\n",*result_int);// 演示double类型处理double pi = 3.1415926;double* p_double = &pi;// 必须进行显示类型的转换(保证类型安全)double* result_double = (double*)process_data(p_double);*result_double *= 2; // 安全操作printf("Double value:%.6f\n",*result_double);// void*指针的特殊使用注意事项void* generic_ptr = process_data(p_int);// *generic_ptr = 30; // 错误! void* 不能直接解引用(必须明确类型)// 正确的写法int* c_ptr = (int*)generic_ptr;*c_ptr = 30;printf("Converted value:%d\n",*c_ptr);return 0;}

内存操作

我们对于内存操作需要依赖于string.h头文件中相关的函数完成

内存操作函数

内存填充
memset
  • 头文件:#include <string.h>

  • 函数原型:void* memset(void* s,int c,size_t n);

  • 函数功能:将内存卡s的前n个字节填充为c

  • 参数说明:

    • void* s:目标内存首地址

    • int c:填充值(以unsigned char形式处理(0~255))

    • size_t n:填充字节数(size_t无符号长整型)

  • 返回值:返回s的指针

  • 注意事项:

    • 常用于动态化初始化,c通常设置为0(清零)

    • 按字节填充,非整型初始化需要谨慎(如填充int数组时,0是安全的)

  • 示例:

     #include <stdlib.h>#include <string.h>​// 在堆区申请4个int的连续空间int* p = (int*)malloc(4 * sizeof(int)); // 建议写常量表达式// 非空校验(校验指针有效性)if(p == NULL){perror("内存申请失败!");return -1;}​// 初始化堆内存,填充0memset(p,0,4 * sizeof(int));​// 测试输出printf("%d\n",*(p+1)); //*p = *(p+0) = p[0]​// 内存使用完毕,需要释放free(p);​// 此时要对指针p置空p = NULL; ​
内存拷贝
memcpy/memmove
  • 头文件:#include <string.h>

  • 函数原型:

    • void* memcpy(void* dest, const void* src, size_t n):(源与目标内存无重叠时使用)

    • void* memmove(void* dest, const void* src, size_t n):(安全处理内存重叠)

  • 函数功能:将src的前n个字节拷贝到dest(从低位开始,因为指针指向从低到高)

  • 参数说明:

    • void* dest:目标内存首地址

    • const void* src:源内存首地址

    • size_t n:拷贝字节数

  • 返回值:返回dest的首地址

  • 注意事项:

    • memmove能正确处理内存重叠,推荐优先使用

    • 确保目标内存足够大,避免溢出

  • 示例:

     #include <string.h>​// 准备两个数组,用来作为源和目标int src[4] = {11,22,33,44};int dest[6] = {111,222,333,444,555,666};​// 进行拷贝memcpy(dest+1,src+1,2 * sizeof(int)); // 从src拷贝22,33到dest的222的位置memmove(dest+1,src+1,2 * sizeof(int)); // 从src拷贝22,33到dest的222的位置​printf("源数组:\n");register int i;for(i = 0; i < 4; i++){printf("%-6d",src[i]);}printf("\n");​printf("目标数组:\n");for(i = 0; i < 6; i++){printf("%-6d",dest[i]);}printf("\n");

课后思考:

什么是内存重叠?

进行内存操作时,源内存区域和目标内存区域存在部分或者完全重叠,如果不处理内存重叠,可能导致数据被意外覆盖,引发未定义行为。

内存比较
memcmp
  • 头文件:#include <string.h>

  • 函数原型:int memcmp(const void* s1, const void* s2, size_t n)

  • 函数功能:比较s1s2的前n个字节

  • 返回值:

    • 0:内存内容相同

    • >0s1中第一个不同字节大于s2

    • <0s1中第一个不同字节小于s2

  • 注意事项:比较按字节进行,非字符串需确保参与比较的字节数一致(总字节数一致)(不一致按小的来超出不比较)

  • 示例:

    #include <stdlib.h>
    #include <string.h>// 准备比较的数据
    int* arr1 = (int*)malloc(3 * sizeof(int));
    int* arr2 = (int*)calloc(4,sizeof(int));// 清零
    memset(arr1,0,3 * sizeof(int));// 赋值
    arr1[0] = 65; arr1[1] = 66;
    arr2[0] = 70; arr2[1] = 5;// 比较
    int cmp_result = memcmp(arr2,arr1, 2 * sizeof(int)); // 双方比较字节数完全一致printf("比较结果:%d\n",cmp_result); // 5  70-65// 内存使用完毕,释放内存
    free(arr1);
    free(arr2);// 如果后面要用到,返回到外面,需要置空;不用的话就不需要置空
    arr1 = NULL;
    arr2 = NULL;
内存查找
memchr/memrchr
  • 头文件:#include <string.h>

  • 函数原型:

    • void* memchr(const void* s, int c, size_t n):(正向查找)

    • void* memrchr(const void* s, int c, size_t n):(逆向查找,这个不是C语言标准库提供,属于GNU扩展)

  • 函数功能:在s的前n个字节中查找字符c

  • 返回值:

    • 成功:返回指针

    • 失败:返回NULL

  • 注意事项:

    • memrchr:是GNU扩展函数,需手动声明

    • 查找单位为字节值,非整型数据需要注意内存布局

  • 示例:

    #include <string.h>// memrchr是GNU扩展函数,需要外部声明
    extern void* memrchr(const void* s, int c, size_t n);int main(int argc, char*argv[])
    {char str[] = {'A','B','C','B'};// 查找字符'B'(ASCII 66)char* first = (char*)memchr(str, 'B', sizeof(str)); char* last = (char*)memrchr(str, 'B', sizeof(str));printf("first=%p,last=%p\n",first,last);printf("第1个B的位置:%ld\n",first - str); // 1printf("最后1个B的位置:%ld\n",last - str); // 3return 0;
    }

综合案例:学生成绩管理系统

  • 需求:

    要求实现一个基于指针的学生成绩管理系统,具体功能如下:

    1. 添加学生信息:输入学号和三门成绩,存储到数组中

    2. 显示所有学生信息:遍历数组,输出每个学生的学号和成绩

    3. 计算每个学生的平均分和总分:遍历数组,计算每行的总分和平均分

    4. 根据某科成绩排序:用户选择科目,然后按该科成绩排序,可以升序或降序

    5. 查找学生信息:按学号查找,显示该生的成绩和平均分

    6. 退出程序。

  • 代码:

    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>#define MAX_STUDENTS 50  // 最大学生数量
    #define COURSE_NUM 3     // 课程科目数量
    #define ID_LENGTH 4      // 学号长度/* 函数原型声明 */
    void addStudent(int (*scores)[COURSE_NUM], char (*ids)[ID_LENGTH], int *count);
    void displayAll(int (*scores)[COURSE_NUM], char (*ids)[ID_LENGTH], int count);
    void showStatistics(int (*scores)[COURSE_NUM], int count);
    void sortStudents(int (*scores)[COURSE_NUM], char (*ids)[ID_LENGTH], int count);
    void searchStudent(int (*scores)[COURSE_NUM], char (*ids)[ID_LENGTH], int count);
    int validateId(char *id);int main(int argc, char *argv[])
    {int choice;            // 用户菜单选择int studentCount = 0;  // 当前学生数量// 学生数据存储(二维数组)char studentIds[MAX_STUDENTS][ID_LENGTH];  // 学号数组int scores[MAX_STUDENTS][COURSE_NUM];      // 成绩二维数组do{// 系统菜单界面printf("\033[1;32m+----------------------------+\033[0m\n"); // 绿色边框printf("\033[1;32m| \033[1;33m学生成绩管理系统 v2.0\033[1;32m |\033[0m\n");printf("\033[1;32m| \033[1;33m作者:momo \033[1;32m |\033[0m\n");printf("\033[1;32m+----------------------------+\033[0m\n");printf("\033[1;32m1. 添加学生信息\033[0m\n");printf("\033[1;32m2. 显示所有记录\033[0m\n");printf("\033[1;32m3. 查看统计信息\033[0m\n");printf("\033[1;32m4. 成绩排序\033[0m\n");printf("\033[1;32m5. 查找学生\033[0m\n");printf("\033[1;32m6. 退出系统\033[0m\n");printf("\n请输入您的选择:");scanf("%d",&choice);switch(choice){case 1: // 添加学生信息addStudent(scores, studentIds, &studentCount);break;case 2: // 显示所有记录displayAll(scores, studentIds, studentCount);break;case 3: // 查看统计信息showStatistics(scores, studentCount);break;case 4: // 成绩排序sortStudents(scores, studentIds, studentCount);break;case 5: // 查找学生searchStudent(scores, studentIds, studentCount);break;case 6: // 退出系统printf("系统已退出,感谢使用!\n");break;default: printf("无效输入,请重新选择!");}}while(choice != 6);return 0;
    }/*** 添加学生信息* @param scores  学生成绩二维数组* @param ids     学生编号二维数组* @param count   当前学生数量*/
    void addStudent(int (*scores)[COURSE_NUM], char (*ids)[ID_LENGTH], int *count)
    {// 校验存储空间是否已满if(*count >= MAX_STUDENTS){printf("错误:存储空间已满!\n");return;}printf("\n--- 添加学生信息 ---\n");// 创建一个数组,用来存放学生学号char tempId[ID_LENGTH + 1]; // 控制台录入的字符串默认\0结尾// 学号验证do{printf("请输入4位学号:");scanf("%4s",tempId);// 清除输入缓冲区while(getchar() != '\n');}while(!validateId(tempId));// 检查学号是否已存在register int i;for(i = 0; i < *count; i++){if(memcmp(ids[i],tempId,ID_LENGTH) == 0){printf("错误:该学号已存在!\n");return;}}// 存储学号memcpy(ids[*count], tempId, ID_LENGTH);// 输入成绩printf("请输入%d门课程成绩(0~100):\n",COURSE_NUM);for(i = 0; i < COURSE_NUM;){printf("课程%d:", i+1);// 非法字符校验int tempScore = scanf("%d",&scores[*count][i]);if(tempScore != 1){printf("错误:成绩无效,请重新输入!\n");// 清空缓冲区while(getchar() != '\n');continue;}// 输入范围校验if(scores[*count][i] < 0 || scores[*count][i] > 100){printf("错误:成绩无效,请重新输入!\n");continue;}i++;}// 改变studentCount的值(*count)++;printf("学生信息添加成功!\n");
    }/*** 显示所有记录* @param scores 学生成绩二维数组* @param ids    学生学号二维数组* @param count  已录入学生人数*/
    void displayAll(int (*scores)[COURSE_NUM], char (*ids)[ID_LENGTH], int count)
    {printf("\n--- 学生成绩列表 ---\n");// 校验是否存在数据if(count == 0){printf("暂无学生数据!\n");return;}// 表格-表头printf("%-8s %-6s %-6s %-6s\n","学号","语文","数学","英语");// 表格-数据for(int i = 0; i < count; i++){printf("%-8.4s",ids[i]); // 学号// 成绩for(int j = 0; j < COURSE_NUM; j++){printf("%-6d",*(*(scores + i) + j)); // scores[i][j]}printf("\n");}printf("\n");
    }/*** 显示统计信息* @param scores 成绩二维数组* @param count  已录入学生数量*/
    void showStatistics(int (*scores)[COURSE_NUM], int count)
    {// 校验是否存在学生if(count == 0){printf("暂无学生数据!\n");return;}//创建一个数组,用来存储每一科总分int courseTotal[COURSE_NUM] = {0};// 创建一个数组,用来存储每一科最高分int max[COURSE_NUM] = {0};// 创建一个数组,用来存储每一科最低分int min[COURSE_NUM] = {100,100,100};// 遍历成绩,计算每一科的总分,最高分,最低分for(int i = 0; i < count; i++){for(int j = 0; j < COURSE_NUM; j++){// 获取成绩int score = scores[i][j];// 单科总分courseTotal[j] += score;// 单科最高分if(score > max[i]) max[j] = score;// 单科最低分if(score < min[j]) min[j] = score;}}// 输出信息printf("\n--- 课程统计信息 ---\n");char *courses[] = {"语文","数学","英语"};for(int i = 0; i < COURSE_NUM; i++){printf("%s:\n",courses[i]); // 科目printf("  平均分:%.2f\n",(float)courseTotal[i] / count);printf("  最高分:%d\n",max[i]);printf("  最低分:%d\n",min[i]);}
    }/*** 成绩排序* @param scores 学生成绩二维数组* @param ids    学生学号二维数组* @param count  已录入学生人数*/
    void sortStudents(int (*scores)[COURSE_NUM], char (*ids)[ID_LENGTH], int count) 
    {if(count < 2) {printf("需要至少2条记录才能排序!\n");return;}int course;printf("\n请选择排序科目(1-语文 2-数学 3-英语): ");scanf("%d", &course);if(course < 1 || course > 3) {printf("无效的科目选择!\n");return;}course--; // 转换为数组索引// 使用改进的冒泡排序for(int i = 0; i < count-1; i++) {int swapped = 0;for(int j = 0; j < count-1-i; j++) {if(scores[j][course] < scores[j+1][course]) { // 降序排列// 交换学号char tempId[ID_LENGTH];memcpy(tempId, ids[j], ID_LENGTH);memcpy(ids[j], ids[j+1], ID_LENGTH);memcpy(ids[j+1], tempId, ID_LENGTH);// 交换成绩int tempScores[COURSE_NUM];memcpy(tempScores, scores[j], sizeof(tempScores));memcpy(scores[j], scores[j+1], sizeof(scores[j][0]) * COURSE_NUM);memcpy(scores[j+1], tempScores, sizeof(tempScores));swapped = 1;}}if(!swapped) break;}printf("排序完成!\n");
    }/*** 学生查找* @param scores 学生成绩二维数组* @param ids 学生学号二维数组* @param count 已添加学生数量*/
    void searchStudent(int (*scores)[COURSE_NUM], char (*ids)[ID_LENGTH], int count) 
    {char targetId[ID_LENGTH + 1];printf("\n请输入要查找的学号: ");scanf("%4s", targetId);while (getchar() != '\n'); // 清除输入缓冲区for(int i = 0; i < count; i++) {if(memcmp(ids[i], targetId, ID_LENGTH) == 0) {printf("找到学生记录:\n");printf("学号: %.4s\n", ids[i]);printf("成绩: 语文=%d 数学=%d 英语=%d\n",scores[i][0], scores[i][1], scores[i][2]);return;}}printf("未找到该学号的学生记录!\n");
    }/*** 学号校验* @param id  校验的学号(数组)* @return 1-校验合格,0-校验不合格*/
    int validateId(char *id)
    {char *p = id; // 不要直接操作形参,最好使用局部变量接收int len = 0;// 遍历字符串while(*p && len < ID_LENGTH){// 校验输入的是否是数字if(!(*p >= '0' && *p <= '9')){printf("学号必须为数字!\n");return 0;}p++;len++;}// 校验输入的长度if(len != ID_LENGTH || *p != '\0'){printf("学号必须为4位!\n");return 0;}return 1;
    }

http://www.dtcms.com/wzjs/189614.html

相关文章:

  • 购物网站建设情况汇报广州seo网络优化公司
  • 陕西建设技师学院网站今日热点新闻事件摘抄2022
  • 网站制作公司下外贸网站搭建推广
  • 网站建设 工商注册电视剧排行榜
  • 公司做推广高级seo招聘
  • 动态网站浏览界面会计培训
  • 二手表网站推广产品的方式有哪些
  • 软件开发的一般流程南京seo网络推广
  • 凡科投票优化网络
  • 官方网站建设情况说明广告网页
  • 网站不备案会怎么样公司注册流程
  • 网页搜索的快捷键佛山百度提升优化
  • 高校网站开发百度灰色关键词排名代做
  • 韩国做游戏的电影 迅雷下载网站佛山网站建设公司
  • 哪个网站做加盟百度权重3的网站值多少
  • 衡水做网站推广东营百度推广电话
  • 建设银行网站查询密码是什么西地那非片
  • 做政府网站多少钱网络营销策划目的
  • 装修设计公司网站排名百度广告投放电话
  • 知名的设计网站百度客户服务中心
  • 网址备案查询郑州seo多少钱
  • 建设网站的五个步骤是百度seo排名360
  • dede怎么做网站友情链接的作用大不大
  • 河南做网站的公司百度一下你就知道首页
  • 网站用哪些系统做的软文撰写案例
  • 单产品网站建设北京关键词排名推广
  • 网站上推广游戏怎么做的网站建设的基本
  • 疯狗做网站cnfg短视频营销推广
  • 手机站网站建设站长统计app网站
  • 高唐住房建设局网站江苏seo平台