打印

C语言 指针学习笔记 连载

[复制链接]
3893|18
手机看帖
扫描二维码
随时随地手机跟帖
跳转到指定楼层
楼主
gdmgb520|  楼主 | 2011-3-20 22:15 | 只看该作者 回帖奖励 |倒序浏览 |阅读模式
本帖最后由 gdmgb520 于 2011-3-21 22:26 编辑

想去找一个嵌入式的工作,发现C语言太弱了。好好学学。
----------------------------------------------------------------------
指针与内存(1).rar (5.53 KB) word文档
---------------------------------------------------------------------

首先需要明确,指针就是地址,变量的指针就是变量的地址。存放变量地址的变量就是指针变量,它用来指向另一个变量。
#include <msp430x22x2.h>

char i;
char * pointer_1;
char a;

int j;
int * pointer_2;
int b;

int main( void )
{

// Stop watchdog timer to prevent time out reset


WDTCTL = WDTPW + WDTHOLD;

      

i = '0';


j = 5;


pointer_1 = &i;


pointer_2 = &j;


a = * pointer_1;


b = * pointer_2;

      
      

return 0;

}

初始化后内存分配如下:

内存地址
内存内容
变量名
0x200

Pointer_1


0x202

j


0x204

Pointer_2


0x206

b


0x208

i
0x209

a









程序运行情况分析:
所有变量定义为全局变量时为了在Watch窗口中方便查看。这样定义实际上对变量分配的内存空间是不一样的,回头再研究。全局变量的内存空间是分配在静态区的。在内存中数据的低字节存放在内存的低地址中。
首先,1617行,对i j 赋值,操作的结果是使0x208空间存入0x30,使0x202空间和0x2.3空间分别存入0x050x00
18,19行,给指针变量赋值,把i
j
的地址存入指针变量。操作的结果是内存空间0x2000x201分别变成了0x080x02,可看到对应的汇编代码是 mov.w #0x208&pointer_1,即把立即数移入pointer_1变量对应的内存空间。内存空间0x2020x203的内容更新为0x020x02

20,21行,指针运算,通过指针变量进行间接访问。把pointer_1变量中存放的指针(地址)所对应的数据存放到变量a中。操作结果是把0x2000x201内存中存放的数值 0x208)所对应的地址内的数据(0x30)存入0x209内存空间。21行,把内存0x204空间存放的地址(0x202)中的数据(0x0005)存入b变量(内存空间0x206)内,即0x20600x207空间为0x050x00

汇编代码如下:
main:
?cstart_end:

00E018
40B2 5A80 0120
mov.w
#0x5A80,&WDTCTL


i = '0';


00E01E
40F2 0030 0208
mov.b
#0x30,&i


j = 5;


00E024
40B2 0005 0202
mov.w
#0x5,&j


pointer_1 = &i;


00E02A
40B2 0208 0200
mov.w
#0x208,&pointer_1


pointer_2 = &j;


00E030
40B2 0202 0204
mov.w
#0x202,&pointer_2


a = * pointer_1;


00E036
421F 0200
mov.w
&pointer_1,R15


00E03A
4FE2 0209
mov.b
@R15,&a


b = * pointer_2;


00E03E
421F 0204
mov.w
&pointer_2,R15


00E042
4FA2 0206
mov.w
@R15,&b


return 0;


00E046
430C
clr.w
R12


00E048
4130
ret

__exit:

00E04A
120A
push.w
R10


00E04C
8321
decd.w
SP


00E04E
4C0A

mov.w
R12,R10


00E050
4A81 0000
mov.w
R10,0x0(SP)


小结:
做这样的理解,在C语言中,变量名就是内存地址,访问一个变量名实际上就是取得这个变量名所代表的地址空间中存放的数据,而指针变量也变量,所以访问指针变量也会得到指针变量名所代表的内存空间中的数据,而指针变量中存放的数据一个地址,通过使用“简介访问”运算符“*”就可以访问到这个地址内的数据,这样就取得了指针变量所指的数据。

相关帖子

沙发
linux达人| | 2011-3-21 21:18 | 只看该作者
接着学习

使用特权

评论回复
板凳
linux达人| | 2011-3-21 21:31 | 只看该作者
不过里面有错别字。

使用特权

评论回复
地板
gdmgb520|  楼主 | 2011-3-21 22:18 | 只看该作者
呵呵,谢谢!下面发第二篇。

使用特权

评论回复
5
gdmgb520|  楼主 | 2011-3-21 22:23 | 只看该作者
本帖最后由 gdmgb520 于 2011-3-21 22:24 编辑

论坛发帖对格式支持不是很好,而且图片不能直接贴上来的,一个一个上传麻烦。所以直接上传了word
指针学习(2).rar (31 KB)
以下是文档内容(不含图片)
-----------------------------------------------------------------

感觉使用EW430学习C语言指针真的很不错,可以很好的跟踪程序,可以看到内存的变化,从而加深对指针的理解。今天记一下“指向函数的指针和指向函数的指针作函数的参数”的学习情况。参考书依然是谭浩强老师的C语言课本。先学习了课本10.5节。以该节最后的一个问题作为题目进行了实践。编写如下代码: Main.c int main( void ) { extern float f1(float x,float y); extern float f2(float x,float y); extern float integral(float a,float b,float (*fun)(float,float)); // Stop watchdog timer to prevent time out reset WDTCTL = WDTPW + WDTHOLD; float integ; float (*pf)(float,float); //定义一个指向函数的指针,该类型的函数返回值是float,且有两个float类型的参数。 //求积分 pf=f1; //把f1函数的入口地址赋值给函数指针pf integ = integral(0,1,pf); //函数指针作为函数的参数 integ++; pf = f2; integ = integral(0,1,pf); integ++; } Integral.c //该函数的第三个参数是一个指向函数的指针 float integral(float a,float b,float (*fun)(float,float)) { float result; result = (*fun)(a,b); //通过指向函数的指针调用函数 return(result); } float f1(float x,float y) { return(0.5*y*y + y - 0.5*x*x - x); } float f2(float x,float y) { return(y*y + 3*y - x*x -3*x); } 在 IAR EW IDE下,进入debug模式。程序初始化以后可以在Watch窗口中看到 即,函数f1的入口地址是在FLASH中的0xE44C,函数f2的入口地址是0xE3C0。那么我们验证一下。在 Disassembly窗口中我们找到0xE44C地址,在这里我们可以看到实际的FLASH中存放的是什么东东。找到该地址,可以看到: 可以看到0xE44C确实是函数f1() 的入口地址,函数的第一条语句是把寄存器R10的值压入堆栈。 好,下面看第一行代码,pf=f1。在执行该语句之前可在watch窗口中看到pf 的值为unavailable,该语句的作用是把函数f1的入口地址存入pf这个指向函数的指针变量中。那么执行该语句后pf的值应该等于0xE44C。执行该语句,然后再看watch窗口: 可以看到运行结果与我们推测的一致。然后程序进入下一行,integ = integral(0,1,pf);执行该语句后程序跳到integral()函数中result = (*fun)(a,b);语句处,执行该语句程序跳转到f1函数处,在Disassembly窗口中可以看到程序指针跳到了0xE4C处。执行完后程序调转到主程序的integ++;行。这样就完成了一次调用。

使用特权

评论回复
6
gdmgb520|  楼主 | 2011-3-22 22:01 | 只看该作者
指针学习(3).rar (159.99 KB)

--------------------------------------------------------------
指向指针的指针

继续使用EW430学习C语言。又有新发现,是430的地址空间(address space)。根据msp430_x2xx_family_user_guider_slau144e 数据手册的说明,430x2xx系列的内存空间如下:

而,在我的这个工程中我选择的targetmsp430F2232,该芯片为8kB+256B Flash Memory 512B RAM
1.
SFR空间。
从上图看,SFR的地址空间是0h – 0Fh,在EW430 IDE中实际上是把外围设备的寄存器也作为SFR的,因为在IDE中看到的SFR空间是0h – 01FFh


2.
RAM空间
数据手册上说RAM空间从0200h空间开始,结束地址取决于RAM的大小,那么2232RAM512B,那结束地址应该是03FFh。这与在IDE中实际看到的相符。

3.
FLASH空间
数据手册上说,Flash的开始地址决定于Flash空间的大小,并因器件类型改变,结束地址是0x1FFFFh。但是在IDE中实际看到的Flash结束地址是0xFFFFh,起始地址是0xE000h,计算(0xFFFFh – 0xE000h + 1/ 1024 = 8k。这与2232
8k Flash是相符的。


通过上面的分析,就把430 Memory捋了一遍。但我们现在要讨论的问题是指向指针的指针。
通过分析,发现一个问题。在Disassembly窗口中看到的内容是编译器把他翻译成了指令显示的。待会就会看到。

好,下面看程序。代码如下:放在main函数中的

//
指向指针的指针


char *name[] = {"Follow me","BASIC","Great Wall","FORTRAN"};//
定义一个指针数组


char **p4;
//
定义一个指针,该指针指向指针变量,即是一个指向指针的指针


int i2;


for (i2=0;i2<4;i2++)


{


p4 = name+i;

asm("NOP");


*(*(p4))++;


}

执行程序第一行后,可在watch窗口中查看name变量的相关信息:

name是一个数组变量,可以看到作为一个变量,它被分配了实际的内存空间,空间地址为0x03D20x03D9,显然,这个地址是RAM空间地址。那么我们在Memory窗口中找到0x03D2可以看到

由于name是指针数组,那么name中存放的显然应该是地址,在watch窗口中可以看到name[0]中存放的是0xE020,而0xE020这个地址所指向的内存空间的内容是字符”F”。那我们再在Memory窗口中找到0xE020空间

可以看到从0xE020地址开始,依次存放的是”Follow me\0”,共占用10个字节。从0xE02A开始为下一个字符串”BASIC”。这与watch窗口中看到的是一致的。
下面再进入for循环,执行 p4 = name+i; 可以在watch窗口中看到p4被分配的空间是R11p4的内容是0x03D2,而0x03D2内存空间存放的内容是0xE020,这个地址的空间的内容是什么呢?前面已经看过了,这个地址的内容是字符’F’,所以对p4使用两次间接访问运算即可得到字符’F’

执行 *(*(p4))++ 语句后0x03D2的内容变为0xE021,即p4所指的空间的内容加了1

这里注意*(*p4)++ *(*p4++) 的区别。
*(*p4)++:先取得*(*p4)的值,即p4中所存放的指针所指向的内容,再对*p4 的内容++
可以从上图中看到p4的位置是R11p4的内容是0x03D2,而*p4的内容是p4所指向的内容,即地址0x03D2所存放的内容,即0x0E20,那么结果应该是0x0E21。运行后:

可以看到,实际上name指针数组的内容发生了变化,name[0]指向了0xE021,这是因为之前把name+i赋值给了p4,而这种赋值实际上传递的是地址,所以改变p4所指向的内容也就是改变name+i所指向的内容。
*(*p4++):先取得*(*p4)的值,然后p4的值++,即p4会等于0x3D4,即指向下一个字符串。运行后结果如下:

使用特权

评论回复
7
sysdriver| | 2011-3-25 23:19 | 只看该作者
呵呵,写程序的人,很容易理解指针的。
2个属性:地址 和  内容
地址你不知道吗?ROM中的地址 或 RAM中的地址,写程序的人没有不知道的。
内容就更简单了,所以,指针的学习本质就2个,没必要附带这么多东西。

使用特权

评论回复
8
416775364TP| | 2011-3-26 19:34 | 只看该作者
MARK  ~~~~~~~~

使用特权

评论回复
9
老鱼探戈| | 2011-3-30 10:30 | 只看该作者
我还直播呢................

使用特权

评论回复
10
7_七画| | 2011-3-31 00:03 | 只看该作者
分享很好

使用特权

评论回复
11
lixupengIC| | 2011-4-1 22:05 | 只看该作者
学习!!!

使用特权

评论回复
12
shihun009| | 2011-4-2 13:09 | 只看该作者
谢谢!!!

使用特权

评论回复
13
gdmgb520|  楼主 | 2011-4-12 22:43 | 只看该作者
有人说,C语言,十年以下难说精通。

谭浩强的C语言指针,结构体 我才读1遍,至少还要读9遍吧。

使用特权

评论回复
14
johnwjl| | 2011-4-14 15:51 | 只看该作者
如果只读谭浩强的书,十年也不能说精通。

使用特权

评论回复
15
521ycd| | 2011-4-14 22:53 | 只看该作者
厉害!

使用特权

评论回复
16
shiwilson| | 2011-4-14 23:23 | 只看该作者
留下脚印

使用特权

评论回复
17
gdmgb520|  楼主 | 2011-4-15 12:56 | 只看该作者
如果只读谭浩强的书,十年也不能说精通。
johnwjl 发表于 2011-4-14 15:51


兄弟不妨指点下,那几本书市比较经典的。
谢谢!

使用特权

评论回复
18
xingaiking| | 2011-4-15 14:35 | 只看该作者
我也在学习~~呵呵~~~

使用特权

评论回复
19
xieyue1975| | 2013-6-26 09:56 | 只看该作者
很受用

使用特权

评论回复
发新帖 我要提问
您需要登录后才可以回帖 登录 | 注册

本版积分规则

个人签名:了解新东西才知道自己的不足。 www.elecbench.com

67

主题

452

帖子

1

粉丝