11.字符串、结构体、枚举

字符串

==============

字符串

==============

字符串

        1.字符串的本质
            1》什么是字符串,字符串的存储结构
            2》字符串的输入和输出
        2.字符类型判断函数
            1》isalpha函数
            2》isnumber函数
            3》isupper函数
            4》islower函数
        3.字符转换函数
            1》toupper函数
            2》tolower函数
        4.字符处理函数
            1》strlen字符串长度函数
            2》strcpy字符串复制函数
            3》strcmp字符串比较函数
            4》strcat    字符串连接函数
        5.字符串查找函数
            1》strchr字符串查找字符函数
            2》strrchr字符串中查找匹配的最后一个字符函数
            3》strstr字符串中查找字符串
        7.字符串处理函数的实现
            1》实现以上的字符串处理函数
        8.结构体的定义和使用
            1》什么是结构体,结构体的作用
            2》结构体的初始化
            3》结构体数组
            4》结构体的嵌套
            5》结构体和指针
        9.枚举
            1》什么是枚举,枚举的作用
            2》枚举的定义和使用
            3》使用枚举需要注意的事项

一、什么是字符串?

字符串:就是一串字符。
1.字符数组的定义
数据类型 数组名[常量];
char 数组名[常量];
char ch[100];
(字符数组成员(元素)的引用和整型数组是一样的也是下标法)
2:字符数组成员的引用
下标法:数组名[下标];(下标从0开始到n-1结束)

3:字符数组成员在内存中的存储
结论:连续存储

4:字符数组的大小
char buf[100];
计算方式:sizeof(数组名);
5:字符数组的初始化
1》通过单个字符对字符数组进行初始化
1:完全初始化

            如:char ch[5] = {‘a’,’b’,’c’,’d’,’e’};
        2:部分初始化
            如:char buf[5] = {‘a’,’b’};
        3:没有指定初始化值
            如:char buf[5] = {};
        4:没有指定成员个数
            如:char buf[] = {‘a’,’b’,’c’,’d’,’e’};
    2:通过字符串对字符数组进行初始化
        1:完全初始化
            如:char buf[5] = “abcd”;
        2:部分初始化
            如:char buf[5] = “ab”
        3:没有指定初始化值 
            例子:char buf[5] = “”;
        4:没有指定成员个数
            例子:char buf[] = “abcde”;
#include <stdio.h>

int main(int argc, const char *argv[])
{
    char ch[] = {'a', 'b', 'c', 'd', 'e'};
    printf(" %lu\n", sizeof(ch));
    char ch1[] = "abcde";
    printf("%lu\n", sizeof(ch1));
    return 0;
} 

6:字符串
在c语言中没有提供一种单独的数据类型用来保存字符串,所有我们把字符串保存在字符数组中,通过对字符数组的相关操作来操作字符串
字符串:用双引号“”括起来的若干个字符,并且以‘\0’作为字符串的结束标志
字符串结束标志‘\0’:系统自动添加在字符串的末尾,不需要程序员手动添加
‘\0’:ascii码值等于0 ,是一个不可显示的字符

大小:
字符数组的大小:内存为字符数组开辟的存储空间的大小
字符串的大小:字符串中首次出现’\0’以前的字符的个数
#include <stdio.h>
#include <string.h>

int main(int argc, const char *argv[])
{
    char ch[100] = "dfklhsd\0sdkjh\0sdjdfgdfh\0skdj";
    printf("%lu\n", sizeof(ch));
    printf(" %lu\n", strlen(ch));
    printf("%s\n", ch);
    return 0;
}   

7:字符串的输入和输出
字符串的输入:

        1:scanf
        char buf[100] = “”;
        格式:scanf(“%s”, buf);
        缺点:scanf会把空格,回车和tab键作为字符串的结束
    2:gets
        char buf[100] = “”;
        格式:gets(buf); 
        缺点:gets函数不会对字符串越界进行检查
    字符串的输出:
    1:printf
        printf(“%s”, buf);
    2:puts
        puts(buf);
#include <stdio.h>
#include <string.h>

int main(int argc, const char *argv[])
{
    char buf[100] = "";
    //scanf("%s", buf);
    gets(buf);
    printf("buf = %s\n", buf);
    puts(buf);
    return 0;
} 

练习:输入一个字符串,统计字符串中数字字符和字母字符的个数

#include <stdio.h>

int main(int argc, const char *argv[])
{
    char buf[100] = "";
    int i ;
    int n_n = 0;//统计数字字符的个数
    int n_e = 0;//统计英文字母的个数

    gets(buf);//输入字符串

    for (i=0; buf[i]!=0; i++){
        if ((buf[i]>='0') && (buf[i]<='9')){
            n_n++;
        }
        if (((buf[i]>='A') && (buf[i]<='Z')) || ((buf[i]>='a') && (buf[i]<='z'))){
        n_e++;
        }
    }
    printf("数字字符的个数 =  %d\n", n_n);
    printf("英文字母的个数 =  %d\n", n_e);
    return 0;
} 

二、字符类型判断函数(了解)

1.int isalpha(int c);

判断一个字符是否是字母。

2.int isnumber(int c);

判断一个字符是否是表示数字的字符。

3.int isupper(int c);

判断一个字符是否是表示大写字母的字符

4.int islower(int c);

判断一个字符是否是小写字母。

三、字符转换函数

1.toupper函数

将小字字母转为大写

2.tolower函数

将大写字母转为小字

四、字符处理函数

1.strlen:计算字符串的长度
函数名:strlen

原型:int strlen(char *s);
用法:#include <string.h>

功能:计算字符串s的长度
说明:返回s的长度,不包括结束符\0。

#include <stdio.h>
#include <string.h>

int main(int argc, const char *argv[])
{
    char buf[100] = "";
    int len = 0;
    gets(buf);
    len = strlen(buf);//计算字符串的长度
    printf("len = %d\n", len);
    return 0;
} 
2:strcpy:字符串的复制

原型声明:char strcpy(char dest, const char *src);
头文件:#include <string.h>
功能:把从src地址开始且含有NULL结束符的字符串复制到以dest开始的地址空间
说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。
返回指向dest的指针。

#include <stdio.h>
#include <string.h>

int main(int argc, const char *argv[])
{
    char buf1[100] = "";
    char buf2[100] = "";
    gets(buf2);

    strcpy(buf1, buf2);
    printf("buf1 = %s\n", buf1);
    printf("buf2 = %s\n", buf2);

    return 0;
} 
3:strcat:字符串的拼接
buf1 = bei jing 
buf2 = huan ying nin
strcat(buf1, buf2);
函数名:strcat
原型: char *strcat(char *dest,char *src);
参数说明:参数nptr字符串
头文件: #include <string.h>
功能:把src所指字符串添加到dest结尾处(覆盖dest结尾处的'\0')并添加'\0'
说明:src和dest所指内存区域不可以重叠且dest必须有足够的空间来容纳src的字符串。
返回指向dest的指针。
#include <stdio.h>
#include <string.h>

int main(int argc, const char *argv[])
{
    char buf1[100] = "";
    char buf2[100] = "";
    gets(buf1);
    gets(buf2);

    strcat(buf1, buf2);
    printf("buf1 = %s\n", buf1);
    printf("buf2 = %s\n", buf2);

    return 0;
} 
4:strcmp:字符串的比较
函数名:strcmp
原型:int strcmp(const char *s1,const char * s2);
所在头文件:#include <string.h>
功能:比较字符串s1和s2。
一般形式:strcmp(字符串1,字符串2)
说明:
当s1<s2时,返回为负数 注意不是-1
当s1==s2时,返回值= 0
当s1>s2时,返回正数 注意不是1
即:两个字符串自左向右逐个字符相比
(按ASCII值大小相比较),直到出现不同
的字符或遇'\0'为止。
#include <stdio.h>
#include <string.h>

int main(int argc, const char *argv[])
{
    char buf1[100] = "";
    char buf2[100] = "";
    int t = 0;
    gets(buf1);
    gets(buf2);

    t = strcmp(buf1, buf2);
    if (t < 0){
        printf("buf1 < buf2\n");
    } else if(t == 0) {
        printf("buf1 = buf2\n");
    } else{
        printf("buf1 > buf2\n");
    }

    return 0;
} 

五、字符串查找函数

1:strchr:字符串中查找某个字符
函数名:strchr
char *strchr(const char* _Str,int _Val)
char *strchr(char* _Str,int _Ch)
头文件:#include <string.h>
功能:查找字符串s中首次出现字符c的位置
说明:返回首次出现c的位置的指针,返回的地址是字符串在内存中随机分配的地址再加上你所搜索的字符在字符串位置,如果s中不存在c则返回NULL。
#include <stdio.h>
#include <string.h>

int main(int argc, const char *argv[])
{
    char buf[100] = "";
    char ch = 0;
    
    gets(buf);
    ch = getchar();

    printf("%s\n", strchr(buf, ch));

    return 0;
} 
2:strstr:字符串中查找子串
函数名: strstr
头文件:#include <string.h>
函数原型:char *strstr(const char *str1, const char *str2);
语法:* strstr(str1,str2)
str1: 被查找目标 
str2: 要查找对象 
返回值:该函数返回str2第一次在str1中的位置,如果没有找到,返回NULL
#include <stdio.h>
#include <string.h>

int main(int argc, const char *argv[])
{
    char buf1[100] = "";
    char buf2[100] = "";
    
    gets(buf1);
    gets(buf2);

    printf("%s\n", strstr(buf1, buf2));

    return 0;
} 

六、字符串处理函数的实现

1:my_strlen:计算字符串的长度
#include <stdio.h>

int main(int argc, const char *argv[])
{
    char buf[100] = "";
    int i = 0;//计数
    gets(buf);

    for (i=0; buf[i]!=0; i++);

    printf("i = %d\n", i);
    return 0;
} 

2:my_strcpy:字符串的复制
#include <stdio.h>

int main(int argc, const char *argv[])
{
    char buf1[100] = "";
    char buf2[100] = "";
    int i = 0;

    gets(buf2);

    for (i=0; buf2[i]; i++){//循环复制
        buf1[i] = buf2[i];
    }
    buf1[i] = buf2[i];//'\0'复制过去
    printf("buf1 = %s\n", buf1);
    printf("buf2 = %s\n", buf2);
    return 0;
} 
3:my_strcat:字符串的拼接
1:找到buf1的末尾
for (i=0; buf1[i]!=0; i++);//i是buf1末尾
2:取出buf2中的每一个字符复制到buf1
for (j=0; buf2[j]!=0; j++){
    buf1[i+j] = buf2[j];
}
buf1[i+j]=0;
#include <stdio.h>

int main(int argc, const char *argv[])
{
    char buf1[100] = "";
    char buf2[100] = "";
    int i = 0;
    int j = 0;

    gets(buf1);
    gets(buf2);

    //1:找到buf1的末尾
    for (i=0; buf1[i]!=0; i++);

    //2:取出buf2中的每个字符复制到buf1末尾
    for (j=0; buf2[j]!=0; j++){
        buf1[i+j] = buf2[j];
    }
    buf1[i+j] = 0;//复制0

    printf("buf1 = %s\n", buf1);
    printf("buf2 = %s\n", buf2);
    return 0;
} 
4:my_strcmp:两个字符串的比较
for (i=0; buf1[i]!=0 && buf2[i]!=0; i++){
    if (buf1[i] != buf2[i]){
            break
    }
}
printf(“buf1[i] - buf2[i]”);
#include <stdio.h>

int main(int argc, const char *argv[])
{
    char buf1[100] = "";
    char buf2[100] = "";
    int i = 0;
    int j = 0;

    gets(buf1);
    gets(buf2);

    for (i=0; (buf1[i]!=0)&&(buf2[i]!=0); i++){//遍历字符串
        if (buf1[i] != buf2[i]){//找到第一个不相同的字符
            break;
        }
    }
    printf("buf1[%d]-buf2[%d] = %d\n", i, i, buf1[i]-buf2[i]);
    return 0;
} 
5:my_strchr:字符串中查找字符
for (i=0; buf[i]!=0; i++){
    if (buf[i] == ch){
        break;
    }
}

if (buf[i]!=0){
printf(“%s\n”, buf+i);
} else {
    
}

#include <stdio.h>

int main(int argc, const char *argv[])
{
    char buf[100] = "";
    char ch = 0;
    int i = 0;

    gets(buf);
    ch = getchar();

    for (i=0; buf[i]!=0 ;i++){//遍历buf
        if (buf[i] == ch){//找到ch
            break;
        }
    }

    if (buf[i]!=0){//找到了
        printf("%s\n", buf+i);
    } else {//没找到
        printf("null\n");
    }
    return 0;
} 
6:my_strstr:字符串中找字符串
buf1 = “abcdefg”
buf2 = “cde”     

遍历buf1
遍历buf2

#include <stdio.h>

int main(int argc, const char *argv[])
{
    char buf1[100] = "";
    char buf2[100] = "";
    int i = 0;
    int j = 0;

    gets(buf1);
    gets(buf2);

    for (i=0; buf1[i]!=0; i++){//遍历buf1
        for (j=0; buf2[j]!=0; j++){//遍历buf2
            if (buf1[i+j] != buf2[j]){//有一个字符不相同,后续就不需要在比较了
                break;
            }
        }
        if (buf2[j] == 0){//找到了
            break;
        }
    }

    if (buf2[j] == 0){//找到了
        printf("%s\n", buf1+i);
    } else {//没找到
        printf("null\n");
    }
    return 0;
} 

课后练习:

  1. 给定某个字符数组,统计数组中所有英文字符的个数,比如“123fdd”中有3个。
  2. 给定某个字符数组,统计数组中所有英文字符和阿拉伯数字的个数,比如“123fdd”中有英文字符有3个,数字3个。
  3. 给定一个完全由英文字符构成的数组,将数组中的小写字母转换成大写字母,大写字母转换成小写字母并输出。例如“abcGGG”转化为“ABCggg”。
  4. 给定一个完全由英文字符构成的数组,将数组中下标为偶数的字符都转换为大写(如果原来是大写则不变)。
  5. 给一个完全由英文字符构成的字符数组加密,加密原则如下,除了字符‘Z’和‘z’之外,每个字符变成ASCII码值比它大1的字符,也就是‘A’变成‘B’。‘Z’或者‘z’转化为‘A’或者‘a’。
  6. 计算某个由英文、数字以及标点符号构成的数组的总宽度,其中英文字符的宽度为1cm,数字宽度为0.5cm、标点符号宽度为0.8cm。
    7 给定一个英文句子,单词之间用1个空格分开,求出第2个单词的偏移位置。例如“Professor du comes from Korea”的偏移位置是10。
  7. 给定一个英文句子,单词之间用1个空格分开,求其中所有单词的数量。
  8. 给定两个字符数组,将这两个拼接起来放在第一个数组中(假定第一个数组足够长),比如“abc”和“123”构成“abc123”。
    12.独立实现6个字符串处理函数的基本功能

七、结构体的定义和使用

1:为什么使用结构体
思考:输入输出10个学生年龄
数据模型:数组
操作:循环
思考:年龄只是学生的一个属性,如果描述学生所有的属性
学号———>int num
性别———>char sex;
年龄———>int age;
姓名———>char name[20];
地址———>char addr[30];
结构体:当程序中出现大量不同(相同)数据类型变量时,这些不同类型变量合在一起能够描述某些信息时,这时候就可以通过结构体类型对这些变量进行整体的声明

2:结构体类型的声明

    格式:
    struct 结构体名
    {
        成员列表;
    };
    struct:声明结构体类型关键字,不可以省略
    struct 结构体名:结构体类型
    成员列表:多个数据类型  变量名
    例子:
    struct student
    {
            int num;//学号
            char sex;//性别
            int age;//年龄
            char name[20];//姓名
            char addr[30];//地址
    };

注意:

1:声明结构体类型,只是相当于在系统下声明了一个新的数据类型(int),不会开辟任何的存储空间
2:结构体的成员名可以和程序中的变量名相同
3:在一个结构中,结构体成员可以是其它类型的结构体变量

#include <stdio.h>

struct birthday
{
    int year;
    int month;
    int day;
};

struct student
{
int num;//学号
char sex;//性别
int age;//年龄
char name[20];//姓名
char addr[20];//地址
struct birthday day;//生日
};

int main(int argc, const char *argv[])
{
return 0;
}

练习:

    1:定义出描述朋友相关属性的结构体。
    2:定义出描述生日的结构体(年、月、日)
#include <stdio.h>

struct teacher
{
    int age;
    char name[20];
    char sex;
};

struct birthday
{
    int year;
    int month;
    int day;
};

int main(int argc, const char *argv[])
{
    int age;//结构体成员可以和程序中的变量名相同
    return 0;
} 

3:结构体类型变量的定义
1:在声明结构体类型的同时定义结构体变量
2:先声明结构体类型再定义结构体变量

#include <stdio.h>

struct student
{
    int num;//学号
    char sex;//性别
    int age;//年龄
    char name[20];//姓名
    char addr[20];//地址
}std1;//声明类型同时定义变量

int main(int argc, const char *argv[])
{
    struct student std2;//先声明后定义
    return 0;
} 

注意:
1:声明结构体类型,不需要开辟存储空间,当定义了该结构体类型下的变量时,需要开辟空间了
声明结构体类型 ————>int a中int
定义结构体类型变量———>int a中a
2:相同结构体类型变量之间可以直接赋值

4:结构体类型变量的初始化

#include <stdio.h>

struct student
{
    int num;//学号
    char sex;//性别
    int age;//年龄
    int score;//分数
    char name[20];//姓名
    char addr[20];//地址
}std1 = {1, 'W', 30, 98, "zhangsan", “beike”};

int main(int argc, const char *argv[])
{
    struct student std2 = {2, 'M', 20, 100, “li”, “beike”};
    return 0;
} 

5:指向结构体类型变量的指针
1:指针的定义
格式:struct 结构体名 *变量名;
2:指针的赋值
1:初始化
2:赋值语句

    struct student (*pStd1) = &std;//初始化
    struct student (*pStd2) = NULL;
    pStd2 = &std;//赋值语句
3:指针的大小(8字节)

6:结构体成员的引用
1:通过结构体变量引用结构体成员
格式:结构体变量名 . 结构体成员名
2:通过指向结构体变量的指针来引用结构体成员
格式:指向结构体变量指针 - > 结构体成员名

    #include <stdio.h>

struct student
{
    int num;//学号
    char sex;//性别
    int age;//年龄
    int score;//分数
    char name[20];//姓名
    char addr[20];//地址
};

int main(int argc, const char *argv[])
{
    struct student std = {2, 'M', 20, 100, "chenchao", "hui long guan"};
    struct student (*pStd) = &std;//初始化
    printf("std.num = %d\n
                    std.sex = %c\n
                    std.age = %d\n
                    std.score = %d\n
                    std.name = %s\n
                    std.addr = %s\n", 
                    std.num, 
                    std.sex, 
                    std.age, 
                    std.score, 
                    std.name, 
                    std.addr);
    printf("(*pStd).num = %d\n
                    (*pStd).sex = %c\n
                    (*pStd).age = %d\n
                    (*pStd).score = %d\n
                    (*pStd).name = %s\n
                    (*pStd).addr = %s\n", 
                    (*pStd).num, 
                    (*pStd).sex, 
                    (*pStd).age, 
                    (*pStd).score, 
                    (*pStd).name, 
                    (*pStd).addr);
    printf("pStd->num = %d\n
                    pStd->sex = %c\n
                    pStd->age = %d\n
                    pStd->score = %d\n
                    pStd->name = %s\npStd->addr = %s\n", pStd->num, pStd->sex, pStd->age, pStd->score, pStd->name, pStd->addr);
    printf("(&std)->num = %d\n
                    (&std)->sex = %c\n
                    (&std)->age = %d\n
                    (&std)->score = %d\n
                    (&std)->name = %s\n
                    (&std)->addr = %s\n", (&std)->num, (&std)->sex, (&std)->age, (&std)->score, (&std)->name, (&std)->addr);

    return 0;
} 

int num
char name[20]
int score

课堂练习:
1:输入两个学生的学号、姓名、和成绩,输出成绩较高的学生的学号、姓名和成绩。

#include <stdio.h>

//声明结构体类型
struct student
{
    int num;
    char name[20];
    int score;
};

int main(int argc, const char *argv[])
{
    struct student std1 = {};//结构体变量定义
    struct student std2 = {};

    //输入
    scanf("%d", &(std1.num));
    getchar();
    gets(std1.name);
    scanf("%d", &(std1.score));

    scanf("%d", &(std2.num));
    getchar();
    gets(std2.name);
    scanf("%d", &(std2.score));

    //比较结构体变量的成绩
    if (std1.score > std2.score){
        printf("std1.num = %d\nstd1.name = %s\nstd1.score = %d\n", std1.num, std1.name, std1.score);    
    } else {
        printf("std2.num = %d\nstd2.name = %s\nstd2.score = %d\n", std2.num, std2.name, std2.score);    
    }

    return 0;
} 

2:输入三个学生的学号、姓名和成绩,按成绩高低排序,并输出排序后的结果

#include <stdio.h>

//声明结构体类型
struct student
{
    int num;
    char name[20];
    int score;
};

int main(int argc, const char *argv[])
{
    struct student std1 = {};//结构体变量定义
    struct student std2 = {};
    struct student std3 = {};
    struct student tmp = {};

    //输入
    scanf("%d", &(std1.num));
    getchar();
    gets(std1.name);
    scanf("%d", &(std1.score));

    scanf("%d", &(std2.num));
    getchar();
    gets(std2.name);
    scanf("%d", &(std2.score));

    scanf("%d", &(std3.num));
    getchar();
    gets(std3.name);
    scanf("%d", &(std3.score));

    //排序
    if (std1.score > std2.score){
        tmp = std1;
        std1 = std2;
        std2 = tmp;
    }
    if (std1.score > std3.score){
        tmp = std1;
        std1 = std3;
        std3 = tmp;
    }
    if (std2.score > std3.score){
        tmp = std3;
        std3 = std2;
        std2 = tmp;
    }

    //输出
    printf("std1.num = %d\nstd1.name = %s\nstd1.score = %d\n", std1.num, std1.name, std1.score);
    printf("std2.num = %d\nstd2.name = %s\nstd2.score = %d\n", std2.num, std2.name, std2.score);
    printf("std3.num = %d\nstd3.name = %s\nstd3.score = %d\n", std3.num, std3.name, std3.score);

    return 0;
} 

7:结构体数组和指向结构体数组首元素的指针以及函数
大量整形变量 ——>整形数组
大量字符变量 ——>字符数组
大量指针变量 ——>指针数组
大量结构体变量——>结构体数组

格式:
struct 结构体名 数组名[常量];

数组名:数组首元素地址,地址常量
struct 结构体名:结构体数组成员的数据类型
常量:数组成员个数

指向结构数组首元素的指针:

格式:struct 结构体名 *变量名;

练习:
1:输入输出5个学生的信息
数组

#include <stdio.h>

#define NAME_SIZE   20
#define ADDR_SIZE   30
#define NUM         5
struct student
{
    int num;//学号
    char name[NAME_SIZE];//姓名
    int score;//分数
};

int main(int argc, const char *argv[])
{
    struct student arr[NUM] = {};//结构体数组的定义
    struct student *pArr = arr;//指向结构体数组首元素的指针
    int i = 0;
    //循环输入
    for (i=0; i<NUM; i++){
        scanf("%d", &(arr[i].num));     getchar();
        gets(arr[i].name);
        scanf("%d", &(arr[i].score));
    }

    //循环输出
    for (i=0; i<NUM; i++){
        printf("arr[%d].num = %d\narr[%d].name = %s\narr[%d].score = %d\n", i, arr[i].num, i, arr[i].name, i, arr[i].score);
    }
    return 0;
} 

指针

#include <stdio.h>

#define NAME_SIZE   20
#define ADDR_SIZE   30
#define NUM         5
struct student
{
    int num;//学号
    char name[NAME_SIZE];//姓名
    int score;//分数
};

int main(int argc, const char *argv[])
{
    struct student arr[NUM] = {};//结构体数组的定义
    struct student *pArr = arr;//指向结构体数组首元素的指针
    int i = 0;
    //循环输入
    for (i=0; i<NUM; i++){
        scanf("%d", &((pArr+i)->num));
        getchar();
        gets((pArr+i)->name);
        scanf("%d", &((pArr+i)->score));
    }

    //循环输出
    for (i=0; i<NUM; i++){
        printf("(pArr+%d)->num = %d\n(pArr+%d)->name = %s\n(pArr+%d)->score = %d\n", i, (pArr+i)->num, i, (pArr+i)->name, i, (pArr+i)->score);
    }
    return 0;
} 

函数行参是数组名

#include <stdio.h>

#define NAME_SIZE   20
#define ADDR_SIZE   30
#define NUM         5
struct student
{
    int num;//学号
    char name[NAME_SIZE];//姓名
    int score;//分数
};
void input(struct student arr[], int n);//函数声明
void output(struct student arr[], int n);

int main(int argc, const char *argv[])
{
    struct student arr[NUM] = {};//结构体数组的定义
    struct student *pArr = arr;//指向结构体数组首元素的指针
    input(arr, NUM);//函数调用
    output(arr, NUM);
    int i = 0;
    return 0;
} 
//函数定义
void input(struct student arr[], int n)
{
    int i = 0;
    //循环输入
    for (i=0; i<n; i++){
        scanf("%d", &(arr[i].num));
        getchar();
        gets(arr[i].name);
        scanf("%d", &(arr[i].score));
    }
}

void output(struct student arr[], int n)
{
    int i = 0;
    //循环输出
    for (i=0; i<n; i++){
        printf("arr[%d].num = %d\narr[%d].name = %s\narr[%d].score = %d\n", i, arr[i].num, i, arr[i].name, i, arr[i].score);
    }
}

函数行参是指针

#include <stdio.h>

#define NAME_SIZE   20
#define ADDR_SIZE   30
#define NUM         5
struct student
{
    int num;//学号
    char name[NAME_SIZE];//姓名
    int score;//分数
};
void input(struct student *pArr, int n);//函数声明
void output(struct student *pArr, int n);

int main(int argc, const char *argv[])
{
    struct student arr[NUM] = {};//结构体数组的定义
    struct student *pArr = arr;//指向结构体数组首元素的指针
    input(arr, NUM);//函数调用
    output(arr, NUM);
    int i = 0;
    return 0;
} 
//函数定义
void input(struct student *pArr, int n)
{
    int i = 0;
    //循环输入
    for (i=0; i<n; i++){
        scanf("%d", &((pArr+i)->num));      getchar();
        gets((pArr+i)->name);
        scanf("%d", &((pArr+i)->score));
    }
}

void output(struct student *pArr, int n)
{
    int i = 0;
    //循环输出
    for (i=0; i<n; i++){
        printf("(pArr+%d)->num = %d\n(pArr+%d)->name = %s\n(pArr+%d)->score = %d\n", i, (pArr+i)->num, i, (pArr+i)->name, i, (pArr+i)->score);
    }
}

练习:
输入5个学生的信息,并对学生进行排序(成绩)(姓名)

#include <stdio.h>

#define NAME_SIZE   20
#define ADDR_SIZE   30
#define NUM         5
struct student
{
    int num;//学号
    char name[NAME_SIZE];//姓名
    int score;//分数
};
void input(struct student arr[], int n);//函数声明
void output(struct student arr[], int n);
void sort(struct student arr[], int n);

int main(int argc, const char *argv[])
{
    struct student arr[NUM] = {};//结构体数组的定义
    struct student *pArr = arr;//指向结构体数组首元素的指针
    input(arr, NUM);//函数调用
    sort(arr, NUM);
    output(arr, NUM);
    int i = 0;
    return 0;
} 
//函数定义
void input(struct student arr[], int n)
{
    int i = 0;
    //循环输入
    for (i=0; i<n; i++){
        scanf("%d", &(arr[i].num));     getchar();
        gets(arr[i].name);
        scanf("%d", &(arr[i].score));
    }
}

void output(struct student arr[], int n)
{
    int i = 0;
    //循环输出
    for (i=0; i<n; i++){
        printf("arr[%d].num = %d\narr[%d].name = %s\narr[%d].score = %d\n", i, arr[i].num, i, arr[i].name, i, arr[i].score);
    }
}

void sort(struct student arr[], int n)
{
    struct student tmp = {};
    int i = 0;
    int j = 0;
    for (j=0; j<n; j++){//冒泡执行的次数
        for (i=0; i<n-1; i++){//冒泡
            if (arr[i].score > arr[i+1].score){//比较
                tmp = arr[i];//交换
                arr[i] = arr[i+1];
                arr[i+1] = tmp;
            }
        }
    }
}

九、枚举
1:枚举的使用
思考:如何描述季节
季节:春、夏、秋、冬
int a;——>1 2 3 4
枚举的使用:当某个变量的值只有几种可能的时候,我们可以通过枚举一一列举出变量的值(枚举形象直观好看)
例子:
1:四季
2:星期
3:月份

2:枚举类型的声明
格式:enum 枚举名 {枚举元素列表};
enum:声明枚举类型的关键字,不能省略
enum 枚举名:枚举类型
例子:

    enum Season {spring, summer, autumn, winter};
    enum Weekday {………};
    enum Month {……………};

3:枚举类型变量定义
格式:enum 枚举类型 变量名;

    enum Season {spring, summer, autumn, winter};
    enum Season season;

4:枚举类型变量的赋值
枚举变量的值只能枚举元素中的某一个

    enum Season {spring, summer, autumn, winter};
    enum Season season;
    season  = summer;

5:关于枚举的几点说明
1:系统是把枚举的元素的值当作常量的来处理的,程序运行过程中枚举元素的值不能够被修改
summer = 8;//错误
2:枚举元素的值对应一个整数值,枚举元素的值是有枚举元素在枚举元素列表的位置决定

enum Season {spring, summer, autumn, winter};
spring(0), summer(1), autumn(2), winter(3)

    声明枚举元素时,可以对枚举元素进行初始化
enum Season {spring, summer=6, autumn, winter};

    3:枚举元素之间可以进行关系运算
#include <stdio.h>

enum Season {spring, summer, autumn, winter};//枚举类型声明

int main(int argc, const char *argv[])
{
    enum Season season = 0;
    for (season=spring; season<=winter; season++){
        printf("season = %d\n", season);
    }
    return 0;
} 

typedef
1:typedef的使用
typedef可以给系统下已经存在的数据类型起别名(typedef没有创建新的数据类型,只是在原有的数据类型基础上起个新名字)

2:typedef给数据类型起别名的步骤
1:先定义出该类型下的变量
2:将变量名换成新的数据类型
3:在最前面加上typedef
4:新的数据类型定义出变量

3:typedef和其它数据类型的结合
1: typedef和基本数据类型

            例子:typedef  int   Interage;
                Interage a;//相当于int a;//Interage是数据类型,相当于int
2: typedef和数组
        例子:typedef int Arr10[10];
                        Arr10 arr;//等价于int arr[10];//Arr10是数据类型,相当于int [10]
3: typedef和指针
        1: typedef和一级指针                 例子:typedef  int *Pointer;
                Pointer p;//等价于int *p;//Pointer是数据类型,相当于int *
        2: typedef和二级指针
                例子:typedef  int **Ppointer;
                Ppointer pp;//相当于int **pp//Ppointer是数据类型,相当于int **
        3: typedef和函数指针
                例子:
                int add(int a, int b);
                typedef  int (*Pfunction)(int a, int b);
                Pfunction p;//相当于 int (*p)(int a, int b);//Pfunction是数据类型,相当于 int (*)(int a, int b)

4: typedef和结构体
            1: typedef和结构体变量和指向结构体的指针
            例子:
                typedef struct student
                {
                        int age;
                        char name[20];
                }Student, *Pstudent;
            Student std;//相当于struct student std;//Student是数据类型类型,相当于struct student
            Pstudent p;//相当于struct student *p;//Pstudent是数据类型,相当于struct student *

5: typedef和枚举
        例子:
            typedef  enum Season {spring, summer, autumn, winter} EnumSeason;
            EnumSeason season;//等价于enum Season season; //EnumSeason是数据类型,相当于enum Season
#include <stdio.h>

//typedef和结构体
typedef struct
{
    int age;
    char name[20];
}Student, *Pstudent;

//typedef和枚举
typedef enum Season {spring, summer, autumn, winter}EnumSeason;

int add(int a, int b)
{
    return a+b;
}

//typedef和基本数据类型
typedef int Interage;
//typedef和数组
typedef int Arr10[10];
//typedef和指针
//1: typedef和一级指针
typedef int *Pointer;
//2: typedef和二级指针
typedef int **Ppointer;
//3: typedef和函数指针

typedef int (*Pfunction)(int a, int b);

int main(int argc, const char *argv[])
{
    //通过新的数据类型定义变量
    Interage a;//int a
    Arr10 arr;//int arr[10]
    Pointer p;//int *p
    Ppointer pp;//int **pp
    Pfunction pFun = add;//int (*p)(int a, int b)
    Student std;//struct std
    Pstudent pStd;//struct *
    return 0;
} 

预处理命令
1:什么是预处理
预处理发生在程序编译的第一个阶段,将程序转换成纯粹的c语言

2:常见预处理的种类和特点
1:宏定义
2:文件包含
3:条件编译

特点:
1:#开头
2:独占一行
3:末尾没有分号

3:宏定义
1:不带参数的宏定义
格式:#define 宏名 字符串
作用:在程序中任何出现宏名的地方都用字符串进行替换
例子:
#define NUM 10
#define SIZE 100
例子:
#define PI 3.14
#define R 2
printf(“%f\n”, PIRR );

    2:带参数的宏定义
        格式:#define 宏名(行参列表)    字符串
        作用:不仅要进行宏名替换,还要进行字符串的替换(实参替换行参,其它普通字符原样保留)
        #define  S(a, b)  ((a)*(b))
        S(3, 5)———>3*5
        
        S(3+2, 5+7)——>((3+2)  * (5+7))
        复合运算符
        a*=3+5
        a = a *(3+5)            

4:文件包含
stdio.h
1:#include <stdio.h>:标准查找,系统回到存放标准库头文件的目录去查查找
2:#include “head.h”:现在当前目录查找,如果找不到在按标准方式查找

5:条件编译
什么是条件编译:通常情况下,程序中的每一条语句都会参与编译,如果想让某些代码在满足一定条件才参与编译
条件编译的几种形式:
(1)#ifdef 标识符
程序段1
#else
程序段2
endif
判断过程:若标识符已经被#define定义过,则在程序编译阶段编译程序段1;否则编译程序段2.其中#else部分可以没有。

(2)#ifndef 标识符
程序段1
#else
程序段2
endif
判断过程:若标识符没有被#define定义过,则在程序编译阶段编译程序段1;否则编译程序段2.其中#else部分可以没有。
(3)#if 表达式
程序段1
#else
程序段2
#endif
判断过程:当表达式值为真执行程序段1,否则执行程序段2

常用的条件编译:
1:

if 0

代码

endif

2:防止头文件重复包含
.h开头

ifndef _HEAD_H

define _HEAD_H

内容

endif

©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 204,445评论 6 478
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 85,889评论 2 381
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 151,047评论 0 337
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 54,760评论 1 276
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 63,745评论 5 367
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 48,638评论 1 281
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 38,011评论 3 398
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 36,669评论 0 258
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 40,923评论 1 299
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 35,655评论 2 321
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 37,740评论 1 330
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 33,406评论 4 320
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 38,995评论 3 307
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 29,961评论 0 19
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 31,197评论 1 260
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 45,023评论 2 350
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 42,483评论 2 342

推荐阅读更多精彩内容