卓跃教育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的出现。
四.回调函数
注:暂存的内容只能恢复到当前文章的编辑器中,如需恢复到其他文章中,请编辑该文章并从暂存箱中恢复;或者直接复制以上内容,手工恢复到相关文章。