013_stdc_C语言

回顾:

    c的数据类型:
          基本数据类型
               整型
                  char short int long
               浮点
                  float double
          扩展数据类型
               数组
               指针
               自定义数据类型
                   结构体(构造体)
                   枚举

                   联合
          void 空类型

  结构体的作用
        将其他多个类型,组合起来构造一个新的类型

  结构体的定义
  struct student {   //定义结构体类型 student
        char name[8];
        int score;
        ......
  };
 
typedef

  struct student  s; //定义了一个结构体变量

  s.name  通过.(分量运算) 访问结构体里地 name成员
  .....

  结构体指针
  struct student *ps;  
  ps = &s;

  ps->name  通过->(指向运算) 访问结构体成员


  结构体的使用
       结构体作为函数的参数
       跟基本数据类型变量一样,传递的是结构体的值,而不是引用(地址) ,跟数组(指针)不一样


       结构体作为函数的返回值
       作为返回值,跟基本类型变量一样,返回的是结构体整体的值,而不是指针


  结构体的对齐和补齐
              

  结构体的数组
--------------------
/*
 * 结构体数组
 */
#include <stdio.h>

int main(){

typedef struct {
        char name[8]; 
        int score;
        int age;
    }Student;

    Student s;
    Student as[20];

    printf("sizeof(s) = %d
",sizeof(s)); //16

    printf("&as[4] = %p
",&as[4]);
    printf("&as[5] = %p
",&as[5]);


    return 0;
}

//16
//16 每个元素占用16个字节
//16

/*
 * 结构体 里的成员是结构体
 */
#include <stdio.h>

int main(){
    struct Score{
        int stdc;
        int unixc;
        int cpp;
        char qt;
    };
    typedef struct {
        char name[8];
        struct Score score;//定义一个结构体类型
        int age;
    }Student;
    Student s;
    s.score.stdc = 90;
    s.score.unixc = 92;
    s.score.cpp = 93;

    printf("stdc = %d
",s.score.stdc);
    printf("unixc = %d
",s.score.unixc);
    printf("cpp = %d
",s.score.cpp);
    getchar();
}
        //struct student s;  //结构体里不能放该结构体的变量,
        struct student* s; //可以是该结构体类型的指针
typedef struct student{
        char name[8]; 
        struct Score score;
        //struct student s;  //结构体里不能放该结构体的变量,
        struct student* s; //可以是该结构体类型的指针
        int age;
    }Student;

自定义数据类型  --枚举

char c; c的取值集合(-128 ~ 127)
unsigned char uc ;uc的取值集合(0 ~ 255)

 通过 enum 可以设定一个 取值集合范围 的类型,枚举

SEASON{Spring,Summer,Autumn,Winter} //SEASON只能是中括号里面的值

#include <stdio.h>

int main(){
    enum SEASON{Spring,Summer,Autumn,Winter};
    enum SEASON s; //定义一个枚举变量s
    s = Summer;
    if(Summer == s)
    {
        printf("现在是夏天
"); 
    }
    getchar();
}
//现在是夏天
#include <stdio.h>

int main(){
    enum SEASON{Spring,Summer,Autumn,Winter};
    enum SEASON s; //定义一个枚举变量s
    printf("Spring = %d
",Spring);
    printf("Summer = %d
",Summer);
    printf("Autumn = %d
",Autumn);
    printf("Winter = %d
",Winter);
    getchar();
}
Spring = 0
Summer = 1
Autumn = 2
Winter = 3

定下标

#include <stdio.h>

int main(){
    enum SEASON{Spring =6,Summer,Autumn=10,Winter};
    enum SEASON s; //定义一个枚举变量s
    printf("Spring = %d
",Spring);
    printf("Summer = %d
",Summer);
    printf("Autumn = %d
",Autumn);
    printf("Winter = %d
",Winter);
    getchar();
}
Spring = 6
Summer = 7
Autumn = 10
Winter = 11

/*
* 输入数字 1 - 7
* 输出 对应的星期几调休
*/

#include <stdio.h>
enum WEEK {MON = 1,TUE,WED,THU,FRI,SAT,SUN};

int main(){

    //int num = 0;
    enum WEEK  num;
    //输入数字
    printf("输入调休的数字:");
    scanf("%d",(int *)&num);

    switch(num)
    {
        case MON:
            printf("周一休息
");    
            break;

        case TUE:
            printf("周二休息
");    
            break;

        case WED:
            printf("周三休息
");    
            break;

        case THU:
            printf("周四休息
");    
            break;

        case FRI:
            printf("周五休息
");    
            break;

        case SAT:
            printf("周六休息
");    
            break;

        case SUN:
            printf("周日休息
");    
            break;

        default:
            printf("你输入的数字不对
");
            break;
    }
    getchar();
    getchar();
    return 0;
}

联合体(共用体)  union

typedef union Score { //定义了一个联合类型 Score
        char level;
        int  i_score;
        double d_score; //8
    };
    Score s;
    printf("sizeof(s) = %d
",sizeof(s)); //8  即double类型的大小
    getchar();

联合体会找到所有成员中最大的那一个类型做为当前联合体体的占用空间

#include <stdio.h>
int main(){

    typedef union Score { //定义了一个联合类型 Score
        char level;
        int  i_score;
        double d_score;
    };
    Score s;
    s.level = 'A'; // 或者
    printf("当前成绩是%c
",s.level);
    printf("&s.level = %p
",&s.level);

    s.i_score = 80;
    printf("当前成绩是%d
",s.i_score);
    printf("&s.i_score = %p
",&s.i_score);

    s.d_score = 80.8;
    printf("当前成绩是%lf
",s.d_score);
    printf("&s.d_score = %p
",&s.d_score);

    printf("当前成绩是%c
",s.level);//之前的值被覆盖掉了
    printf("当前成绩是%d
",s.i_score);//之前的值被覆盖掉了
    getchar();
    
}

当前成绩是A
&s.level = 00000000010FFEC0
当前成绩是80
&s.i_score = 00000000010FFEC0
当前成绩是80.800000
&s.d_score = 00000000010FFEC0
当前成绩是3   //之前的值被覆盖掉了
当前成绩是858993459   //之前的值被覆盖掉了

C的数组成分: 19
c的数据类型:
基本数据类型
整型 unsigned signed
char short int long
浮点
float double
扩展数据类型
数组
指针
自定义数据类型
结构体(构造体) struct
枚举 enum
联合 union
void 空类型 void

数据的存储特性:
auto static const regiter volatile

用于计算数据字节数 sizeof

类型的别名 typedef

流程控制语句:
分支语句 if else
多路分支 switch case default
循环 for while do
其他语句 break continue return goto


extern 符号的外部链接特性


C99 扩充了5个
_Bool 布尔类型
_Complex 复数类型
_Imaginary 二进制类型
inline 内联
restrict 存储类型,限定指针的访问

指针高级

  回顾指针
      指针 --> 内存的地址 
      指针变量 --> 用来保存地址的内存
      sizeof(指针变量) = 机器字 

      指针运算
               +  -  ++ --
#include <stdio.h>

int main(){
    int arr[5];
    char *pc = (char *)arr;
    int *pa = arr;

    printf("arr 地址 = %p
",arr);
    printf("pc 保存的地址 = %p
",pc);
    printf("pa 保存的地址 = %p
",pa);
    getchar();
    return 0;
}

arr 地址 = 0000000000EFFEC0
pc 保存的地址 = 0000000000EFFEC0
pa 保存的地址 = 0000000000EFFEC0

指针类型++

#include <stdio.h>

int main(){
    int arr[5];
    char *pc = (char *)arr;
    int *pa = arr;
    printf("arr 地址 = %p
",arr);
    printf("pc 保存的地址 = %p
",pc);
    printf("pc++ 保存的地址 = %p
",++pc);
    printf("pa 保存的地址 = %p
",pa);
    printf("pa++ 保存的地址 = %p
",++pa);
    getchar();
    return 0;
}
arr 地址 = 00000000010FFD70
pc 保存的地址 = 00000000010FFD70
pc++ 保存的地址 = 00000000010FFD71
pa 保存的地址 = 00000000010FFD70
pa++ 保存的地址 = 00000000010FFD74
 printf("pc 保存的地址 = %p ",pc);
    pc++; //pc 为char +1个字节
    printf("pc++ 保存的地址 = %p ",pc);

    printf("pa 保存的地址 = %p ",pa);
    pa++; //pa 为int  +4个字节
    printf("pa++ 保存的地址 = %p ",pa);
      指针的作用
            通过指针变量间接访问其所指向的变量    

            作为函数的参数,可以通过指针变量修改函数外部的局部变量

            通过指针传入 大块的数据

      指针常量

       作为函数的参数,通过指针不可以修改 传入的指向区域的内容     

      指针常见问题

           1. 野指针
           int *p;

           p == 


           2. 空指针
           int i = 0;
           int *p = NULL; //p -> 指向 内存0位置

           *p = 20; //往0地址赋值为20;
           //系统报段错误,终止程序

           空指针 比野指针好
           空指针更安全

           避免野指针  在声明指针变量时 对其初始化为NULL


           3. 悬空指针
              函数返回的指针 指向当前函数的局部变量
              当函数结束,局部变量生命结束,内存被收回,指针指向函数局部变量无效
/*
 * 悬空指针
 */

#include <stdio.h>

int * func()
{
    static int b = 20;
    int *pb = &b;
    return pb; //pb 是悬空的指针,所指向的b 在函数结束后,已经被释放了,b的存储空间 可以被其他函数使用
               //pb 之所以悬空 因为 b 是auto 变量
               // 可以返回 字符串常量 的地址

}
int main(){
    
    int a = 10;
    int *pa = NULL;

    pa = func();
    printf("a = %d
",a); //该函数调用 使用了原来b的位置
    printf("*pa = %d
",*pa);

    return 0;
}

int * p,q;
p 是指针变量
q 是整型变量

------------

二级指针

    int *pa = &a; //pa 指向 a变量  pa 保存a 变量的地址
    int **ppa = &pa; //ppa 是二级指针,包保存指针变量pa的地址
#include <stdio.h>

int main(){
    int a = 20;
    int *pa = &a; //pa 指向 a变量  pa 保存a 变量的地址
    int **ppa = &pa; //ppa 是二级指针,包保存指针变量pa的地址


    printf("*pa = %d
",*pa); //通过pa 间接访问 a的值
    printf("**ppa = %d
",*(*ppa)); //通过ppa 间接访问 a的值
    getchar();
    return 0;
}
  *pa = 20
**ppa = 20

 二级指针变量   保存指针变量的地址

   二级指针的作用

#include <stdio.h>
void func(int* i)
{
    *i = 30;
}
int main(){
    int a = 20;
    func(&a);//修改main函数的a变量
    printf("i=%d
",a);//i=30
    getchar();
    return 0;
}
/*
 * 指向指针的指针
 * 二级指针
 */

#include <stdio.h>
void func2(int** pi)
{
    *pi = NULL;
}

int main(){
    int i = 20;
    int *pi = &i;
    printf("pi = %p
",pi);

    func2(&pi); //func2 功能将pi 指向NULL
                //如果要修改传入变量的内容,必须是该变量的指针

    printf("pi = %p
",pi);
    getchar();
    return 0;
}
pi = 000000000098F950
pi = 0000000000000000

      1. 通过函数参数 修改指针变量的内容

/*
 * 二级指针练习
 * [练习]
 *     从键盘上输入两个整数,分别保存在a,b变量中,编写一个func函数,通过调用函数实现pmax 指针指向 保存较大值的变量
 */
#include <stdio.h>
void func2(int *a,int *b, int** pi)
{
    if (*a>*b)
    {
        *pi = a;
    }else{
        *pi = b;
    }
    
}

int main(){
    int a=0,b=b,*pmax=NULL;
    printf("a的地址= %p
",&a);
    printf("b的地址= %p
",&b);
    printf("请输入两个整数
");
    scanf("%d%d",&a,&b);
    printf("改之前pamx = %p
",pmax);
    func2(&a,&b,&pmax);
    printf("改之后pamx = %p
",pmax);
    getchar();
    getchar();
    return 0;
}
a的地址= 0000000000F3F7A0
b的地址= 0000000000F3F7A8
请输入两个整数
34
32
改之前pamx = 0000000000000000
改之后pamx = 0000000000F3F7A0

 2. 字符串数组的使用

#include <stdio.h>
int main(){
    char *str[5] = {"巴西","葡萄牙","比利时","法国","德国"};
    char **pstr = str;
    for(int i = 0;i<5;i++)
    {
        printf("%s
",*(pstr+i));
    }
    getchar();
    return 0;
}
巴西
葡萄牙
比利时
法国
德国
/*
 *  二级指针使用案例
 *  操作字符串数组
 *
 *  写一个程序,预测一下世界杯冠军
 */

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(){
    int i = 0;
    char *str[5] = {"巴西","葡萄牙","比利时","法国","德国"};
    char **pstr = str;

    for(i = 0;i<5;i++)
    {
        printf("%s
",*(pstr+i));
    }

    srand(time(0));
    i = rand()%5;

    printf("我预测的世界杯冠军是 %s
", *(pstr+i));
    getchar();
    return 0;
}
巴西
葡萄牙
比利时
法国
德国
我预测的世界杯冠军是 法国
何所为,不仅仅是一种态度,更是一种艺术!
原文地址:https://www.cnblogs.com/tanzizheng/p/12918793.html