知识点: 1.结构体 struct 2.联合体 union 3.枚举 4.结构、联合与函数 =========================== 结构体 思考:如果现在希望保存一个学生的信息,该如何保存 sprintf "zhangsan:18:180” %s:%d:%d, name, height, age char name[10][100] int age[10] int height[10] 1.什么是结构体 struct 结构体指的是一种数据结构,是c语言中复合数据类型的一 种多种不同数据类型的集合 2.结构体的作用 结构体可以用来创建复杂的数据结构 3.结构体的定义 1)定义的语法!! 4.结构体成员声明 1)可以声明各种类型的成员 2)成员声明时需要注意的地方 练习: struct 1.定义一个结构体,用来描述时间, 具体说该结构体有三个成员,分别描述时分秒信息 2.定义一个结构体,用来描述书本的信息, 结构体成员包括名称,单价,作者,出版社 author price publish 5.声明结构体类型变量和初始化 . 非指针 -> 指针 6.结构体成员的访问方式 练习: 1.初始化并输出时间结构体的信息 2.初始化并输出书本结构体的信息 3.从终端输入书本的信息,并且输出 7.结构体数组 练习: 1.2本书的名称等信息,然后按照每行一本书的信息输出 2.建立包含2个学生信息的登记表,其中包括学号,姓名,性别,住址和3门成绩 8.结构体指针变量 1)指向结构体变量的指针 int *p; struct stu *p; 9.结构体的嵌套和指针成员 1)结构体中嵌套结构体 2)结构体中的成员为一个指针变量 10.结构体和函数 1)思考:结构体在函数传递时是否会和数组一样进行地址传递 2)结构体的参数传递方式,值传递和地址传递 练习: 0.实现一个函数,作用为输入某个学生的学生信息 scanf("%d", &s->id); 1.实现一个函数,作用为输出某个学生的学生信息 2.实现一个函数,作用为遍历所有的学生信息 11.结构体的大小和内存对齐 1)思考:为什么会出现相同机构体,大小不同的情况 2)原因:大致可以分为2点 1>平台原因(移植):不是所有的硬件平台都能访问任意 地址上的任意数据 2>性能原因:经过内存对齐后,cpu的内存访问速度大大 提升 3)对齐方式 1>和编译器有关,一般32位系统默认以4个字节方式对齐 2>本系统以结构体中最大元素的类型进行对齐 =========================== 联合体 ip协议 192.168.1.1 fe80::72cd:60ff:fe38:308%en0 union{ struct ipv4{ //... }; struct ipv6{ //... }; }; 1.什么是联合体 union 1)共享存储空间 2)同时只能使用某一种数据类型 char int double 2.作用 1)当多个数据需要共享内存或者多个数据每次只取其一时,可以利用联合体 3.联合体的定义 //和结构体操作一致 4.联合体成员声明 5.联合体类型变量 6.联合体大小 7.联合体成员输入和输出 =========================== 枚举 enum size{S,M,L} S = 0 M = 1 L = 2 1.什么是枚举 enum 所谓枚举是指将变量的值一一列举出来,变量只限于列举出来的值的范围内取值。 2.枚举的作用 关心的不是它的值的大小,而是其表示的状态 3.枚举变量的声明 4.枚举变量的初始化和输入输出 5.枚举的本质 1)用标识符表示的整数常量集合 2)枚举元素不是变量,而是常量,因此枚举元素又称为枚举常量。 因为是常量,所以不能对枚举元素进行赋值。 3)枚举元素作为常量,它们是有值的,C 语言在编译时按定义的顺序使它们的值为,1,2,…。 练习: 1.定义一个表示衣服码数的枚举集合 2.让用户选择码数,然后输出该码数 6.使用枚举需要注意的地方 1)在一个程序中不允许出现同名的枚举类型 2)在一个程序中不允许出现同名的枚举常量 ===========================
字符串总结:
知识点: 1.字符和字符处理函数 2.字符串的本质和字符串输入输出函数 3.字符串转换函数 4.常用字符串处理函数 5.字符串查找函数 6.字符串分割函数 7.字符串替换 8.常用字符串处理函数实现 9.sscanf函数 ================================= 字符和字符处理 1.复习ascii码 '0'~'9' 'a'~'z' 'A'~'Z' 48 97 65 2.字符的本质 思考:sizeof(char) 和sizeof('a') 1)字符的本质为一个int类型的ascii码 2)字符变量保存的是ascii码,但是ascii码只需要一个字节即可保存 3.使用字符判断函数 isdigit 数字字符 isalpha 字母(大小写) isalnum 数字字符和字母 islower 小写字母 isupper 大写字母 isspace 空格字符 0 --表示测试不成立 1 --表示测试成立 练习: 1.用户输入一个字符串,统计其中数字,字母,空格的个数 2.分别统计出大小写字母的个数 4.使用字符转换函数 tolower 大写转换为小写 int tolower(int c) toupper 小写转换为大写 int toupper(int c) 练习: 1.将用户输入的字符串中的大写字母转换为小写字母 2.将用户输入的字符串中的数字 小写字母全部转换为*号 3.将用户输入的字符串中的其他字符转换为?号 其他字符不包括数字,字母,空格 Hell+ world Hell? world ================================= 字符串 char s1[100] = "hello world"; char *s2 = "hello world"; 0.字符串 不以字符数组引用时为一个常量 //栈 char str[] = "hello"; char str[12] = {'h', 'e','l','l', 'o',' '}; char str[100]; //只读数据段 char *p = "hello world"; printf("%s", str); string scanf("%s"); 不包含空格的输入 scanf("%[^ ]"); 包含空格的输入 printf("hello world"); char str[] = "hello world" char str[] = {'h','e','l','o',' '}; 1.字符串的本质 1)字符串本质为字符串常量 "hello world" 2.思考:sizeof('A')和sizeof("A") 字符常量按照4个字节处理 字符串常量为了节省内存空间,字符串中的所有字符均以char类型处理 3.回忆char *str和char str[]区别 NSString NSMutableString ================================= 字符串的输入输出 1.字符串的输入和输出 0)字符串输入输出函数 1>回忆scanf获取字符串 scanf("%s"); 2>如何获取带空格的字符串 %[^ ] 3>puts string 4>字符串输出 puts函数会在字符串输出后添加换行符号 printf("%s ", str); 1)字符串的输入与溢出问题 思考:字符数组在输入时候的长度问题 2)解决方法 fgets 用法:fgets(buf, 100, stdin); 从标准输入获取指定长度的字符串,包含字符串结束符 ================================= 字符串转换函数 100 + 200 需求:现在用户输入一个算术表达式,要求得到对应的结果 思考:如何将字符串中的字符数字转换为真实的数字 1.字符串转换函数 1)atol和atoi和atof函数 atof返回double 2)实现atoi函数(支持正负数) 示例:实现个位数的负数转换 练习:实现n位数的的正负数转换 3)strtol函数 1010 0x123456 字符串中不能出现和当前进制相悖的数据 1>atoi的增强版 2, 8, 10, 16 2>函数说明:将指定字符串按照base的进制方式转换为10进制 base范围为2~36 ==================================== 字符串常用函数 需求:用户需要知道输入的字符数的长度 1.字符串长度计算函数 1)strlen函数使用 "hello world" while (str[i] != ' ') { cnt++; i++; } 2)思考:strlen和sizeof的区别 3)思考:strlen长度的大小 需求:用户需要我们在软件中实现选中字符的复制功能 2.字符串拷贝函数 strcpy 会将src内的所有内容拷贝到 dst数组中,包括 strncpy 思考:strncpy拷贝后是否会包含结束符 练习:实现一个字符串拷贝模块 需求:用户需要在软件中实现一个字符串的查找功能 3.单个字符的查找 strchr 查找字符第一次出现的地址 strrchr 查找字符最后一次出现的地址 练习: 输入一个字符串,再输入一个字符 查找并打印第一次出现和最后一次出现的字符 并输出该字符的地址 4.字符串查找到 strstr,strcasestr,strnstr 需求:用户需要输入一个名字,判断该用户是否存在 5.字符串比较函数 strcmp,strcasecmp strncmp,strncasecmp int strncmp(const char *s1, const char *s2, int n); 1)比较顺序:s1是否和s2相同 2)比较结果:0为相同,非0为不同,并且返回对应的差值 思考:非0的结果表示什么 3)思考:当s1比s2长度长的话会如何 返回s1最后一个字符和s2结束符的差 练习: 0.编写一个模拟登陆程序,输入用户名和密码,判断用户名和密码 是否和所设定的一致 1.编写一个验证程序,判断用户输入的字符串是否以qianfeng开头 需求:用户现在需要将输入的两个字符串组合成一个完整的字符串 6.字符串连接 strcat,strncat 练习:先输入自己的姓,再输入名字,最后将连接好的名字输出 需求:用户现在需要按照一定的格式分割一个字符串 7.字符串分割函数 1)strtok使用 1>要分割的内容 2>分割符,分割标记 2)如何获取下一个字符串 3)注意 0>不能截取字符串常量 1>截取后的长度 2>如果在下一次截取前截取另外一个字符串会如何 练习: 1.顺序输出分割后的所有字符串 2.查找字符串中的最长单词,并且输出该单词 需求:现在用户需要实现一个文本的查找替换功能 8.单个字符替换 strchr 9.字符串替换 strstr和strncpy联合实现 hello world ===================================== 常用字符串处理函数的实现 1.字符处理函数的实现 2.字符串处理函数的实现 strlen int mystrlen(const char *str); strcpy void mystrcpy(char *dst, const char *src); strchr char *mystrchr(char *str, int c); strrchr char *mystrrchr(char *str, int c); strcmp int mystrcmp(const char *s1, const char *s2) strcat void mystrcat(char *s1, const char *s2); ==================================== “11:59:59” sprintf和sscanf %[^'|'] 需求:用户需要将每个用户的信息按照以下格式输出 1.字符串格式化函数 1)sprintf使用 2)printf和sprintf对比 int sprintf(const char *s, const char *fmt, …) 练习: 1.按照以下格式输出时间 年-月-日 时:分:秒 需求:用户需要将刚才的用户信息重新解析为单个的属性 2.字符串格式化读取函数 1)sscanf使用 集strtok和atoi等函数于一体 2)scanf和sscanf对比 ==================================== 超大数相加 “123” + “123” = “246” 2 = ’2‘ “123423413412374891374238476123846183474183” “123423413412374891374238476123846183474183”
位操作总结:
知识点: 1.位运算符 2.位移运算符 1.将指定位设置为1 2.将指定位设置为0 3.获取指定位的内容 ========================== 复习二进制 1.二进制转换 10--> /2 取余数 1010 2.原码,反码,补码 -1 0xffffffff %d %#x %#o 3.二进制高位和低位 0000 0001 4.二进制输出函数 1010 ========================== 位操作 1.什么是位操作 位操作是程序设计当中对位模式按位或二进制数的一元和二元操作. 在许多古老的微处理器上, 位运算比加减运算略快, 通常位运算比乘除法运算要快很多. 在现代架构中, 情况并非如此:位运算的运算速度通常与加法运算相同(仍然快于乘法运算). 2.作用 1)加快某些算术元素操作,例如乘法和除法使用位移效率较高 2)标志位设置 ========================== 位运算符 1.位运算符 << , >>, &, |, ~, ^ 1)对比逻辑运算符 &&, ||, ! 2.位与操作 & 1)按位&运算符的运算方法 按顺序,每一位进行比较,如果两位都为1,结果为1,相反为0 2)十六进制表示二进制 4)作用: 1.清空某一位 2.获取某一位 示例: 0&0, 1&0, 0&1, 1&1 -1 & 1 练习: 1.手工运算,然后程序验证: 1010 1100 & 1110 0111 164—>0xa4 1110 1101 & 1010 0101 165->0xa5 3.位或操作 | 1)按位|运算的运算方法 对应位只要一个为1,结果为1,如果都为0,结果为0 练习: 1.手工运算,然后程序验证: 1010 1100 | 1110 0111 239 1110 1101 | 1010 0101 237 & 0 1 0 0 0 1 0 1 | 0 1 0 0 1 1 1 1 4.位取反 ~ 1)位取反运算方法 所有位按位取反 2)注意取反结果 练习: 手工运算,然后程序验证: 1.~11011111 0xffffff20 2.~-1 5.位异或(xor) ^ 1)运算方法 对应位不同为1,相同为0 ^ 0 1 0 0 1 1 1 0 练习: 手工运算,然后程序验证 1. 1 ^ 1, 1 ^ 2, 1 ^ 3 2. -1 ^ 10 两数交换的位操作版本 =========================== 位移操作 2^n |0000 0001| 1.左移运算符 << 1)运算方式 高位移出位舍弃,低位补0 示例: 1111 0001 << 1 练习: 手工运算,然后程序验证 1. 1 << 0, 1 << 1, 1 << 2, 1 << 3 2. -1 << 1 1 << 31 |0000 0010| |1111 1000| |0000 0001| |1111 1100|0 |0000 0000|1 |1111 1110|00 0000 0001 >> 1 1 / 2 1%2 2.右移运算符 >> 1)运算方式 1>无符号右移 unsigned 高位补0 2>有符号右移 -2 2 移出位舍弃,高位补符号位 练习: 手工运算,然后程序验证 1. 1 >> 0,1 >> 1, 4 >> 1, 8 >> 1 2. -10 >> 1 -5 >> 1 ======================================== 应用示例: 1.指定位清0 思考:如何设置第n位为0 n & ~(1 << num) 练习:定义一个函数,作用为设置指定为0 函数原型:int set0(int n, int num) 2.指定位设置为1 思考:如何设置第n位为1 n | (1 << num) 练习:定义一个函数,作用为设置指定位为1 函数原型:int set1(int n, int num) 3.获取某一位的值 n >> num & 1 00000000 思考:如何可以获取指定位的值 练习:定义一个函数,作用为获取某一位的值 函数原型:int get_bits(int n, int num) 4.二进制转换函数 思考:如何利用位操作可以获取到一个数的二进制 函数原型:void binshow(unsigned int n, int size) ========================================= 扩展 1.如何循环左移或者右移int的所有位 1 2 3 4 5 5 1 2 3 4 unsigned 1010 0101 1010 2.利用位操作实现简单的加密解密功能 ^