C语言 枚举,进制,原码,反码,补码,移码,结构体,

枚举
什么是枚举
把一个事物所以可能的取值一一列举出来
/*

目的:枚举

*/

#include <stdio.h>

//自定义了一个数据类型,并没有定义变量,该数据类型的名字 enum WeekDay
enum WeekDay
{
//MonDay, TuesDay, WednesDay, ThursDay, FriDay, SaturdDay, Sunday
MonDay=10, TuesDay, WednesDay, ThursDay, FriDay, SaturdDay, Sunday

};//分号

int main(void)
{
//int day;//day定义成int类型范围太大不合适,day的取值只可能有7个(0-6),浪费空间
enum WeekDay day = FriDay; //初始化一个enum WeekDay 类型变量 day
printf("%d\n", day);

return 0;

}

/*
输出结果:
4

14
/
怎么使用枚举
/

目的:枚举2

*/

#include <stdio.h>
enum weekday
{
MonDay, TuesDay, WednesDay, ThursDay, FriDay, SaturdDay, Sunday

};

void f(enum weekday i)//本函数的目的只是期望接受0-6之间的数字,将形参定义为枚举
{
switch (i)
{
case 0:
printf(“MonDay !\n”);
break;
case 1:
printf(“TuesDay !\n”);
break;
case 2:
printf(“WednesDay !\n”);
break;
case 3:
printf(“ThrusDay !\n”);
break;
case 4:
printf(“FriDay !\n”);
break;
case 5:
printf(“ThursDay !\n”);
break;
case 6:
printf(“SunDay !\n”);
break;
}

}

int main(void)
{
f(FriDay);//虽然FriDay本质上就是5,但直接写出f(5);就是错的,也不可能写成Friday 大小写敏感
return 0;
}
枚举的优缺点
优点:代码更安全(强制输入),比较直观(有意义)
缺点:书写麻烦,不能出错。
总结:当是有限个元素时,用枚举更安全,高效。

位运算符
约翰·冯·诺依曼(JohnVonNouma,1903-1957),美藉匈牙利人
被称为计算机之父:2大贡献
二进制
计算机设备分类:运算器 控制器 存储器 输入设备 输出设备
什么是进制
数字是本质,进制只是不同表现方式
一个十六进制位,要用4个二进制数表示,(1)16 = (0001)2 前面补齐

二进制 逢 二进一
十进制 逢 十进一 dec
八进制 逢 八进一 oct 0数字 int i = 05;
十六进制 逢 十六进一 hex 0x数字 0X数字
int i = 0x5;int i = 0X5;
生活中:
七进制 七天进周
十二进制 十二月进年
二十四进制 二十四小时进日
六十进制 六十分钟进小时
六十秒钟进分钟
汇编里
1101B 二进制
1357O 八进制
2049D 十进制
3FB9H 十六进制

十进制(D) 二进制(B) 八进制(O) 十六进制(H)
0 0 0 0
1 1 1 1
2 10 2 2
3 11 3 3
4 100 4 4
5 101 5 5
6 110 6 6
7 111 7 7
8 1000 10 8
9 1001 11 9
10 1010 12 a (A)
11 1011 13 b (B)
12 1100 14 c ©
13 1101 15 d (D)
14 1110 16 e (E)
15 1111 17 f (F)
16 10000 20 10

017 = 7 + 18 = 15
0x17 = 7 + 1
16 = 25
1234 = 4 + 110三次方 + 210二次方 + 310一次方
0x32c = c + 3
16二次方 + 2*16一次方 = 4354
最高幂数是位数-1

#include<stdio.h>
int main(void)
{
int i = 0x32c;
printf(“i = %d\n”, i);
printf(“i = %x\n”, i);
printf(“i = %o\n”, i);
/*
printf的用法
%d 以十进制输出
%x 或 %X 以十六进制输出
%o 或 %O 以八进制输出
*/
return 0;
}

#include <stdio.h>

int main(void)
{
int i = 1000;
print("%X\n", i) //3E8
printf("%#X\n",i) //OX3E8 %#X 推荐
return 0;
}

补码:
原码:
也叫符号绝对值
最高位0表示正 1表示负,其余二进制位是该数字的绝对值的二进制位
在计算机中,从未被使用!

******反码******
	反码运行不便,也没有在计算机中应用
	-----------------------------------------	
****移码****
	表示数值平移n位,n称为移码量
	移码主要用于浮点数的阶码的存储
	-----------------------------------------	
补码	

地址是内存单元编号从 0到4G-1
即 2的32次方-1 总线若是32位,则有32个0,1
主要解决整数的存储 int 4字节 32位个0,1

A 已知十进制求二进制
求正整数的二进制
除2取余,直到商为零,余数倒序排列

求负整数的二进制
先求出与该负数相对应的正整数的二进制代码,
然后,将所有位取反末尾加1,不够位数时,左边补一
4字节int -5 先求5的二进制
0000 0000 0000 0000 0000 0000 0000 0101 所有位取反,末尾加1
1111 1111 1111 1111 1111 1111 1111 1011 16进制:FFFFFFFB
2字节 short int(-3) 先求3的二进制
0000 0000 0000 0011 所有位取反,末尾加1
1111 1111 1111 1101 用十六进制表示: FFFD
求零的二进制
全是零

B 已知二进制求十进制
如果首位是0,则表明是正整数,
按普通方法来求

如果首位是1,则表明是负整数,
将所有位取反末尾加1,所得数字就是该负数的绝对值
	习题:FFFFFFF5 已知二进制  求其代表的整数是多少?

1111 1111 1111 1111 1111 1111 1111 0101
由于最高位是1,所以最终是负数,先对其所有取反
0000 0000 0000 0000 0000 0000 0000 1010 末尾加1后
0000 0000 0000 0000 0000 0000 0000 1011 该值为11 所以最终结果:-11

如果全是零,则对应的十进制数字就是零

C 二进制 到 十六进制
4位一段 从右到左 分别转化 不够左边初零
(0010 1110)2 – (2E)16

D 十六进制 到 二进制
一位转化成4位,不够左边补0
(1)16-- (0000 0000 0000 0000 0000 0000 0000 0001)2

E 二进制 转到 八进制
从右往左,三位一段 不够被0

F 八进制 与 十六进制 不能直接转化。通过中间进制。
进制总结:
进制属于什么知识点,许多人爱不懂装懂。学习好它有利于将来学习底层如汇编等知识,但要往高级语言发展则不需要掌握,另外学好它对后面位运算等有帮助。

      最小负数的二进制代码是多少	1(0-0 31个0)
      最大正数的二进制代码是多少	0(1-1 31个1)
			
      已知一个整数的二进制代码求原始的数字 

按“已知二进制求十进制”求
数字超过最大正数会怎样 变成负数 0111 1111=127 1000 0000 -128

不同数据类型转化
丢失最高位.只截留后者类型所占的字节数。
例如: int 类型 转化 为char 则高3位字节被截取。只保留最后一位字节。

结构体 (非重点)
为什么需要结构体
为了表示一些复杂的事物,而普通的基本类型无法满足实际要求。
什么叫结构体
把一些基本类型数据组合在一起形成的一个新的复合数据类型。
如何定义结构体
3种方式:
// 第一种 只是定义了一个新的数据类型,并没有定义变量 推荐采用1
struct Student
{ Int age;
Float score;
Char sex;
};
//第二种
struct Student
{ Int age;
Float score;
Char sex;
} st;
// 第三种
struct
{ Int age;
Float score;
Char sex;
} st;
怎样使用结构体变量
赋值和初始化
定义的同时可以整体赋值。
如果定义完之后,则只能单个赋初值。
如果取出结构体变量中的每一个成员{重点}
1 结构体变量名.成员名
2 指针变量名->成员名 (更常用)
它会在计算机内部转化成 (* 指针变量名).成员名 的方式来执行。
所以两者是等价的。
例子:
Struct Student
{
Int age;
Float score;
Char sex;
};
Int main(void)
{
Struct Student st = {80,66.6f,’F’};
//初始化定义的时候赋值 66.6在C语言中默认是double类型,如果希望一个实数是float类型,则必须在末尾加f或F, 因此66.6是double, 66.6f或66.6F是float
struct Student st2;
st2.age = 10;
st2.score = 88;
st2.sex = ‘F’; // 第二种方式 单独赋值

Struct Student *pst = &st; // &st 不能写成 st 
Pst->age = 88; // 通过结构体指针变量
printf("%d %f\n", st.age, pst->score);
Return 0;

}
理解:1 pst->age 会在计算机内部转化成 (*pst).age 的方式来执行,没有为什么,这就是->的含义,这也是一种硬性规定。
2 所以 pst->age 等价于 (*pst).age 也等价于 st.age
3 pst->的含义:pst 所指向的那个结构体变量中的age这个成员。
结构体变量的大小略大于其内部成员类型所占字节数之和。试:sizeof(struct)
若想通过函数对主函数结构体变量进行修改,则主函数必须发送地址,外函数定义指针结构体变量,通过外函数内部语句完成对变量的修改。
而仅想输出、读取操作,则不用传地址,定义指针过程。

例:
/*

通过函数完成对结构体变量的输入和输出

*/

include <stdio.h>

include <string.h>

struct Student
{
int age;
char sex;
char name[100];
}; //分号不能省

void InputStudent(struct Student *);
void OutputStudent(struct Student ss);
int main(void)
{
struct Student st; //15行

InputStudent(&st); //对结构体变量输入  必须发送st的地址
//printf("%d %c %s\n", st.age, st.sex, st.name);  // 此行和 下行输出函数 功能相同
OutputStudent(st); //对结构体变量输出  可以发送st的地址也可以直接发送st的内容

return 0;

}

void OutputStudent(struct Student ss)
{
printf("%d %c %s\n", ss.age, ss.sex, ss.name);
}

void InputStudent(struct Student * pstu) //pstu只占4个字节
{
(*pstu).age = 10;
// pstu->name = “张三丰”; 或(*pstu).name = “张三丰”; 都是error,提示错误信息: cannot convert from ‘char [5]’ to ‘char [100]’
strcpy(pstu->name,“张三丰”); // 用字符串拷贝命令解决问题
pstu->sex = ‘F’;
}

/*
//本函数无法修改主函数15行st的值 所以本函数是错误的
void InputStudent(struct Student stu)
{
stu.age = 10;
strcpy(stu.name, “张三”); //不能写成 stu.name = “张三”;
stu.sex = ‘F’;
}
*/

结构体:应该发送地址还是内容
设计函数的目的:必须考虑 功能单一, 还要考虑安全因素
C++中指针前可加const 则只能读而不能修改其指向的变量。
指针的优点:
耗用内在小(4字节)
快速传递数据
执行速度快。
因此:推荐使用结构体变量作为函数参数来传递

/*
2009年11月24日9:17:43
示例:
发送地址还是发送内容
目的:
指针的优点之一:
快速的传递数据,
耗用内存小
执行速度快
*/

include <stdio.h>

include <string.h>

struct Student
{
int age;
char sex;
char name[100];
}; //分号不能省

void InputStudent(struct Student *);
void OutputStudent(struct Student *);
int main(void)
{
struct Student st ; //15行
//printf("%d\n", sizeof(st));

InputStudent(&st); //对结构体变量输入  必须发送st的地址
OutputStudent(&st); //对结构体变量输出  可以发送st的地址也可以直接发送st的内容 但为了减少内存的耗费,也为了提高执行速度,推荐发送地址

return 0;

}

void OutputStudent(struct Student *pst)
{
printf("%d %c %s\n", pst->age, pst->sex, pst->name);
}

void InputStudent(struct Student * pstu) //pstu只占4个字节
{
(*pstu).age = 10;
strcpy(pstu->name, “张三”);
pstu->sex = ‘F’;
}

结构体变量的运算
不能加减乘除操作,只能相互赋值。
例如: struct Student
{
Int age;
Char sex;
Char[100];
};
Struct Student str1, str2;
Str1 = str2 / str2 = str1 ; 都是正确的。

举例:动态构造存放学生信息的结构体数组

include <stdio.h>

include <malloc.h> // 必须先添加头文件 malloc

struct Student
{
int age;
float score;
char name[100];
};

int main(void)
{
int len;
struct Student * pArr;
int i, j;
struct Student t;

//动态的构造一维数组
printf("请输入学生的个数:\n");
printf("len = ");
scanf("%d", &len);
pArr = (struct Student *)malloc(len * sizeof(struct Student));
//printf("%d\n",sizeof(struct Student));   // 108字节  

//输入
for (i=0; i<len; ++i)
{
	printf("请输入第%d个学生的信息:\n", i+1);
	printf("age = ");
	scanf("%d", &pArr[i].age);

	printf("name = ");
	scanf("%s", pArr[i].name);  //name是数组名,本身就已经是数组首元素的地址, 所以pArr[i].name 不能改成 &pArr[i].name

	printf("score = ");
	scanf("%f", &pArr[i].score);
}

//按学生成绩升序排序 冒泡算法
for (i=0; i<len-1; ++i)
{
	for (j=0; j<len-1-i; ++j)
	{
		if (pArr[j].score > pArr[j+1].score)  // >升序 <降序
		{
			t = pArr[j];    // 注意 t 的类型为  Struct Student 
			pArr[j] = pArr[j+1];
			pArr[j+1] = t;
		}
	}
}

printf("\n\n学生的信息是:\n");
//输出
for (i=0; i<len; ++i)
{
	printf("第%d个学生的信息是:\n", i+1);
	printf("age = %d\n", pArr[i].age);
	printf("name = %s\n", pArr[i].name);  
	printf("score = %f\n", pArr[i].score);

	printf("\n");
}

return 0;

}

总结:
对于一个人事管理或图书管理项目,分析流程:
第一步;存储
第二步:操作
第三步:输出
前两个过程最难、最核心 是“数据结构”研究的重点,一般都屏蔽了。
数组 和 变量 虽然都可以存储,但都不完美。
比如:人事关系图、交通图等,都不好用数组保存。
从事关系结构只能用“树”还保存,而对于 两个起终点:公交线路查询,实现时间最小/ 距离最短/ 花费最低 等功能,只能用“图”来存。
而图 和 树 都必须有指针知识,它们属于较高深的思想层次的东西。因此要学好数据结构必须要 懂得指针。

发布了43 篇原创文章 · 获赞 3 · 访问量 1344

猜你喜欢

转载自blog.csdn.net/it_xiangqiang/article/details/104294089