1 指针
如何将数值存储到指定的内存地址
int *p = (int *)0x12ff7c; // 将地址 0x12ff7c 赋值给指针变量 p 的时候必须强制转换
*p = 0x100; // 通过钥匙“*”向这块内存写入一个数据 0x100
*(int *)0x12ff7c = 0x100; // 这种一步搞定
2 数组 int a[5];
省政府和市政的区别----&a[0]和&a 的区别
sizeof(&a[0])的值在 32 位系下为 4,这很好理解。取元素 a[0]的首地址。
sizeof(&a)的值在 32 位系统下也为 4, 这也很好理解。 取数组 a 的首地址。
但是在 VisualC++6.0 上,这个值为 20,我认为是错误的。
sizeof(a)的值为 4*5 = 20
a[0]是一个元素, a 是整个数组,虽然 a、 &a[0] 和 &a 的值一样,但其意义不一样。
前者&a[0] / a 是 数组首元素 的 首地址,
而后者 &a 是 数组 的首地址。
举个例子:湖南的省政府在长沙,而长沙的市政府也在长沙。
两个政府都在长沙,但其代表的意义完全不同。这里也是同一个意思。
int a[5]={1,2,3,4,5};
int *ptr=(int *)(&a+1); // 即 &a + 5*sizeof(int)
printf("%d,%d",*(a+1),*(ptr-1));// 2,5
数组名 a 作为左值和右值的区别:
出现在赋值符“=”右边的就是右值,出现在赋值符“=”左边的就是左值。 比如,x=y
左值:在这个上下文环境中,编译器认为 x 的含义是 x 所代表的地址。
这个地址只有编译器知道,在编译的时候确定,编译器在一个特定的区域保存这个地址,
我们完全不必考虑这个地址保存在哪里.
右值:在这个上下文环境中,编译器认为 y 的含义是 y 所代表的地址里面的内容。
这个内容是什么,只有到运行时才知道。
a 作为右值时其意义与&a[0]是一样,代表的是 数组首元素的首地址,
而不是数组的首地址。这是两码事。
但是注意,这仅仅是代表,并没有一个地方(这只是简单的这么认为,其具体实现细节不作过多讨论)来存储这个地址,
也就是说编译器并没有为数组 a分配一块内存来存其地址,这一点就与指针有很大的差别。
a 不能作为左值,数组地址不能被改变。
我们可以把 a[i]当左值,而无法把 a当左值。
3 数组与指针的关系
数组就是数组,指针就是指针,它们是完全不同的两码事!他们之间没有任何关系,只是经常穿着相似的衣服来迷惑你罢了。
4 数组指针 与 指针数组
指向数组的指针: 数组指针
存储指针的数组: 指针数组
int *p1[10]; // “[]”的优先级比“*”要高。 p1 先与“[]”结合,构成一个数组的定义.
// 数组的内容 由 int* 给出,即包含10个指向整形数据的指针的数组
int (*p2)[10];// “()”的优先级比“[]”高,“*”号和 p2 构成一个指针的定义,
// int[10] 这里表示的是一个包含10个整形数据的 数组
// 数组在这里并没有名字,是个匿名数组。
5 多维数组 多维空间 超过二维的数组和超过二级的指针其实并不多用
char a[3][4];
// |a[0] - - - - | a[1] - - - - | a[2] - - - - |
// a[0],a[1],a[2]。 每个元素的大小为 sizeof(a[0]),即 sizeof(char)*4。
// 由此可以计算出 a[0],a[1],a[2]三个元素的首地址分别为&a[0], &a[0]+ 1*sizeof(char)*4, &a[0]+ 2*sizeof(char)*4。
// a[i][j]的首地址为 &a[i] + j*sizeof(char)
// a[i][j]元素的首地址为: a + i*sizof(char)*4 + j*sizof(char)。
// 多维数组定义 都是花括号
int a [3][2]={(0,1),(2,3),(4,5)};
// 花括号里面嵌套的是小括号,而不是花括号!
// 这里是花括号里面嵌套了逗号表达式!其实这个赋值就相当于
int a [3][2]={ 1, 3, 5};
6 多级指针-二级指针-指针的指针
7 数组与指针作为函数参数
C 语言中,当一维数组作为函数参数的时候,编译器总是把它解析成一个指向其首元素首地址的指针。
无法把指针变量本身传递给一个函数, 但可以改变指针指向的值。
可以利用函数返回值,也可以传递二级指针,即 想改变的指针 的 地址。
当数组超过一维时,将第一维改写为指向数组首元素首地址的指针之后,后面的维再也不可改写。
比如: a[3][4][5]作为参数时可以被改写为(*p) [4][5]
8 函数指针 函数指针数组
char * fun3(char * p1,char * p2); // fun3是函数,返回值为 char*类型
char * *fun2(char * p1,char * p2); // fun2也是函数, 返回值为 char** 类型
char * (*fun1)(char * p1,char * p2); // fun1是函数指针,指向一个类型为 char*(char*,char*)的函数
函数指针调用示例:
#include <stdio.h>
#include <string.h>
char * fun(char * p1,char * p2)
{
int i = 0;
i = strcmp(p1,p2);
if (0 == i)
{
return p1;
}
else
{
return p2;
}
}
int main()
{
char * (*pf)(char * p1,char * p2);// 定义函数指针
pf = &fun; // 赋值,初始化
(*pf) ("aa","bb");// 调用函数指针指向的函数
return 0;
}
(int)&p 强转 指针地址类型,再解引用
void Function()
{
printf("Call Function!\n");
}
int main()
{
void (*p)(); // void(void)类型函数的指针 p,
// &p 是求指针变量 p 本身的地址,这是一个 32 位的二进制常数(32 位系统)。
// (int*)&p 表示将地址强制转换成指向 int 类型数据的指针。
// (int)Function 表示将函数的 入口 地址 强制转换成 int 类型 的 数据。
*(int*)&p=(int)Function;// 表示将函数的入口地址赋值给指针变量 p。
(*p) ();// 表示对函数的调用。
return 0;
}
((void() ())0)()
void(*)() , 指向类型为 void(void)的函数的 函数指针
(void(*) ())0 ,将 0 强制转换为函数指针类型, 0 是一个地址,也就是说一个函数存在首地址为 0 的一段区域内。
(*(void(*) ())0),取 0 地址开始的一段内存里面的内容,其内容就是保存在首地址为 0 的一段区域内的函数。
(*(void(*) ())0)(), 这是函数调用
同理 :
(*(char**(*) (char **,char **))0) ( char **,char **);
函数指针数组
char * (*pf)(char * p); // 定义的是一个函数指针 pf, 指向一个类型为 char*(char*)的函数
char * (*pf[3])(char * p);// 定义一个函数指针数组, 数组名为 pf,数组内存储了 3 个指向函数的指针。
示例:
#include <stdio.h>
#include <string.h>
char * fun1(char * p)
{
printf("%s\n",p);
return p;
}
char * fun2(char * p)
{
printf("%s\n",p);
return p;
}
char * fun3(char * p)
{
printf("%s\n",p);
return p;
}
int main()
{
char * (*pf[3])(char * p);// pf 为 函数指针数组名
// 为数组赋值
pf[0] = fun1; // 可以直接用函数名
pf[1] = &fun2; // 可以用函数名加上取地址符
pf[2] = &fun3;
pf[0]("fun1");// 调用函数
pf[1]("fun2");
pf[2]("fun3");
return 0;
}
函数指针数组的指针
char * (*pf)(char * p); // 定义的是一个函数指针 pf, 指向一个类型为 char*(char*)的函数
char * (*pf[3])(char * p);// 定义一个 函数指针 数组, 数组名为 pf,数组内存储了 3 个指向函数的指针。
char * (*(*pf)[3])(char * p);// 定义一个指针,指向一个函数指针数组,该数组内存放3个 指向类型为char*(char*)的函数的函数指针。
用法:
#include <stdio.h>
#include <string.h>
char * fun1(char * p)
{
printf("%s\n",p);
return p;
}
char * fun2(char * p)
{
printf("%s\n",p);
return p;
}
char * fun3(char * p)
{
printf("%s\n",p);
return p;
}
int main()
{
char * (*pf[3])(char * p);// pf 为 函数指针 数组名
char * (*(*pf)[3])(char * p);// 函数指针数组 的 指针
pf = &a;
// 为数组赋值
a[0] = fun1;
a[1] = &fun2;
a[2] = &fun3;
pf[0][0]("fun1");// 调用函数
pf[0][1]("fun2");
pf[0][2]("fun3");
return 0;
}
参考
https://github.com/Ewenwan/ShiYanLou