赞
踩
坚持就是胜利
前面我们学习了基本的内置类型,以及它们所占存储空间的大小。
char //字符数据类型 1 字节
short //短整型 2 字节
int //整型 4 字节
long //长整型 4/8 字节 sizeof(long) >= sizeof(int)
long long //更长的整型 8 字节
float //单精度浮点数 4 字节
double //双精度浮点数 8 字节
1、什么是 内置类型?
答:C语言本身自带的类型
2、为什么整型分为 short int long?
答:比如存储年龄 age,用 int 太大了,用 short 就可以。short 取值范围:-32768 ~ 32767
#include <limits.h> //注意头文件
//在此头文件下,可以查询内置类型的最大值,最小值
int main()
{
INT_MAX; //转到定义
return 0;
}
类型的意义:
1、使用这个类型开辟内存空间的大小(大小决定了使用范围)。
2、如何看待内存空间的视觉。
有符号数、无符号数,只针对 整型。
浮点数 没有 有符号数和无符号数 的说法和区分。
//字符 char 在存储的时候,存储的是 ASCII值,是整型所以归类的时候,放在整型家族。
char
unsigned char
signed char
short
unsigned short
signed short
int
unsigned int
signed int
long
unsigned long [int]
signed long [int]
对于整型家族的类型来说,有:“有符号”和“无符号”的区分
1、char 到底是 signed char 还是 unsigned char 不确定
(C语言没有给出明确的规定)
(char 在 VS 上是 signed char)
2、short == signed short
unsigned short
3、int == signed int
unsigned int
4、long == signed long
unsigned long
float
double
1、数组类型
2、结构体类型 struct
3、枚举类型 enum
4、联合类型 union
//int arr1[10] ——> int [10]
//int arr2[20] ——> int [20]
//char arr3[10] ——> char [10]
//数组 arr1 和 arr2 和 arr3 类型各不相同
1、int* pi;
2、char* pc;
3、float* pf;
4、void* pv;
5、结构体指针类型;
void 表示 空类型(无类型)
通常应用于 函数的返回类型、函数的参数、指针类型。
//void* ps;
一个变量的创建,是要在内存中开辟空间的。
空间的大小,是根据不同的类型而决定的。
计算机中的整数有 3 种 2进制 表示方法,即原码、反码、补码。
三种表示方法均有 符号位 和 数值位 两部分,符号位都是用 0 表示 “正”,用 1 表示 “负”,
而数值位:
正整数的原码、反码、补码都相同。
负整数的三种表示方法各不相同。
原码
直接将数值按照正负数的形式翻译成二进制就可以得到原码
反码
将原码的符号位不变,其他位依次按位取反就可以得到反码
补码
反码 + 1 就得到补码
对于整型来说:数据存放内存中,其实存放的是补码。
为什么呢?
在计算机系统中,数值一律用补码来表示和存储。
原因在于,使用补码,可以将符号位和数值域统一处理;
同时,加法和减法也可以统一处理(CPU只有加法器),
此外,补码与原码相互转换,其运算过程是相同的,不需要额外的硬件电路。
为什么用 补码 计算,而不用 原码 计算? 答:用 原码 计算,有些运算会出错 计算 1 - 1 (由于CPU只有加法器,所以 1 - 1 就是 1 + (-1)) 1+(-1) 原码 计算 00000000 00000000 00000000 00000001 数值 1 10000000 00000000 00000000 00000001 数值 -1 10000000 00000000 00000000 00000010 相加等于 -2 ,计算错误 补码计算:将 符号位 和 数值域 统一处理 00000000 00000000 00000000 00000001 数值1原码 00000000 00000000 00000000 00000001 数值1反码 00000000 00000000 00000000 00000001 数值1补码 10000000 00000000 00000000 00000001 数值-1原码 11111111 11111111 11111111 11111110 数值-1反码 11111111 11111111 11111111 11111111 数值-1补码 00000000 00000000 00000000 00000001 数值1补码 11111111 11111111 11111111 11111111 数值-1补码 1 00000000 00000000 00000000 00000000 只能存32位 00000000 00000000 00000000 00000000 结果为 0 ,正确
什么是 字节序?
答:以 字节 为单位,讨论存储顺序的。
大端(存储)模式,是指数据的低位保存在内存的高地址中,而数据的高位,保存在内存的低地址中。
小端(存储)模式,是指数据的低位保存在内存的低地址中,而数据的高位,保存在内存的高地址中。
为什么会有大小端模式之分呢?
这是因为在计算机系统中,我们是以字节为单位的,每个地址单元都对应着一个字节,一个字节为 8 bit。但是在C语言中除了8 bit 的 char 之外,还有 16 bit 的 short型 ,32 bit 的 long型 (要看具体的编译器),另外,对于 位数 大于8位 的处理器;例如 16位 或者 32位 的处理器,由于寄存器宽度大于 一个字节,那么必然存在着一个如何将多个字节安排的问题。因此就导致了大端存储模式和小端存储模式。
例如:一个 16bit 的 short型 x,在内存中的地址为 0x0010,x 的值为 0x1122,那么 0x11 为高字节,0x22 为低字节。对于大端模式,就将0x11 放在低地址中,即 0x0010 中,0x22 放在高地址中,即 0x0011 中。小端模式,刚好相反。
我们常用的 x86 结构 是 小端模式,而 KEIL C51 则为大端模式。很多的 ARM,DSP 都为 小端模式。有些 ARM 处理器 还可以由 硬件 来选择是大端模式还是小端模式。
由于 int a;
所以 &a 是 int* 类型
需要判断 int a 的 第1个字节
将 int* 转换为 char* 即可!
再 解引用*
#include <stdio.h> int main() { int a = 1; //char* p = &a; //这么写是错误的,因为 &a 是 int* 类型 char* p = (char*)&a; if (*p == 1) { printf("小端存储\n"); } else { printf("大端存储\n"); } return 0; }
#include <stdio.h>
int main()
{
int a = 1;
if (*(char*)&a == 1)
{
printf("小端存储\n");
}
else
{
printf("大端存储\n");
}
return 0;
}
#include <stdio.h> int check_sys() { int a = 1; if (*(char*)&a == 1) //再精简为:if(*(char*)&a) { return 1; } else { return 0; } } int main() { int ret = check_sys(); if (ret == 1) { printf("小端存储\n"); } else { printf("大端存储\n"); } return 0; }
#include <stdio.h> int check_sys() { int a = 1; return *(char*)&a; //一步步精简成这样 } int main() { int ret = check_sys(); if (ret == 1) { printf("小端存储\n"); } else { printf("大端存储\n"); } return 0; }
对于整型家族的类型来说,有:“有符号”和“无符号”的区分
1、char 到底是 signed char 还是 unsigned char 不确定
(C语言没有给出明确的规定)
(char 在 VS 上是 signed char)
2、short == signed short
unsigned short
3、int == signed int
unsigned int
4、long == signed long
unsigned long
#include <stdio.h>
int main()
{
char a = -1;
signed char b = -1;
unsigned char c = -1;
printf("a=%d,b=%d,c=%d\n", a, b, c); // a=-1 b=-1 c=255
return 0;
}
//知识点(之前学习过) //1、长度大于 int 的,就不需要进行 ”整型提升“ //2、有符号的整型提升:高位补充符号位 //3、无符号的整型提升,高位补 0 //4、%d 十进制的形式打印有符号整型整数 //正确的解答过程 //整数 -1 存入 char a 中 //整数 -1 原码:10000000 00000000 00000000 00000001 // 反码:11111111 11111111 11111111 11111110 // 补码:11111111 11111111 11111111 11111111 //截断,因为只有 1 字节 才能存入 char a 中:11111111 //%d 十进制的形式打印有符号整型整数 //对char a 进行 整型提升 //补码:11111111 11111111 11111111 11111111 //反码:10000000 00000000 00000000 00000000 //补码:10000000 00000000 00000000 00000001 //结果显示:-1 //signed char b 和 char a 是一样的解答过程 //在本电脑中的VS编译器,char 类型是 signed char //unsigned char c //整数 -1 存入 unsigned char c 中 //整数 -1 原码:10000000 00000000 00000000 00000001 // 反码:11111111 11111111 11111111 11111110 // 补码:11111111 11111111 11111111 11111111 //截断,因为只有 1 字节 才能存入 unsigned char c 中:11111111 //无符号整型提升,高位补 0 //补码:00000000 00000000 00000000 11111111 //%d 十进制的形式打印有符号整型整数 //因为此时已经按照 %d 的形式输出,最高位为 0,是 正数 // 正数的原码、反码、补码相同 //原码:00000000 00000000 00000000 11111111 //结果:255
#include <stdio.h>
int main()
{
char a = -128;
printf("%u\n", a);
return 0;
}
//知识点: //%u 十进制的形式打印无符号的整型整数 //整数-128,存入 char a 中 //-128补码:10000000 00000000 00000000 10000000 // 反码:11111111 11111111 11111111 01111111 // 补码:11111111 11111111 11111111 10000000 //截断:10000000 存入 char a 中 //%u 十进制的形式打印无符号的整型整数 //整型提升,也就是对 char a 进行整型提升 //char a 是有符号的,符号位是 1 //补码:11111111 11111111 11111111 10000000 //%u 是无符号数,内存中就没有符号位,内存中存入的就是:11111111 11111111 11111111 10000000 //无符号数可以看成 正数,补码,反码,原码都是一样的 //结果就是:11111111 11111111 11111111 10000000 //十进制就是:4294967168
#include <stdio.h>
int main()
{
char a = 128;
printf("%u\n", a);
return 0;
}
//知识点: //%u 十进制的形式打印无符号的整型整数 //整数128,存入 char a 中 //128补码:00000000 00000000 00000000 10000000 //正数的原码、反码、补码相同 //截断:10000000 存入 char a 中 //%u 十进制的形式打印无符号的整型整数 //整型提升,也就是对 char a 进行整型提升,char a 是有符号的,符号位为 1 //char a 是有符号的,符号位是 1 //补码:11111111 11111111 11111111 10000000 //%u 是无符号数,内存中就没有符号位,内存中存入的就是:11111111 11111111 11111111 10000000 //无符号数可以看成 正数,补码,反码,原码都是一样的 //结果就是:11111111 11111111 11111111 10000000 //十进制就是:4294967168
#include <stdio.h>
int main()
{
int i = -20;
unsigned int j = 10;
printf("%d\n", i + j);
return 0;
}
//知识点: //1、补码得到原码有两种方式: // (1)补码-1得到反码,反码取反得到原码 // (2)补码先取反再加1,得到原码 //整数-20原码:10000000 00000000 00000000 00010100 // 反码:11111111 11111111 11111111 11101011 // 补码:11111111 11111111 11111111 11101100 //unsigned int j = 10原码:00000000 00000000 00000000 00001010 //无符号数的反码、原码、补码相同 // 补码:00000000 00000000 00000000 00001010 //i+j 补码相加 11111111 11111111 11111111 11101100 // 00000000 00000000 00000000 00001010 // 11111111 11111111 11111111 11110110 //截断:11111111 11111111 11111111 11110110 // (1)补码-1得到反码,反码取反得到原码 //补码:11111111 11111111 11111111 11110110 //反码:11111111 11111111 11111111 11110101 //原码:10000000 00000000 00000000 00001010 //结果:-10 //(2)补码先取反再加1,得到原码 //补码:11111111 11111111 11111111 11110110 //取反:10000000 00000000 00000000 00001001 //+1 :10000000 00000000 00000000 00001010 //结果:-10
#include <stdio.h>
#include <windows.h>
int main()
{
unsigned int i;
for (i = 9; i >= 0; i--)
{
printf("%u\n", i);
Sleep(1000); //单位:毫秒 5000毫秒
}
return 0;
}
死循环,因为 unsigned int i 是 恒大于等于零 的。
//9 8 7 6 5 4 3 2 1 0 的原码、反码、补码 相同
//0 原码:00000000 00000000 00000000 00000000
//-1 原码:10000000 00000000 00000000 00000001
// 反码:11111111 11111111 11111111 11111110
// 补码:11111111 11111111 11111111 11111111
//0-1 0+(-1)
//0 补码:00000000 00000000 00000000 00000000
//-1补码:11111111 11111111 11111111 11111111
//相加 :11111111 11111111 11111111 11111111
//以 %u 输出:4294967295
#include <stdio.h> #include <string.h> int main() { char a[1000]; int i; for (i = 0; i < 1000; i++) { a[i] = -1 - i; printf("%d\n", a[i]); } printf("%d\n", strlen(a)); //答案是:255 return 0; }
结果:255
原因:strlen() 统计的是 ‘\0’,之前出现的数字的个数!!!
#include <stdio.h>
unsigned char i = 0; //unsigned char 的取值范围:0 ~ 255
int main()
{
for (i = 0; i <= 255; i++) //此时:i<=255 条件恒成立,所以死循环
{
printf("hell0 world\n"); //死循环
}
return 0;
}
微软雅黑字体
黑体
3号字
4号字
红色
绿色
蓝色
Copyright © 2003-2013 www.wpsshop.cn 版权所有,并保留所有权利。