Chinaunix首页 | 论坛 | 博客
  • 博客访问: 4463411
  • 博文数量: 1148
  • 博客积分: 25453
  • 博客等级: 上将
  • 技术积分: 11949
  • 用 户 组: 普通用户
  • 注册时间: 2010-05-06 21:14
文章分类

全部博文(1148)

文章存档

2012年(15)

2011年(1078)

2010年(58)

分类: C/C++

2011-05-23 23:36:03

看了c语言的书了,也需要仔细整理整理了,主要的是整理C指针。这
篇博文也是对指针的最后整理。
这也是自己对指针的一些理解。
书籍: 让你不再害怕指针 彻底搞定c指针


包括的内容:

  1. 指针的类型

   2. 指针所指向的类型

   3. 指针的值或者是指针所指向的内存区

   4. 指针本身所占据的空间


const int *pi 与int *const pi 区别

函数名与函数指针 typedef void (*funtype)(int x)



最开始,看一个程序:
  1. #include <stdio.h>

  2. int main(int argc, char *argv[])
  3. {
  4.         int a = 10; //栈 0xbf9302ac
  5.         int *p = &a; //栈 0xbf9302a8

  6.         printf("&a=%p\n",&a);
  7.         printf("&p=%p\n",&p); //本身的地址
  8.         printf("p=%p\n",p); //所指向的内存地址

  9.         return 0;
  10. }

  1. ywx@ywx:~/yu/c$ ./test5
  2. &a=0xbf9302ac
  3. &p=0xbf9302a8
  4. p=0xbf9302ac




首先举例:
1. int *p[3] 这是什么呢??
    1. 因为[]优先级大于 * ,所以 p[3] 是一个数组
    2. 然后 *p[3],说明数组中的都是指针,这里也就有3 个指针
    3. 每个指针 指向了返回值为 int型 的数据

  1. #include <stdio.h>

  2. int main(void)
  3. {
  4.         int a = 10;
  5.         int b = 11;
  6.         int c = 12;

  7.         int *p[3];
  8.         p[0] = &a;
  9.         p[1] = &b;
  10.         p[2] = &c;

  11.         printf("&a=%lu\n",&a);
  12.         printf("p[0]=%lu\n",p[0]);
  13.         printf("*p[0]=%d\n",*p[0]);
  14.         printf("*p[2]=%d\n",*p[2]);
  15.         
  16.         return 0;
  17. }
  1. ywx@ywx:~/Desktop/yu$ ./pp1
  2. &a=3219506252
  3. p[0]=3219506252
  4. *p[0]=10
  5. *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
  1. #include <stdio.h>

  2. int main(void)
  3. {
  4.         int a[3] ={1,2,3}; // 0x00000020
  5.         int (*p)[3] = a;   //0x0000002c

  6.         printf("&a=%p\n",&a);  // 0x00000020
  7.         printf("&p=%p\n",&p);  //0x0000002c 
  8.         printf("p=%p\n",p);   //0x00000020
  9.         printf("%p\n",++p);  //0x0000002c
  10.         return 0;
  11. }

3. int (*p)(int)   //指针函数
    1. (*p)是一个指针,那么就在内存中分配了 4个字节的 内存空间
    2. (*p)(int) ,这是个函数,表示这个内存内存储了 函数的首地址


  1. #include <stdio.h>

  2. int max(int a,int b)
  3. {
  4.         return (a > b ? a : b);
  5. }
  6. int main(void)
  7. {

  8.         int (*fun)(int a,int b);
  9.         fun = max;
  10.         printf("max a b is %d\n",fun(2,3));
  11.         return 0;
  12. }



二.指针四个方面的内容

   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. 这个数据指向的数据不能被修改

           但是,可以修改指向哪个内存单元

  1. #include

  2. int main(int argc, char *argv[])
  3. {
  4.         int a = 10;
  5.         int b = 20;
  6.         const int *p;
  7.         p = &a;
  8.         printf("a=%d\n",*p);
  9.         //select p  point to b
  10.         // 看出我们可以重新指向的数据空间
  11.         p = &b;
  12.         printf("b=%d\n",*p);


  13.         //compile error 
  14.         //但是,如果我们通过 *p 来改变数据,这样是不能编译成功的
  15.         //*p = 20;
  16.        //printf("b=%d\n",*p);
  17.         
  18.         return 0;
  19. }
编译错误如下:
  1. ywx@ywx:~/Desktop/yu/point$ gcc test.c -o test
  2. test.c: In function ‘main’:
  3. test.c:15: error: assignment of read-only location*p’
3. int *const pi

  
1. *pi 一个指针,内存中分配的4个字节的区域
   2. *const pi 这4个字节内存区域中的内容不能被修
改,就是说,如果我初始化命名了一个地址后,这个地址就不能修改
了,但是可以修改指针所指向的地址的数据


  1. #include <stdio.h>

  2. int main(int artc, char *argv[])
  3. {
  4.         int a = 20;
  5.         int b = 30;
  6.         int *const p = &a;
  7.         printf("*p = %d\n",*p);
  8.         //编译错误
  9. // p = &b;test7.c:9:2: error: assignment of read-only variable ‘p’
  10.         //我们可以修改 指针指向的内存中的内容,
  11.         //但是,不能修改 指针的值即指针指向的内存区
  12.         *p = 40;
  13.         printf("a=%d\n",*p);
  14.         return 0;
  15. }



三:函数名与函数指针

 
知道myfun函数名代表的一个功能或是说一段代码 ,那 函数名到底又是什么东西呢??
其实,函数名就是一个函数指针


 
函数: void myfun(int x)
       {
          printf("%d\n",x);
       }
声明函数指针 void (*funp)(int);


1.

  1. int main(int argc, char* argv[])
  2. {
  3.     myfun(10);/* 这是直接调用 MyFun 函数 */
  4.     funp = &myfun; /* 将 myfun 函数的地址赋给 funp 变量*/
  5.     (*funp)(20);/* ()这是通过函数指针变量 funp 来调用myfun 函数的。 */
  6. }
2.
  1. int main(int argc, char* argv[])
  2. {
  3.     myfun(10);/* 这里是调用 MyFun(10)函数 */
  4.     FunP = MyFun; /* 将 MyFun 函数的地址赋给 FunP 变量*/
  5.     FunP(20); /* ()这是通过函数指针变量来调用 MyFun 函数的。*/
  6. }
3.
  1. int main(int argc, char* argv[])
  2. {
  3.     MyFun(10);/* 这里是调用 MyFun(10)函数 */
  4.     FunP = &MyFun; /* 将 MyFun 函数的地址赋给 FunP 变量*/
  5.     FunP(20); /* 这是通过函数指针变量来调用 MyFun 函数的*/
4.
  1. int main(int argc, char* argv[])
  2. {
  3.     MyFun(10);/* 这里是调用 MyFun(10)函数 */
  4.     FunP = MyFun; /* 将 MyFun 函数的地址赋给 FunP 变量*/
  5.     (*FunP)(20); /*这是通过函数指针变量来调用 MyFun 函数的。*/
5.
  1. int main(int argc, char* argv[])
  2. {
  3.     MyFun(10);/* 这里是调用 MyFun(10)函数 */
  4.     FunP = MyFun; /* 将 MyFun 函数的地址赋给 FunP 变量*/
  5.     (*FunP)(20); /*这是通过函数指针变量来调用 MyFun 函数的。*/
1)其实,MyFun 的函数名与 FunP 函数指针都是一样的,即都是函数指针。
MyFun 函数名是一个函数指针常量,而 FunP 是一个函数数指针变量,这是它们的关系。

2)但函数名调用如果都得如(*MyFun)(10)这样,那书写与读起来都是不方便和不习惯的。
所以 C 语言的设计者们才会设计成又可允许 MyFun(10)这种形式地调用(这样方便多了并与数学中的函数形式一样,不是吗?)

3)为统一起见,FunP 函数指针变量也可以 FunP(10)的形式来调用。
4)赋值时,即可 FunP = &MyFun 形式,也可 FunP = MyFun。


  1. #include <stdio.h>

  2. void myfun(int x)//函数名是函数指针
  3. {
  4.         printf("%d\n",x);
  5. }
  6. int main(int argc, char *argv[])
  7. {
  8.         int a = 10;
  9.         (*myfun)(a);
  10.         myfun(a);

  11.         void (*fun)(int);
  12.         fun = myfun;
  13.         //fun = &myfun;//或者是这种
  14.         (*fun)(a);
  15.         fun(a);

  16.         return 0;
  17. }

函数指针作为某个函数的参数
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

函数指针类型



阅读(1793) | 评论(0) | 转发(1) |
给主人留下些什么吧!~~