014_stdc_C语言
回顾: enum 枚举 union 联合(共用) 请谈一谈 结构体和联合的区别 指针高级 二级指针 修改函数外面 指针变量 字符串数组 操作
------------------------------
void * 空指针 没有类型的指针
任何类型的指针可以赋值给空指针,无需类型转换
在使用空指针时,需要将空指针转换为具体的类型
#include <stdio.h> int main(){ void *pv = NULL; //空指针 char c = 'A'; int i= 0x31323334; //1234 char *pc=NULL; pc= &c; pc= (char *)&i; pv = &c;// printf("*pv = %c\n",*(char *)pv);//A 在使用空指针时,需要将空指针转换为具体的类型 printf("*pc = %c\n",*pc);//4 高位到低位输出字符串 printf("*pc = %c\n",*(pc+1));//3 printf("*pc = %c\n",*(pc+2));//2 printf("*pc = %c\n",*(pc+3));//1 getchar(); return 0; }
空指针的使用
1. 函数形式参数的类型
/* * 空指针的使用 */ #include <stdio.h> //可以对任意类型的变量进行输出 void myprint( void *pv,int type) { if(type == 1) { printf("*pv = %d\n",*(int *)pv); } if(type == 2) { printf("*pv = %c\n",*(char *)pv); } if(type == 3) { printf("*pv = %lf\n",*(double *)pv); } } int main(){ int i = 20; char c = 'C'; double d = 3.14; #if 0 printf("i = %d\n",i); printf("c = %c\n",c); printf("d = %lf\n",d); #endif myprint(&i,1); myprint(&c,2); myprint(&d,3); getchar(); return 0; }
2. 动态内存申请到的内存,返回指向该内存区域的void * 指针
函数指针
#include <stdio.h> int add(int a,int b){ return a+b; } int main(){ printf("add 函数的地址:%p\n",&add); //?? printf("main 函数的地址:%p\n",&main); //?? getchar(); }
add 函数的地址:00007FF7535B1000
main 函数的地址:00007FF7535B1010
1. 函数都是有地址,函数名即代表内存地址
#include <stdio.h> int add(int a,int b){ return a+b; } int main(){ printf("add 函数的地址:%p\n",add); //?? printf("main 函数的地址:%p\n",main); //?? getchar(); }
add 函数的地址:00007FF615181000
main 函数的地址:00007FF615181010
#include <stdio.h> int add(int a,int b){ return a+b; } int (*fptr)(int,int); int main(){ fptr = add; //将函数add 的地址 赋值给函数指针变量 printf("*fptr = %p\n",*fptr); printf("add 函数的地址:%p\n",add); //?? printf("main 函数的地址:%p\n",main); //?? getchar(); } *fptr = 00007FF67D581000 add 函数的地址:00007FF67D581000 main 函数的地址:00007FF67D581010
2. 能否声明一个变量保存函数的地址,保存函数的地址的变量就是函数指针变量,即函数指针
//通过 函数指针变量 调用函数
#include <stdio.h> int add(int a,int b){ return a+b; } int (*fptr)(int,int); int main(){ fptr = add; //将函数add 的地址 赋值给函数指针变量 //通过 函数指针变量 调用函数 printf("函数add调用返回 = %d\n",add(4,6)); printf("*fptr间接调用返回 = %d\n",(*fptr)(4,6)); //间接调用add getchar(); }
3. 声明函数指针类型
typedef int (*pfunc)(int,int); //声明一个函数指针的类型pfunc
pfunc fp1,fp2,fp3,fp4; //用fptr 类型声明多个函数指针变量
#include <stdio.h> int add(int a,int b){ return a+b; } int (*fptr)(int,int); int main(){ fptr = add; //将函数add 的地址 赋值给函数指针变量 typedef int (*pfunc)(int,int); //声明一个函数指针的类型pfunc pfunc fp1,fp2,fp3,fp4; //用fptr 类型声明多个函数指针变量 fp1 = add; printf("函数fp1调用返回 = %d\n",fp1(4,6)); //间接调用add getchar(); return 0; } 函数fp1调用返回 = 10
#include <stdio.h> int add(int a,int b); int sub(int a,int b); int mul(int a,int b); int div(int a,int b); int add(int a,int b){ return a+b; } int sub(int a,int b){ return a-b; } int mul(int a,int b){ return a*b; } int div(int a,int b){ return a/b; } int (*fptr)(int,int); int main(){ typedef int (*pfunc)(int,int); //声明一个函数指针的类型pfunc pfunc fp1,fp2,fp3,fp4; //用fptr 类型声明多个函数指针变量 fp1 = add; fp2 = sub; fp3 = mul; fp4 = div; printf("函数fp1调用返回 = %d\n",fp1(4,6)); //间接调用add printf("函数fp2调用返回 = %d\n",fp2(4,6)); //间接调用add printf("函数fp3调用返回 = %d\n",fp3(4,6)); //间接调用add printf("函数fp4调用返回 = %d\n",fp4(4,6)); //间接调用add getchar(); return 0; } 函数fp1调用返回 = 10 函数fp2调用返回 = -2 函数fp3调用返回 = 24 函数fp4调用返回 = 0
4. 函数指针变量的使用 1. 函数指针变量作为 其他函数的参数 回调函数 2. 作为函数的返回值
#include <stdio.h> int add(int a,int b){ return a+b; } typedef int (*pfunc)(int,int); //声明了一个pfunc 的函数指针类型 //传入的第三参数是函数指针类型 int compute(int a,int b,pfunc opr); int compute(int a,int b,pfunc opr) { return opr(a,b); } int main(){ int a = 20; int b = 30; int c = 0; c = compute(a,b,add);//第三个参数是个回调函数 printf("add c = %d\n",c); getchar(); return 0; } add c = 50
pfunc select(char opr) { if(opr == '+') return add; } typedef int (*pfunc)(int,int); //声明了一个pfunc 的函数指针类型 pfunc c; //定义变量名称为c的指针类型 c = select('+');//保存函数add的地址,而不是select的地址
函数指针作为 函数的返回值
#include <stdio.h> int add(int a,int b){ return a+b; } typedef int (*pfunc)(int,int); //声明了一个pfunc 的函数指针类型 pfunc select(char opr); pfunc select(char opr) { if(opr == '+') return add; } int main(){ int a = 20; int b = 30; pfunc c; //定义变量名称为c的指针类型 c = select('+');//保存函数add的地址 printf("c的地址:%p\n",c); //?? printf("add 函数的地址:%p\n",add); //?? printf("运算的结果 = %d\n",c(a,b));//add(a,b) getchar(); return 0; } c的地址:00007FF6BE0E1000 add 函数的地址:00007FF6BE0E1000 运算的结果 = 50
/* * 函数指针作为 函数的返回值 */ #include <stdio.h> int add(int a,int b){ return a+b; } int sub(int a,int b){ return a-b; } int mul(int a,int b){ return a*b; } int div(int a,int b){ return a/b; } typedef int (*pfunc)(int a,int b); pfunc select(char opr); pfunc select(char opr) { if(opr == '+') return add; if(opr == '-') return sub; if(opr == '*') return mul; if(opr == '/') return div; } int compute(int a,int b,char opr); int compute(int a,int b,char opr) { pfunc pf1; pf1 = select(opr); return pf1(a,b); } int main(){ printf("运算的结果 = %d\n",compute(30,20,'*')); printf("运算的结果 = %d\n",compute(30,20,'-')); printf("运算的结果 = %d\n",compute(30,20,'+')); printf("运算的结果 = %d\n",compute(30,20,'/')); getchar(); return 0; }
#include <stdio.h> int add(int a,int b){ return a+b; } int sub(int a,int b){ return a-b; } int mul(int a,int b){ return a*b; } int div(int a,int b){ return a/b; } typedef int (*pfunc)(int a,int b); pfunc pf_arry[127]; void initArry() { pf_arry['+'] = add; pf_arry['-'] = sub; pf_arry['*'] = mul; pf_arry['/'] = div; } int compute(int a,int b,char opr) { pfunc pf1 = pf_arry[opr]; return pf1(a,b); } int main(){ //要初始化数组 initArry(); printf("运算的结果=%d\n",compute(12,23,'+')); getchar(); return 0; }
运算的结果=35
//在main函数中 添加代码 可以实现 输入一个表达式
//输出该表达式的结果
#include <stdio.h> int add(int a,int b){ return a+b; } int sub(int a,int b){ return a-b; } int mul(int a,int b){ return a*b; } int div(int a,int b){ return a/b; } typedef int (*pfunc)(int a,int b); pfunc pf_arry[127]; void initArry() { pf_arry['+'] = add; pf_arry['-'] = sub; pf_arry['*'] = mul; pf_arry['/'] = div; } int compute(int a,int b,char opr) { pfunc pf1 = pf_arry[opr]; return pf1(a,b); } int main(){ //要初始化数组 int as=12,bs=21; char cs='+'; printf("请输入一个表达式:"); scanf("%d%c%d",&as,&cs,&bs); initArry(); //在main函数中 添加代码 可以实现 输入一个表达式 //输出该表达式的结果 printf("运算的结果=%d\n",compute(as,bs,cs)); getchar(); getchar(); return 0; }
请输入一个表达式:5+8
运算的结果=13
标准函数库
函数库 有很多函数组成
printf();
scanf();
time();
rand();
srand();
strlen();
strcmp();
strcpy();
atoi();
abs();
内存管理库函数
动态内存分配函数
在程序运行中,根据需要临时分配一块内存,就是动态内存分配.
要申请的内存空间需要程序员手动(显式调用函数)申请,手动释放
void *malloc(size_t size);
可以向系统动态申请连续内存,#include <stdlib.h>
唯一参数 申请内存的字节数
如果申请成功返回 申请内存的首地址,申请不成功返i回NULL.
返回值的类型: void * 空指针 没有类型的指针
如果要使用该内存地址 需要将空指针 转换为有类型的指针
int *p =(int *) malloc(4); //申请了4个字节,
*p = 200;//将200 写到 malloc 分配的内存中
void free(void *ptr); 释放动态申请到的内存,参数为要释放内存的首地址 释放的内存是一个整体
#include <stdio.h> #include <stdlib.h> int main(){ int *pi = NULL; pi = (int *)malloc(4); *pi = 200; printf("*pi = %d\n",*pi); free(pi); pi = NULL; //pi原来指向的内存已经被free,pi赋值为NULL getchar(); return 0; }
#include <stdio.h> #include <stdlib.h> int main(){ float *pi = NULL; pi = (float *)malloc(4); *pi = 200.2; printf("*pi = %.2f\n",*pi); free(pi); pi = NULL; //pi原来指向的内存已经被free,pi赋值为NULL getchar(); return 0; }
#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct { char name[20]; int score; int age; }Student; int main(){ Student *pi = NULL; pi = (Student *)malloc(sizeof(Student)); strcpy(pi->name,"如花"); pi->score = 30; pi->age = 18; printf("name = %s\n",pi->name); printf("score= %d\n",pi->score); printf("age = %d\n",pi->age); free(pi); pi = NULL; //pi原来指向的内存已经被free,pi赋值为NULL getchar(); return 0; }
把功能放在函数
#include <stdio.h> #include <stdlib.h> #include <string.h> typedef struct { char name[20]; int score; int age; }Student; Student *input(){//返回一个结构体类型指针的函数 Student *pi = NULL; pi = (Student *)malloc(sizeof(Student)); strcpy(pi->name,"如花"); pi->score = 30; pi->age = 18; return pi;//返回一个结构体类型指针 } void output(Student* pi){ printf("name = %s\n",pi->name); printf("score= %d\n",pi->score); printf("age = %d\n",pi->age); } int main(){ Student *ps = NULL; ps=input(); output(ps); free(ps); ps = NULL; //pi原来指向的内存已经被free,pi赋值为NULL getchar(); return 0; }
calloc
void *calloc(size_t nmemb, size_t size);
calloc 对动态分配的内存 清0
第一个参数 要分配多少个存储单元
第二个参数 每一单元的字节数是多少
malloc(10*sizeof(Student)); //分配10个学员结构体的空间
calloc(10,sizeof(Student)); //分配10个学员结构体的空间
void *realloc(void *ptr, size_t size);
如果malloc 分配的空间 不够,可以通过realloc 在原来的内存基础上 往后继续分配
第一个参数,是前面malloc 分配的首地址,需要重新分配的大小
int *p = (int *)malloc(10);
p = (int *)realloc(p,20); //在原来地址的基础上 分配20字节
calloc realloc 调用 也需要free
time(0); //返回 从1970.1.1 0:0:0 到现在的秒数
time_t time(time_t *tloc);
也可以通过传入一个time_t(unsigned int *)指针,带回秒数
#include <stdio.h> #include <time.h> int main(){ unsigned int sec =0; sec = time(0); printf("%u\n",sec); getchar(); return 0; }
char *ctime(const time_t *timep);
对输入的秒数 转换为日历字符串进行输出
#include <time.h> #include <stdio.h> int main() { time_t timer; timer=time(NULL); printf("%s\n",ctime(&timer)); getchar(); return 0; } Wed May 20 15:58:39 2020
pt = localtime(&timer); //可以定制显示日历信息
#include <time.h> #include <stdio.h> int main() { time_t timer; timer=time(NULL); struct tm * pt = NULL; printf("%s\n",ctime(&timer)); pt = localtime(&timer); //可以定制显示日历信息 printf("今天%d号,%d月,%d年\n",pt->tm_mday,pt->tm_mon+1,pt->tm_year+1900); getchar(); return 0; } Wed May 20 16:04:07 2020 今天20号,5月,2020年
char *asctime(const struct tm *tm);
对传入的结构体指针 转换输出日历字符串 跟ctime相同
#include <time.h> #include <stdio.h> int main() { time_t timer; timer=time(NULL); struct tm * pt = NULL; printf("%s\n",ctime(&timer)); pt = localtime(&timer); //可以定制显示日历信息 printf("今天%d号,%d月,%d年\n",pt->tm_mday,pt->tm_mon+1,pt->tm_year+1900); printf("asctime = %s\n",asctime(pt)); //跟ctime 效果一样 getchar(); return 0; } Wed May 20 16:07:07 2020 今天20号,5月,2020年 asctime = Wed May 20 16:07:07 2020
打印时分秒
printf("秒%d,分%d,时%d,今天%d号,%d月,%d年\n",pt->tm_sec,pt->tm_min,pt->tm_hour, pt->tm_mday,pt->tm_mon+1,pt->tm_year+1900); 秒23,分14,时16,今天20号,5月,2020年
struct tm *gmtime(const time_t *timep);
格林威治 时间
而Linux系统下
/* * 时间函数 */ #include <stdio.h> #include <time.h> // typedef long int time_t int main(){ long int sec = 0; struct tm * pt = NULL; //sec = time(0); time(&sec); printf("sec = %ld\n",sec); printf("ctime = %s\n",ctime(&sec)); //输出固定格式日历字符串 pt = localtime(&sec); //可以定制显示日历信息 printf("今天%d号,%d月,%d年\n",pt->tm_mday,pt->tm_mon+1,pt->tm_year+1900); //打印时分秒 printf("asctime = %s\n",asctime(pt)); //跟ctime 效果一样 return 0; }