c语言强化,C语言强化指针高级应用学习心得(02)

本文探讨了C语言中指针的高级应用,包括指针传递、函数指针以及const关键字的使用。通过示例分析了指针在函数参数传递中的作用,以及如何避免内存问题。同时,讲解了const修饰符的意义,强调了它在代码可读性、优化和错误预防方面的重要性。最后,简单介绍了回调函数的概念。
摘要由CSDN通过智能技术生成

卓跃教育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-3:test若改成:

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-4:char * 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给这种类型定义一个别名。

typedefvoid(*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的出现。

四.回调函数

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

  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值