Chap 9:指针

来源:互联网 发布:linux安装exe软件 编辑:程序博客网 时间:2024/06/05 04:27

9.1 指针概念

预备知识

1 内存

总线:地址线(64M=26根) 数据线(32根) 控制线(读写)

地址:最小单位(0地址-0字节,1地址-1字节) 对齐(指令是按4字节对齐的)

2 指令

访存指令: 可以读写内存,用2个寄存器,一个存地址,一个放数据

LDR r0, [r1]// mem(r1) -> data(r0)STR r0, [r1]// data(r0) -> mem(r1)

怎么区分内存里面的数据和指令?

PC 程序计数器,一般初值为0,指向第一条指令除非碰到跳转指令,否则通常情况下,pc = pc + 4

3 变量

变量的本质是什么? 变量是C语言出现之后才有的

2个属性:变量名 int a = 100; 变量值 a + 2;

变量的本质是:在C语言中,由C编译器分配的,表示内存地址和存储单元内容的一种联系。

4 指针变量

指针的本质是什么? 指针也是一种变量,但这个变量值它就是内存地址。

0xbfxxxxxx 函数栈内,局部变量

0x8048xxx 数据段,全局变量

9.2 指针用法

1 指针变量定义:

int * p;

2 指针变量赋值:

p = &a;// goodp = 0x8048xxx;// no error, not good.

补充: int * p = &a; 应该看待为 int* p; 同时 p = &a; 而不是 p = &a;

3 指针变量使用:

*p = 200;// 赋值printf("%d", *p);// 读内容 p--;// 指针调整

4 指针变量类型:

char * p;short * p;int * p;指针变量的类型,决定了用 *p 去访问内存时候的读取的字节数

5 易混淆的错误

1) &a 的用法

&a 是一个常量(由编译器决定),代表内存地址&a 是一个32位整型,与a是什么类型无关&a = 100; 试图修改a的地址,这样的用法是错误的

2) p 的用法

int * p;*p = 1;// wrong!p = 1;// no error给指针本身赋值p=1是允许,但如果用指针取内容 *p=1 这是有风险的,会出段错误。

6 指针的重要用法-传参

用于获取用户输入

int a;scanf("%d", &a);int * p = &a;scanf("%d", p);

用于交换 swap 函数

void swap(int * a, int * b);// 可以用于修改上一级主调函数内部的变量的值

也可以通过传指针来获取多于1个以上的返回值

void decompose(double x, long * int_part, double * frac_part);

课堂练习: 请使用 char * 指针,对一个整型数 a = 0x12345678 修改为大端存储 提示: void swap(char * p1, char * p2);

7 指针的重要用法-const保护

int main(int argc, const char * argv[]);int printf(const char * format, ...);int scanf(const char * format, ...);char * strcpy(char * dst, const char * src);const int * p;// const 修饰 *p*p = 100;// error*(p+1) = 100;// next pos is error tooa = *p;// okp++;// ok

对比学习 const 的另一种用法

int * const p;// const 修饰 p*p = 100;// oka = *p;// okp++;// error

8 指针的重要用法-用作返回值

用传入的指针作为函数返回的指针,这是允许的。

重要结论: 如果是函数内部局部变量的地址作为指针返回,这是有风险的。(编译没错,但不好)

9.3 指针和数组

1 指针的算术运算

1) 加一个整数 p+1 (地址的增加值取决于指针的类型,整型指针则加4)2) 减一个整数 p-1(地址的减少值取决于指针的类型,整型指针则减4)3) 两个指针相减p1-p2(结果是两个指针之间的元素个数,而不是字节数)只有相同类型的指针才能作减法,不同类型不能相减,编译器会报error4) 自增加 p++, ++p5) 自减少 p--, --p6) 指针的比较(p1 > p2)

2 特殊类型指针 void * p

void * p = &a;// okp = 100;// oka = *p;// error*p = b;// errorp+1 (整数加1)// okp++/++p(加1)// okvoid * malloc(size_t);

3 指针名和数组名

int a[10];int * p = a;有何异同?a[0]vsp[0]=> 相同的*pvs *a=> 相同的*(p+1)vs *(a+1)=> 相同的p+1vsa+1=> 相同的p++vs a++=> 不同的(数组名是一个常量,不能修改)

4 指针和二维数组

int a[5][6];int * p = &a[0][0];int * p = a;int * p = a[0];int * p = a[2];

课堂作业: 请用指针实现对一个数组的调整,要求奇数在左边,偶数在右边。 要求: 尽可能不占用额外的存储空间。

编程方法

最重要的就是分解(设计好的函数),更重要的,在于设计程序时,从何种角度考虑解法?

判定标准:1) 逻辑简单 (嵌套少一些)能用1个while,就不用2个能不用else,就不用while, if, for 之间的递进逻辑少代码行数来作为参考2) 学会设计函数原则上,能够复用的函数是好的设计,能多次复用最好函数的功能最好少一些,一个函数只完成一个单一功能函数内部除了调试语句打印外,最好不打印3) 数据驱动编程《Unix 编程艺术》 -> Data Drive精心考虑所谓算法处理过程中要发生变化的数据是什么,以及何种条件下变化?

5 动态内存分配 allocate

堆heap 和 栈stack 的概念

&a = 0xbf9cb86c 栈空间 3G 向下p = 0x8129008 堆空间 向上&b = 0x804a018 数据段(全局变量)跟着代码段main = 0x8048414 代码段最小

常用函数

void * malloc(size_t size);void free(void * ptr);void * calloc(size_t nmemb, size_t size);void realloc(void * ptr, size_t size);void * alloca(size_t size);

原创粉丝点击