看了c语言的书了,也需要仔细整理整理了,主要的是整理C指针。这
篇博文也是对指针的最后整理。
这也是自己对指针的一些理解。
书籍: 让你不再害怕指针 彻底搞定c指针
包括的内容:
1. 指针的类型
2. 指针所指向的类型
3. 指针的值或者是指针所指向的内存区
4. 指针本身所占据的空间
const int *pi 与int *const pi 区别
函数名与函数指针 typedef void (*funtype)(int x)最开始,看一个程序:- #include <stdio.h>
-
-
int main(int argc, char *argv[])
-
{
-
int a = 10; //栈 0xbf9302ac
-
int *p = &a; //栈 0xbf9302a8
-
-
printf("&a=%p\n",&a);
-
printf("&p=%p\n",&p); //本身的地址
-
printf("p=%p\n",p); //所指向的内存地址
-
-
return 0;
-
}
- ywx@ywx:~/yu/c$ ./test5
-
&a=0xbf9302ac
-
&p=0xbf9302a8
-
p=0xbf9302ac
首先举例:
1. int *p[3] 这是什么呢??
1. 因为[]优先级大于 * ,所以 p[3] 是一个数组
2. 然后 *p[3],说明数组中的都是指针,这里也就有3 个指针
3. 每个指针 指向了返回值为 int型 的数据
- #include <stdio.h>
-
-
int main(void)
-
{
-
int a = 10;
-
int b = 11;
-
int c = 12;
-
-
int *p[3];
-
p[0] = &a;
-
p[1] = &b;
-
p[2] = &c;
-
-
printf("&a=%lu\n",&a);
-
printf("p[0]=%lu\n",p[0]);
-
printf("*p[0]=%d\n",*p[0]);
-
printf("*p[2]=%d\n",*p[2]);
-
-
return 0;
-
}
- ywx@ywx:~/Desktop/yu$ ./pp1
-
&a=3219506252
-
p[0]=3219506252
-
*p[0]=10
-
*p[2]=12
2. int (*p)[3]
1. (*p) 表示是一个指针,就在内存中分配了 4个字节的内存地址
2. (*p)[3] 是个数组,内存中存放了这个数组的收地址,但是还不知道指向的数组的类型、内存长度
3. int 这里说明了指向的数据的类型是 int,内存长度也就是 4*3
int (*p)[3] 指向了一个 a[3]的数组。如果 p++, 那么指向的下个地址是 &a + sizeof(int)*3=0x2c
- #include <stdio.h>
-
-
int main(void)
-
{
-
int a[3] ={1,2,3}; // 0x00000020
-
int (*p)[3] = a; //0x0000002c
-
-
printf("&a=%p\n",&a); // 0x00000020
-
printf("&p=%p\n",&p); //0x0000002c
-
printf("p=%p\n",p); //0x00000020
-
printf("%p\n",++p); //0x0000002c
-
return 0;
-
}
3. int (*p)(int) //指针函数
1. (*p)是一个指针,那么就在内存中分配了 4个字节的 内存空间
2. (*p)(int) ,这是个函数,表示这个内存内存储了 函数的首地址
- #include <stdio.h>
-
-
int max(int a,int b)
-
{
-
return (a > b ? a : b);
-
}
-
int main(void)
-
{
-
-
int (*fun)(int a,int b);
-
fun = max;
-
printf("max a b is %d\n",fun(2,3));
-
return 0;
-
}
二.指针四个方面的内容
1. 指针的类型
2. 指针所指向的类型
3. 指针的值或者是指针所指向的内存区
4. 指针本身所占据的空间
1.指针的类型
从语法的角度看,你只要把指针声明语句里的指针名字去掉,剩下的部
分就是这个指针的类型。这是指针本身所具有的类型
char*ptr;//指针的类型是 char*
int**ptr;//指针的类型是 int**
int(*ptr)[3];//指针的类型是 int(*)[3]
int*(*ptr)[4];//指针的类型是 int*(*)[4]
2.指针所指向的类型
把指针声明语句中的指针名字和名字左边的指针声
明符*去掉,剩下的就是指针所指向的类型
char*ptr; //指针所指向的的类型是 char
int**ptr; //指针所指向的的类型是 int*
int(*ptr)[3]; //指针所指向的的类型是 int()[3]
int*(*ptr)[4]; //指针所指向的的类型是 int*()[4]
3.指针的值----或者叫指针所指向的内存区或地址
指针的值:在32位cpu上,所有的指针的值都是一样,32bit
指针所指向的内存区:p(开始地址) + sizeof(指针指向的类型) 的内存区
我们说的一个指针的值,就是指针指向了以xx为首地址的一片内存区域
int a[4] = {1,2,3};
int *p = a;
printf("a=%p\n",a); // 0xeec
printf("p=%p\n",p); // 0xeec
printf("++p=%p\n",p++); //0xefc
//printf("++p=%p\n",sizeof(int)*4); //0xefc
4 指针本身所占据的内存区
32cpu中,指针本省占据了 4个字节的长度
sizeof(对象) 测出的就是对象本身的类型的大小
int (*p)[10] //指向了 包含10个数据的 一片内存区
sizeof(int(*)[10]) = 4 // 指针的类型
sizeof(int[10]) = 40 //指针所指向的类型
sizeof(p) = 4 //所以说,本身的类型的大小
//本身类型 int(*)[10],在32bitcpu中,都是 4 字节const int *pi 与int *const pi 区别 1.首先从 const int i 说起
const int ic = 20; 这两个是一样的
int const ic = 20;
记住一点: int 与 const 哪个放前哪个放后都是一样的2. const int *pi 我的理解: 1. *pi,是一个指针,内存中分配的4个字节的区域
2. 指针指向了 为int型的数据
3. 这个数据指向的数据不能被修改
但是,可以修改指向哪个内存单元- #include
- int main(int argc, char *argv[])
- {
- int a = 10;
- int b = 20;
- const int *p;
- p = &a;
- printf("a=%d\n",*p);
- //select p point to b
- // 看出我们可以重新指向的数据空间
- p = &b;
- printf("b=%d\n",*p);
- //compile error
- //但是,如果我们通过 *p 来改变数据,这样是不能编译成功的
- //*p = 20;
- //printf("b=%d\n",*p);
-
- return 0;
- }
编译错误如下:
- ywx@ywx:~/Desktop/yu/point$ gcc test.c -o test
-
test.c: In function ‘main’:
-
test.c:15: error: assignment of read-only location ‘*p’
3. int *const pi
1. *pi 一个指针,内存中分配的4个字节的区域
2. *const pi 这4个字节内存区域中的内容不能被修
改,就是说,如果我初始化命名了一个地址后,这个地址就不能修改
了,但是可以修改指针所指向的地址的数据- #include <stdio.h>
-
-
int main(int artc, char *argv[])
-
{
-
int a = 20;
-
int b = 30;
-
int *const p = &a;
-
printf("*p = %d\n",*p);
-
//编译错误
-
// p = &b;test7.c:9:2: error: assignment of read-only variable ‘p’
-
//我们可以修改 指针指向的内存中的内容,
-
//但是,不能修改 指针的值即指针指向的内存区
-
*p = 40;
-
printf("a=%d\n",*p);
-
return 0;
-
}
三:函数名与函数指针
知道myfun函数名代表的一个功能或是说一段代码 ,那 函数名到底又是什么东西呢??
其实,函数名就是一个函数指针
函数: void myfun(int x)
{
printf("%d\n",x);
}
声明函数指针 void (*funp)(int);
1. - int main(int argc, char* argv[])
-
{
-
myfun(10);/* 这是直接调用 MyFun 函数 */
-
funp = &myfun; /* 将 myfun 函数的地址赋给 funp 变量*/
-
(*funp)(20);/* (★)这是通过函数指针变量 funp 来调用myfun 函数的。 */
-
}
2.
- int main(int argc, char* argv[])
-
{
-
myfun(10);/* 这里是调用 MyFun(10)函数 */
-
FunP = MyFun; /* 将 MyFun 函数的地址赋给 FunP 变量*/
-
FunP(20); /* (★)这是通过函数指针变量来调用 MyFun 函数的。*/
-
}
3.
- int main(int argc, char* argv[])
-
{
-
MyFun(10);/* 这里是调用 MyFun(10)函数 */
-
FunP = &MyFun; /* 将 MyFun 函数的地址赋给 FunP 变量*/
-
FunP(20); /* 这是通过函数指针变量来调用 MyFun 函数的*/
4.
- int main(int argc, char* argv[])
-
{
-
MyFun(10);/* 这里是调用 MyFun(10)函数 */
-
FunP = MyFun; /* 将 MyFun 函数的地址赋给 FunP 变量*/
-
(*FunP)(20); /*这是通过函数指针变量来调用 MyFun 函数的。*/
5.
- int main(int argc, char* argv[])
-
{
-
MyFun(10);/* 这里是调用 MyFun(10)函数 */
-
FunP = MyFun; /* 将 MyFun 函数的地址赋给 FunP 变量*/
-
(*FunP)(20); /*这是通过函数指针变量来调用 MyFun 函数的。*/
1)其实,MyFun 的函数名与 FunP 函数指针都是一样的,即都是函数指针。
MyFun 函数名是一个函数指针常量,而 FunP 是一个函数数指针变量,这是它们的关系。
2)但函数名调用如果都得如(*MyFun)(10)这样,那书写与读起来都是不方便和不习惯的。
所以 C 语言的设计者们才会设计成又可允许 MyFun(10)这种形式地调用(这样方便多了并与数学中的函数形式一样,不是吗?)
3)为统一起见,FunP 函数指针变量也可以 FunP(10)的形式来调用。
4)赋值时,即可 FunP = &MyFun 形式,也可 FunP = MyFun。- #include <stdio.h>
-
-
void myfun(int x)//函数名是函数指针
-
{
-
printf("%d\n",x);
-
}
-
int main(int argc, char *argv[])
-
{
-
int a = 10;
-
(*myfun)(a);
-
myfun(a);
-
-
void (*fun)(int);
-
fun = myfun;
-
//fun = &myfun;//或者是这种
-
(*fun)(a);
-
fun(a);
-
-
return 0;
-
}
函数指针作为某个函数的参数
void myfun(int x);
typedef void (*funtype)(int); //这里只是定义了一个名为
funtype函数指针类型,而不是一个funtype变量
记得,在系统程序员成长计划 中,page17
1. 定义函数指针类型
typedef void (*funtype)(int x)
2. 声明 函数
int print(Dlist *list,funtype print) //这里使用了 funtype
函数指针类型
阅读(473) | 评论(0) | 转发(0) |