C语言深度剖析之—指针与内存地址(函数指针,普通指针,指针数组,数组的指针,指针的指针)

来源:互联网 发布:淘宝充流量一直不到账 编辑:程序博客网 时间:2024/05/01 01:24

1. int* p=NULL 与*p=NULL的区别:

1)int* p=NULL,

定义一个指针,其指向的内存保存的是int型的数据,同时p的值为0X00000000(即完成一次初始化);

其中,p是一个指针变量,p中内存地址处的内存是p指向的内存。

所以,*前面的类型只是说明内存数据的类型,不管怎么样的指针类型,大小都是4bytes;

2)int* p ; 成为野指针

*p =NULL;

定义一个指针,指向内存保存的是int型的数据,但是p并没有赋初值;(即指向内存的地址不明确,可能指向一个非法地址);*p=NULL,将p指向的内存赋值;

int a=10;

int* p = &a; → *p=10;

*p =NULL; → *p=0; (在c中,#define NULL 0)

2. 如何将数值存储到指定的内存地址: 通过一个指针,向其指向的内存地址写入数据;

例:1. 在内存0x12ff7c中写入0x100;

int* p=(int*)0x12ff7c

*p=0x100;

或者:

*(int*) 0x12ff7c = 0x100;

2,让程序跳转到绝对地址是0x100000去执行,应该怎么做?

转换成函数指针:(void(*)())0x100000;

调用执行: *((void(*)())0x100000 )();

先看一道常见的面试题: 用变量a给出下面的定义

a) 一个整型数(Aninteger)

b) 一个指向整型数的指针(A pointer to an integer)

c) 一个指向指针的的指针,它指向的指针是指向一个整型数(A pointer to a pointer to an integer)

d) 一个有10个整型数的数组(An array of 10 integers)

e) 一个有10个指针的数组,该指针是指向一个整型数的(An array of 10 pointers to integers)

f) 一个指向有10个整型数数组的指针(A pointer to an array of 10 integers)

g) 一个指向函数的指针,该函数有一个整型参数并返回一个整型数(A pointer to a function that takes an integer as an argument andreturns an integer)

h) 一个有10个指针的数组,该指针指向一个函数,该函数有一个整型参数并返回一个整型数( An array of ten pointers to functions that take an integer argumentand return an integer )

答案是:

a) int a; // An integer

b) int *a; // A pointer to an integer

c) int **a; // A pointer to a pointerto an integer

d) int a[10]; // An array of 10integers

e) int *a[10]; // An array of 10pointers to integers

指针数组:【】的优先级高于*;首先a[10]构成一个数组,数组元素类型是 int*

f) int (*a)[10]; // A pointer to anarray of 10 integers

数组指针:()的优先级高于【】;a是一个指针,int修饰无名数组元素,指针a指向含有10个元素的数组;

g) int (*a)(int); // A pointer to afunction a that takes an integer argument and returns an integer

h) int (*a[10])(int); // An array of 10pointers to functions that take an integer argument and return an integer

int(*s[10])(int)表示的是什么啊

【标准答案】int(*s[10])(int) 函数指针数组,每个指针指向一个int func(int)的函数。

函数指针数组运用实例:

char * (*pf[3])(char * p);
pf[0] = fun1; // 可以直接用函数名
pf[1] = &fun2; // 可以用函数名加上取地址符
pf[2] = &fun3;
pf[0]("fun1");
pf[0]("fun2");
pf[0]("fun3");

3. 什么是函数指针?

使用指针时,需要一把钥匙*,来取指向内存的数值;

例:char * (*pf)(char * p1,char * p2);
pf = &fun;
(*pf) ("aa","bb");

(*pf)取出存在这个地址的函数,再调用这个函数;

函数名在编译后成为一个地址,所以给函数指针赋值时可以直接用函数名fun,或者&fun;

再分析一题:

void (*p)(); -> *(int*)&p=(int)Function; -> (*p)();

定义一个函数指针-》将函数的入口地址的数值赋值给函数指针-》利用函数指针调用该函数

那么:如何解释?(*(void(*) ())0)()

(void(*) () 函数指针-》

(void(*) ())0 将0地址强制转换为函数指针类型(理解:一个函数的首地址存放在0)-》

(*(void(*) ())0)取出从0地址开始的一段区域中的函数——》

(*(void(*) ())0)() 调用执行函数;

4. 指针与数组:

指针在32位系统上,永远占用4字节,指针值是某一内存的地址;

数组的大小与元素的类型和个数有关,数组可以存放任何类型的数据,但不能存放函数;

数组名不能作为左值,不能对数组进行整体访问

指针: 数组:

1.

保存数据的地址,任何存入指针p的数据都会被当做地址处理; 保存数据,数组名表示数组首元素的地址而不是整个数组的首地址;

指针P的地址由编辑器自身存储在哪,并不知道; &a,是整个数组的首地址,a本身的地址存放有编辑器安排

2

间接访问数据,从指针p获得数据地址,再从此地址读写数据; 直接访问数据,a是整个数组名字,数组中的元素没有名字

可以以指针形式访问*(p+i),或下标形式访问p[i]; 可以以指针形式访问*(a+i),或下标形式访问a[i]

3.

常用于动态的数据结构; 常用于存放固定个数和数据类型相同的数据

4.

相关函数malloc(),free(); 系统自动分配空间,自动删除

指向匿名,具名数据; 自身为数组名


5.指针的相加减:

struct Test
{
int Num;
char *pcName;
short sDate;
char cha[2];
short sBa[4];
}*p;
假设p 的值为0x100000。如下表表达式的值分别为多少?sizeof(struct Test)= 4+4+2+2+2*4=20byte;
p + 0x1 = 0x___ ? 当指针进行加操作,加数必须考虑指针的类型。0x100000 + sizeof(struct Test) * 0x1 =0x100014
(unsigned long)p + 0x1 = 0x___? 直接是两个无符号长整形整数相加,=0x100001
(unsigned int*)p + 0x1 = 0x___? 0x100000 + sizeof(int) * 0x1 = 0x100004


6.数组参数与指针参数

注:当一维数组作为函数的参数时,编辑器将其解析成一个指向其首元素首地址的指针;

当指针作为参数(一级指针,二级指针),详细举例见我的博文

从内存分配看函数参数传递问题

总结:二维数组参数与二维指针参数的等效关系:

数组参数: 等效的指针参数:

数组的数组:a[3][4]; 数组的指针:a(*p)[3]

指针数组:int* a[3] 指针的指针: int** p;

原创粉丝点击