1.局部变量和数组在内存栈结构中的分配细节
#include <stdio.h>
#define ARRAY_SIZE 10
void natural_numbers(void) {
int i;
int array[ARRAY_SIZE];
i = 1;
while (i <= ARRAY_SIZE) {
array[i] = i - 1;
i = i + 1;
}
}
int main(){
natural_numbers();
printf("end");
}
内存中的分配图如下:
2.浮点数的二进制表示
以float为例,如下
#include <iostream>
#include <iomanip>
using namespace std;
void main()
{
float x = 1.3;
float y = 0.4;
cout << setprecision(10) << x<<endl;
cout<<setprecision(10) <<x + y<<endl;
if (x + y != 1.7)
cout << "addition failed?" << endl;
}
看输出结果
1.3
1.7
addition failed?
请按任意键继续. . .
是不是感觉结果在预测之中,但却一下子反应不过来?看着下图就明白了
float的二进制表示:
再来点更直观的
#include <iostream>
#include <iomanip>
using namespace std;
void main()
{
float x = 1.3f;
float y = 0.4;
cout << setprecision(10) << x<<endl;
cout<<setprecision(10) <<x + y<<endl;
}
输出结果
1.299999952
1.699999928
3.字节对齐
自然对齐:
对齐跟数据在内存中的位置有关。如果一个变量的内存地址正好位于它长度的整数倍,他就被称做自然对齐。比如在32位cpu下,假设一个整型变量的地址为0x00000004,那它就是自然对齐的。
为什么要字节对齐:
需要字节对齐的根本原因在于CPU访问数据的效率问题。比如地址为0x00000002,则CPU如果取它的值的话需要访问两次内存,第一次取从0x00000002-0x00000003的一个short,第二次取从0x00000004-0x00000005的一个short然后组合得到所要的数据,如果变量在0x00000003地址上的话则要访问三次内存,第一次为char,第二次为short,第三次为char,然后组合得到整型数据。而如果变量在自然对齐位置上,则只要一次就可以取出数据。
在VS工程属性->代码生成->C/C++->结构体成员对齐中可以设置具体几字节对齐。
int main()
{
struct {
char a, b;
double d;
int i;
} mystruct;
int e = 0;
return 0;
}
对于上面的结构体mystruct选用1字节对齐,可以看到结构体内部变量的地址紧密排列
4字节对齐,对应于32位cpu
8字节对齐,对应于64位cpu
4.++i和i++
#include <stdio.h>
int main(){
int x=0,y=0;
int a[5];
int b[5];
a[x++]=5;
b[++y]=5;
printf("x=%d,y=%d,a[0]=%d,a[1]=%d,b[0]=%d,b[1]=%d",x,y,a[0],a[1],b[0],b[1]);
return 0;
}
输出结果
x=1,y=1,a[0]=5,a[1]=2686868,b[0]=1982493216,b[1]=5
5.const相关
const int limit //整型变量limit不可二次赋值
const int *p //指针p指向的变量只读,p可以指向不同变量
int* const p //指针p指向的变量可以修改,p不能改变
6.static相关
int my_fn()
{
static bool my_var_initialized = false;
if (my_var_initialized)
printf("已初始化");
my_var_initialized = true;
}
不论 my_fn函数调用多少次,static bool my_var_initialized = false;只在第一次调用时候执行。
7.extern相关
extern关键字中是否extern int *p;能指向int p[5] = {100,123};
原因在于,指向类型T的指针并不等价于类型T的数组extern int *p ;说明p是一个指针变量而不是数组,因此与实际的定义不同,从而造成运行时非法访问
int main(){
extern int *p;
extern int a;
printf("%d\n", a);
printf("%d\n", p[1]);
}
int p[5] = {100,123};
int a = 100;
如上面这样写运行就会出错,应该extern int p[];
8.结构体
int main(){
struct bar
{
int b;
} bar;
bar.b= 10;
printf("%d\n",bar.b);
}
可以正常运行,输出10;声明结构体struct bar{};
结构体的类型为bar;
此时在c语言声明结构体变量struct bar b;
在c++中可以只用bar b;
声明struct bar{} bar;
此时在声明结构体类型bar的同时声明一个结构体变量bar;
此时在c++中也只能用struct bar b;声明另外的结构体变量
int main(){
struct bar
{
int bar;
} bar;
bar.bar= 10;
printf("%d\n",bar.bar);
}
不能正常运行,具体原因还不是很清楚