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
",*(char *)pv);//A   在使用空指针时,需要将空指针转换为具体的类型
    printf("*pc = %c
",*pc);//4  高位到低位输出字符串
    printf("*pc = %c
",*(pc+1));//3
    printf("*pc = %c
",*(pc+2));//2
    printf("*pc = %c
",*(pc+3));//1
    getchar();
    return 0;
}

   空指针的使用

       1. 函数形式参数的类型

/*
 * 空指针的使用
 */

#include <stdio.h>
//可以对任意类型的变量进行输出
void myprint( void *pv,int type)
{
    if(type == 1)
    {
        printf("*pv = %d
",*(int *)pv);
    }
    if(type == 2)
    {
        printf("*pv = %c
",*(char *)pv);
    }
    if(type == 3)
    {
        printf("*pv = %lf
",*(double *)pv);
    }

}
int main(){

    int i = 20;
    char c = 'C';
    double d = 3.14;
#if 0
    printf("i = %d
",i);
    printf("c = %c
",c);
    printf("d = %lf
",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
",&add); //??
    printf("main 函数的地址:%p
",&main); //??
    getchar();
}

  add 函数的地址:00007FF7535B1000
main 函数的地址:00007FF7535B1010

     1. 函数都是有地址,函数名即代表内存地址

#include <stdio.h>
int add(int a,int b){
    return a+b;
}
int main(){
    printf("add 函数的地址:%p
",add); //??
    printf("main 函数的地址:%p
",main); //??
    getchar();
}

  add 函数的地址:00007FF615181000
main 函数的地址:00007FF615181010

    int (*fptr)(int,int); //声明了一个函数指针变量
                               //指针变量名 fptr,该函数指针 返回一个int  传入 两个int的类型
#include <stdio.h>
int add(int a,int b){
    return a+b;
}
int (*fptr)(int,int);
int main(){
    fptr = add; //将函数add 的地址 赋值给函数指针变量
    printf("*fptr = %p
",*fptr);
    printf("add 函数的地址:%p
",add); //??
    printf("main 函数的地址:%p
",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
",add(4,6));
    printf("*fptr间接调用返回 = %d
",(*fptr)(4,6)); //间接调用add
    getchar();
}

     3. 声明函数指针类型

 //声明函数指针 类型
    //int * pa;  //声明了一个int * 变量pa
    //typedef int * pa; //声明了一个 int * 类型的别名 pa
    //pa p1,p2,p3; //声明了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
",fp1(4,6)); //间接调用add
    getchar();
    return 0;
}
函数fp1调用返回 = 10
/*
 * 函数指针
 *   编写  剩下的三个函数
 *        int sub(int a,int b);
 *        int mul(int a,int b);
 *        int div(int a,int b);
 *
 *        将函数地址赋值给下面的函数指针变量,
 *        通过函数指针变量退函数进行调用
 *
    pfunc fp1,fp2,fp3,fp4; //用fptr 类型声明多个函数指针变量
 */
#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
",fp1(4,6)); //间接调用add
    printf("函数fp2调用返回 = %d
",fp2(4,6)); //间接调用add
    printf("函数fp3调用返回 = %d
",fp3(4,6)); //间接调用add
    printf("函数fp4调用返回 = %d
",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
",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
",c); //??
    printf("add 函数的地址:%p
",add); //??
    printf("运算的结果 = %d
",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
",compute(30,20,'*'));
    printf("运算的结果 = %d
",compute(30,20,'-'));
    printf("运算的结果 = %d
",compute(30,20,'+'));
    printf("运算的结果 = %d
",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
",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
",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
",*pi);
    free(pi);
    pi = NULL; //pi原来指向的内存已经被free,pi赋值为NULL
    getchar();
    return 0;
}
/*
 * 申请动态内存并使用 释放
 * [练习]
 *     1. 申请其他基本类型 动态内存,并使用, 使用后注意释放
 *     2. 申请一个Student类型的动态内存,并使用.注意释放
 */
#include <stdio.h>
#include <stdlib.h>

int main(){
    float *pi = NULL;
    pi = (float *)malloc(4);
    *pi = 200.2;
    printf("*pi = %.2f
",*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
",pi->name);
    printf("score= %d
",pi->score);
    printf("age  = %d
",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
",pi->name);
    printf("score= %d
",pi->score);
    printf("age  = %d
",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
",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
",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
",ctime(&timer));
    pt = localtime(&timer); //可以定制显示日历信息
    printf("今天%d号,%d月,%d年
",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
",ctime(&timer));
    pt = localtime(&timer); //可以定制显示日历信息
    printf("今天%d号,%d月,%d年
",pt->tm_mday,pt->tm_mon+1,pt->tm_year+1900);
    printf("asctime = %s
",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年
",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
",sec);
    printf("ctime = %s
",ctime(&sec)); //输出固定格式日历字符串

    pt = localtime(&sec); //可以定制显示日历信息
    printf("今天%d号,%d月,%d年
",pt->tm_mday,pt->tm_mon+1,pt->tm_year+1900);
    //打印时分秒

    printf("asctime = %s
",asctime(pt)); //跟ctime 效果一样

    return 0;
}
何所为,不仅仅是一种态度,更是一种艺术!
原文地址:https://www.cnblogs.com/tanzizheng/p/12924330.html