数据类型
C 语言是一个有类型的语言,使用变量必须定义确定类型。
整数:char, short, int, long, long long, bool
浮点数:float, double, long double
指针
自定义类型
数据类型的不同
在64位机器上:
整数和浮点数 在内存中的形式都是以二进制的形式存在的,但是整数是真实的二进制数字 可以直接拿来运算,而浮点数是一种编码方式,不能直接运算。通常来说CPU上专门有一个硬件来处理浮点数运算。
sizeof
这个方法可以返回某个类型或者某个变量在内存中所占据的字节数
sizeof(int);
int a = 0;
sizeof(a);
整数
int 的特殊意义
int 和 long 的长度取决于编译器和CPU,通常的意义是表示 "一个字" 的长度。
什么叫一个字?
CPU和内存读取数据模型:
CPU [register] RAM
CPU中的寄存器通过总线和内存进行数据读写,现在的CPU的寄存器通常这个大小是 32bit 或者 64bit,这个大小就是一个字的长度,通常就代表 int 的长度。
内部的表达
在计算机中任何数据都是二进制数据,这个数据是什么取决与我们怎么看它。
1个字节可以表达的数范围:
因为char刚好就是一个字节,我们就拿char来实验一下:
因为一个字节,只能表达 256 个数字,那么 char 的表示数的范围是 (0 ~ 255) 还是可以表示负数呢?
char c = -1;
printf(c="%d\n", c);
c=-1
测试代码可以看出 char 是可以表示负数的。
那么负数怎么表示呢?对应的二进制又是怎样的呢?
我们这样这样想 -1 + 1 = 0,那么:
????????
这样看就很明显了:
由于 超出了 1个字节的范围,所以溢出了就变成了
。
所以虽然内存中的数据都是
,但是当被当成原码看的时候是
255
,当成补码看的时候就是
-1
。
signed & unsigned
signed, unsigned 数据类型的修饰符,只能修饰 整数类型的数据,表示是否带符号,也就是不用补码来表示负数了。
8进制 16进制
int i = 012; // 八进制
int j = 0x12; // 十六机制
printf("i=0%o,j=%x\n", i, j);
浮点数
精度误差
float f = 1.123f;
float ff = 2.123f;
float sum = f + ff;
if (sum == 3.246f) {
printf("相等\n");
} else {
printf("不相等 sum=%.10f, sum=%f\n", sum, sum);
}
不相等 sum=3.2459998131, sum=3.246000
浮点数是不准确,有效位数是有限的,所以在处理钱的问题上,不要使用小数点来表示角分,而是转换成最小单位来计算,比如: 1.23元 = 123分,这样转换成整数计算就不会又误差了。
指针
指针是什么? 指针就是一个内存地址,代表的就是一块内存空间。
// 定义一个 int类型的变量 i 值为5
int i = 5;
// &i 中的 &为取地址符,可以得到 i 的地址,%x 为十六进制输出
printf("i的地址 %p\n",&i);
关于怎么快速学C/C++游戏编程,有什么方法,这个问题,想必大家都已经心中有数了,打算深入了解这个行业的朋友,可以加下小编的C/C++游戏编程学习群:626+871+916,邀请码(往事)不管你是小白还是大牛,小编我都欢迎,不定期分享干货,包括小编自己整理的一份2018最新的C/C++资料和0基础入门教程,欢迎初学和进阶中的小伙伴。
每天晚上20:00我都会开直播给大家分享C/C++游戏编程学习知识和路线方法,群里会不定期更新最新的教程和学习方法(进群送2018C/C++游戏编程学习教程),大家都是学习C/C++的,或是转行,或是大学生,还有工作中想提升自己能力的前端党,如果你是正在学习C/C++的小伙伴可以加入学习。最后祝所有程序员都能够走上人生巅峰,让代码将梦想照进现实,非常适合新手学习,有不懂的问题可以随时问我,工作不忙的时候希望可以给大家解惑。
// 指针变量 定义一个int* 类型的变量p
int* p;
// 把 i 的地址给 p,现在 p 就存放的 i 的地址
p = &i;
printf("i=%d\n",i);
// *p --> 当指针变量前面有*的时候,表示取这个指针变量所存放的地址里面对应的数据
printf("*p的值%d\n",*p);
指针占多少字节
int i =3;
double d = 3.141692;
float f = 3.1423;
char c ='B';
int* ip = &i;
double* dp = &d;
float* fp = &f;
char* cp = &c;
printf("int 类型指针变量的长度为 %d\n",sizeof(ip)); // --> 4
printf("double 类型指针变量的长度为 %d\n",sizeof(dp)); // --> 4
printf("float 类型指针变量的长度为 %d\n",sizeof(fp)); // --> 4
printf("char 类型指针变量的长度为 %d\n",sizeof(cp)); // --> 4
数组
数组变量是特殊的指针
无需用 & 取地址
int a[10]; int *p = a;
但是数组的单元表达的是变量,所以是需要用 & 取地址
*a == &a[0]
[]
可以对数组做,也可以对指针做。
p[0]; a[0];
*
也可以对数组做
*a = 0;
数组变量是一个 const 的指针,所以不能被再次赋值,只能初始化。
int b[] = a;
// int b[] === int * const b
指针运算
// 指针的运算和数组都是紧密关联的
char* pChar = &arr[2];
printf("pChar的内存地址:%#X,对于的值为:%c\n", pChar, *(pChar));
printf("pChar + 1 的内存地址:%#X,对于的值为:%c\n", pChar + 1, *(pChar + 1));
// pChar的内存地址:0X28FF22,对于的值为:c
// pChar + 1 的内存地址:0X28FF23,对于的值为:d
// 指针的运算 按照 约定好的数据类型, 偏移相对应的内存空间的大小 !
printf("dist=%c\n", &arr[0] - &arr[2]); // dist=2
// 指针减法 返回的值是距离,并不是返回整数相减的结果
指针类型转换
int* p = &i;
void* q = (void*) p;
函数指针
void print(char const * str) {
printf("%s\n", str);
}
void sayHi(void (* p)(char const * str)) {
p("hi2");
}
sayHi(print);
指针的运用
需要传入较大的数据时用作参数:传数组
对数组的操作
函数返回值不止一个结果的时候
需要用函数来修改不止一个变量:swap
动态申请内存
函数指针相当于java的回调
动态内存分配
#include
// 申请 n个int 大小内存,失败返回 0
int* p = (int*) malloc(n * sizeof(int));
// 回收
free(p);
字符串
声明字符串的三种方式
char c[] = {'H', 'e', 'l', 'l', 'o', '\0'};
printf("%s\n", c);
char c2[6] = {'H', 'e', 'l', 'l', 'o'};
printf("%s\n", c2);
char* str = "Hello World!";
printf("%s\n", str);
字符串数组
char s[][] = {"Hello", "Wrold"};
char *ss[] = {"Hello", "Wrold"};
字符串操作
#include
在标准函数库
string.h
里面有关于 string 处理相关的函数库。
具体方法查找:http://www.runoob.com/cprogramming/c-standard-library-string-h.html
结构类型
枚举
enum Type {
Open,
Close
};
enum Type t = Open;
结构体
struct Position {
int x;
int y;
};
结构体的内存大小为所有成员的大小之和
结构体初始化
struct Position p = ;
struct Position q;
q.x = 2;
q.y = 2;
结构体指针
struct Position* p = &q;
(*p).x = 1;
C的
操作符,其实就是指针取值的简写。
结构体运算
p = (struct Position) ; // 相当于 p.x = 1; p.y = 2;
p1 = p2 // 相当于 p1.x = p2.x; p1.y = p2.y
联合体
union Value {
int x;
float y;
char z;
double q;
};
union Value v;
v.x = 1;
v.z = 'A';
v.y = 0.1;
v.q = 0.2;
printf("%zu\n", sizeof(union Value));
联合体的大小,会存在内存对齐的情况,其内存大小等于成员中最大的那个属性的长度,并且因为联合体内的成员是共用内存的,所以只会安全的保存一个值。
1, 0.000000, , 0.000000
65, 0.000000, A, 0.000000
8
别名
typedef int Age;
typedef int* AgeP;
struct Man {
char* name;
};
typedef struct Man Student, *StudentP;
Age a = 1;
printf("%d\n", a);
AgeP p = &a;
printf("%d\n", *p);
Student student;
student.name = "Jack";
printf("%s\n", student.name);
StudentP sp = &student;
printf("%s\n", sp->name);
1
1
Jack
Jack
给结构体取别名,可以让结构体的使用更加接近于Java。
宏定义
#define value
下面这个是 标准 C header 的宏定义,为了解决头文件的导入死循环
#ifndef __X__HEADER__
#define __X__HEADER__
void hello();
#endif
在C99之前,C语言没有
const
关键字,所以定义常量通常也是用宏定义
#define PI 3.14159
编译器处理宏定义其实就是最原始的文本替换。
double x = 2 * PI;
double x = 2 * 3.14159;
带参数的宏
#define cube(x) ((x)*(x)*(x))
printf("%d\n", cube(2)); // 8
end
领取专属 10元无门槛券
私享最新 技术干货