重返C语言(三)

指针

一、指针类型的意义:

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=&num;
*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位

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值