Chinaunix首页 | 论坛 | 博客
  • 博客访问: 532848
  • 博文数量: 87
  • 博客积分: 1549
  • 博客等级: 上尉
  • 技术积分: 970
  • 用 户 组: 普通用户
  • 注册时间: 2011-03-14 16:56
文章分类
文章存档

2013年(10)

2012年(28)

2011年(49)

分类: C/C++

2012-05-04 14:36:06

卓跃教育C语言强化指针高级应用学习心得(02)

一.关于指针传递的思考

1-1

#include

char* test()

{

      char str[] = "this is a test";

      return str;

}

 

int main(void)

{

      char* pStr = NULL;

      pStr = test();

      puts(pStr);

      return 0;

}

运行之后,会出现什么情况呢?

答:很可能是一些乱码。

因为test返回的的是指向栈,原先开辟出来的内存生存周存在函数执行完之后,就被系统回收。故输出的值不确定。

1-2

#include

#include

#include

 

void test(char* str)

{

      strcpy(str,"this is a test");

}

 

int main(void)

{

      char str[100] = {0};

      test(str);

      printf("str=%s\n",str);

      return 0;

}

运行结果是什么呢?

答:str=this is a test

传给test函数的参数是指针值,本质上可以说指针传递也是值传递,即传给test函数的是指向str[100]数组的首地址。在test内对指定地址内容进行操作。

1-3test若改成:

void test2(char* str)

{

      str = malloc(sizeof("this is a test"));

      strcpy(str,"this is a test");

}

main函数改成:

int main(void)

{

      char* str2=NULL;

      test2(str2);

       printf("str2=%s\n",str2);

      free(str2);

 

      return 0;

}

输出结果又是什么呢?

答:输出NULL

因为str = malloc(sizeof(“this is a test”));语句使str里的地址发生改变,因此后面的strcpy()操作不影响数组str2

那如何解决这个问题呢?可以采用指针的指针,即将str2的地址传给test3,如下:

void test3(char** str)

{

      *str = malloc(sizeof("this is a test"));

      strcpy(*str,"this is a test");

}

来一个比较有意思的例子

1-4char * test2(void)

{

      char *str = "this is my test";

      return str;

}

int main(void)

{

      char* str2=NULL;

      str2 = test2();

      printf("str=%s\n",str2);

      return 0;

}

运行会出现什么情况?

答:在debug下,会出现“degub assertion failed”,同时也会输出:str=this is my test

因为”this is my test”是字符串常量,保存在内存区域的文字常量区域,它的生存周期是程序运行的整个过程。利用这一点,将”this is my test”字符串的首地址返回保存起来,之后用这个地址来输出字符串是可行的。但是,函数结束完之后,”this is my test”这个字符串的生存期也就结束了,以后再用它就会有问题。即出现野指针问题。

不改程序,照样也想运行程序,可以嘛?在vc6.0下,将debug改成release模式(build->configuration,删除debug),就不会再出现degub assertion failed的提示。

二.函数指针

如何定义一个指向函数的指针变量?

一般定义形式为:数据类型  (* 指针变量名)  (函数参数列表)

这里“数据类型”指函数返回值的类型。

实例:定义一个函数参数是int型,返回类型为空的函数指针变量

void  (*f)(int);

可以说变量f的类型为void (* )(int),既然如此,那不是可以用typedef给这种类型定义一个别名。

typedef  void  (*F)(int);

此时就可以用F定义变量了。

2-1

#include

#include

#include

 

void test(int n)

{

      printf("n=%d\n",n);

}

 

typedef void(*F)(int);

 

int main(void)

{

      F f = test;             //定义函数指针f,并初始化指向test函数

      F *p = NULL;

 

      f(100);

 

      printf("%p %p\n", test,&test);

      return 0;

}

 

三.关于const关键字

const修饰的变量,可以被修改嘛?

答:可以

如:

int* p2;

const int n2 = 200;

p2 = &n2;

*p2 = 300;

printf("n2=%d\n",n2);

编译的时候有个警告:warning C4090: '=' : different 'const' qualifiers

但执行完后,发现n2值变为300了。

警告提示是类类型不匹配,改成const int * p2之后,就不会出现警告,因为此时类类型都为const int,但会出现错误:error C2166: l-value specifies const object.

说时const类型不能作为左值。

关于const比较难理解的是修饰指针变量。如:

const int a;

int const a;

const int *a;

int * const a;

const int * const a;

前两个的作用是一样,a是一个常整型数。第三个意味着a是一个指向常整型数的指针(也就是,整型数是不可修改的,但指针可以)。第四个意思a是一个指向整型数的常指针(也就是说,指针指向的整型数是可以修改的,但指针是不可修改的)。最后一个意味着a是一个指向常整型数的常指针(也就是说,指针指向的整型数是不可修改的,同时指针也是不可修改的)。如果应试者能正确回答这些问题,那么他就给我留下了一个好印象。顺带提一句,也许你可能会问,即使不用关键字 const,也还是能很容易写出功能正确的程序,那么我为什么还要如此看重关键字const呢?我也如下的几下理由:
1)
关键字const的作用是为给读你代码的人传达非常有用的信息,实际上,声明一个参数为常量是为了告诉了用户这个参数的应用目的。如果你曾花很多时间清理其它人留下的垃圾,你就会很快学会感谢这点多余的信息。(当然,懂得用const的程序员很少会留下的垃圾让别人来清理的。)
2)
通过给优化器一些附加的信息,使用关键字const也许能产生更紧凑的代码。
3)
合理地使用关键字const可以使编译器很自然地保护那些不希望被改变的参数,防止其被无意的代码修改。简而言之,这样可以减少bug的出现。

四. 回调函数

注:暂存的内容只能恢复到当前文章的编辑器中,如需恢复到其他文章中,请编辑该文章并从暂存箱中恢复;或者直接复制以上内容,手工恢复到相关文章。

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