指针
一、指针类型的意义:
1、指针进行解引用操作时,能一次访问几个字节
2、指针进行+/-整数操作时,步幅不一样
例:
int* pa=&a;//pa+1到pa是四个字节
char* pb=&b;//pb+1到pb时一个字节
二、野指针:指向位置随机、不可知
野指针成因:
1、指针未初始化;
2、指针越界访问;
3、指针指向的空间释放
例:
int* test() { int a=10; return &a; } int main() { int* p=test();//此时p为野指针 return 0; }
三、指针运算
1、指针 +/- 整数
2、指针 - 指针——前提:两个指针指向同一空间
计算结果为两个指针之间元素的个数
3、指针的关系运算
二级指针:指向指针的指针
int a=10;
int* pa=&a;
int** ppa=&pa;//ppa就是二级指针
指针数组:存放指针的数组
结构体
声明:结构体类型是自定义的。
struct Book
{
char name[20];
short price;;
};b1,b2,b3
//此时b1,b2,b3是在建立结构体后在main函数外的结构体变量,是全局变量
int main()
{
struct Book b;
strcpy(b.name,"C语言");
b.price=55;
return 0;
}
typedef——重命名类型
typedef struct Book
{
.
.
.
}Book;
//此时strct Book b=Book b;
结构体成员的访问
struct Stu
{
char name[20];
short age;
};
//取出Stu中的数据,可以按下面方式取出
Stu.name
Stu.age
struct Stu* ps=&s;
ps->name,ps->age;
结构体传参
传参有两种方式,分别是直接把结构体的值传进去和把结构体的地址传进去。
在这两种方式中首选传址调用
函数传参的时候,参数是需要压栈的。
选择值传参,如果结构体过大,参数压栈系统开销大,会导致系统性能下降;反之,选择地址调用则因为地址大小在系统中固定,反而可以节省系统性能。
压栈
任何一次函数调用都要向内存申请空间,申请的是栈区。(栈——一种数据结构)
栈区的数据存储方式:
进:从下往上摞——压栈
出:从上往下拿
调试
Debug——调试版本
Release——发布版本(编译器会进行自动优化,是debug的优化版本,比如在数据存储上)
F10——逐过程
F9——切换断点
F11——逐语句
F5——开始调试
int main() { int i=0; int arr[10]={1,2,3,4,5,6,7,8,9,0}; for(i=0;i<=12;i++} { arr[i]=0; printf("%d\n",i); } return 0; }
上述代码会造成死循环。
原因在于:栈区的使用习惯是先用高地址,再用低地址。因此在栈区里存储数据时,先存储的是i的值(高地址),再存储的是数组arr[10]的值 (低地址,且内部从arr[0]到arr[9]的地址也是从低到高的),所以arr[12]是越界访问,但是arr[12]的地址和i的地址完全一致,当循环计算到arr[12]=0时,同时也给i的赋值为0,造成死循环。
在i和arr中间间隔多少个存储单元,不同的编译器的规则不一致,例如:VC6.0中是紧挨着的;VS中间隔2个整型;Linux中间间1个整型。
assert(dest!=NULL)——存储于头文件<assert.h>中
意义为:断言,即只有满足assert的条件程序才能正常运行,否则就会立即报错并终止程序。
const——所修饰的变量不能修改
const int num=10; //此时num不能改变,但是可以通过取地址进行改变 int* p=# *p=20; //此时num=20 //另外, const int* p;//限制*p int const* p;//限制p
函数中有指针一定要用assert,const,以防止在不知情的时候改变了值
数据在内存中的存储
数据类型:
1、内置类型:char int long short long long float double
可分为整型家族和浮点型家族。
在整型家族中可分为有符号和无符号,例:unsigned char(无符号)和sign char(有符号)
2、自定义类型
1)构造类型:数组类型、结构体类型、枚举类型、联合类型
2)指针类型
3)空类型:void,是一种类型但是又无意义,常用于函数的返回、函数的参数、指针
整型在内存中的存储
整型在内存中存储的是整型的补码
例:
int a=1-1;
在CPU中只有加法器,所以a=1+(-1)。
1 00000000 00000000 00000000 00000001 -1 10000000 00000000 00000000 00000001 原码相加结果是 10000000 00000000 00000000 00000010 = -2
1 00000000 00000000 00000000 00000001 -1 11111111 11111111 11111111 11111111 补码相加结果是 1 00000000 00000000 00000000 00000000 最前方的1因为位数不够舍去,所以最后结果是0
所以补码计算没有问题。
.
使用补码计算优点:
1、可以将符号域和数值域统一处理
2、加减法可以统一处理
3、原码求补码和补码求原码过程相同,无需额外硬件
.
存储有2种方式:
1、大端字节序存储方式
把一个数的低位字节序的内容放在高地址处,高位字节序的内容放在低地址处。
2、小端字节序存储方式
把一个数的低位字节序的内容放在低地址处,高位字节序的内容放在高地址处。
%u——打印无符号整型
浮点数在内存中的存储
浮点数的表达方式为:(-1)^S*M*2^E
所以在内存里只要存储下S、M、E三个值就可以表示任意浮点数
float类型:
float大小为4个字节,32个bit位,S占据一个bit位,E占据11个bit位,M占据23个bit位,总计32个bit位
double类型:
double大小为8个字节,64个bit位,S占据一个bit位,E占据11个bit位,M占据52个bit位,总计64个bit位