注册 登录  
 加关注
   显示下一条  |  关闭
温馨提示!由于新浪微博认证机制调整,您的新浪微博帐号绑定已过期,请重新绑定!立即重新绑定新浪微博》  |  关闭

尐鬼じ☆ve伱

和你在一起的日子

 
 
 

日志

 
 

指针 (转)  

2012-04-17 14:35:38|  分类: C/C++ |  标签: |举报 |字号 订阅

  下载LOFTER 我的照片书  |

1.多维数组元素的地址

int b[5] = {1,2,3,4,5};

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

%p: 按地址格式输出

&b:数组名b本来就是一个地址,为何还可以再利用一次取地址符呢?有些不好理解,a[5][5]是二维数组,可以看做a[5]是一维数组,每个数组元素包含5个元素。a[5]是地址,但是指向列元素,a也是地址,但是指向行,即指针的类型改变了。因此,&b可以看作是类似二维数组,作&运算后,是指向行的。空口无凭,当然得用实例证明。

以上输出结果:

代码改成:printf("%p %p\n",b,&b 1);输出结果应该是相对b[0]地址偏移了20个字节。证据如下: 地址是16进制格式

扩展:

int x = 0x87654321;

printf("%p\n",(void *)x);

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

输出结果如下:

printf("%p\n",(void *)x); //打印x被转换为指针的地址,就是他的值

printf("%p\n",&x); //打印x的地址

2.给main()函数传参

int main(int argc, char* argv[])

argc:表示参数的个数,注意这里有包含执行文件名

char* argv[]:是指针数组,它可以指向多个字符串

argc和argv是形参,当然可以也可以是其他名字

main()函数是由操作系统调用的,那形参的值从何处得到呢?实际上实参和形参是和命令(程序名)一起给出的,如:

命令名  参数1 参数2 ……参数n

例1-1:

#include <stdio.h>

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 <stdio.h>

#include <string.h>

#include <malloc.h>

 

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

typedef  void  (*F)(int);

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

例2-1:

#include <stdio.h>

#include <string.h>

#include <malloc.h>

 

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

  评论这张
 
阅读(185)| 评论(0)
推荐 转载

历史上的今天

评论

<#--最新日志,群博日志--> <#--推荐日志--> <#--引用记录--> <#--博主推荐--> <#--随机阅读--> <#--首页推荐--> <#--历史上的今天--> <#--被推荐日志--> <#--上一篇,下一篇--> <#-- 热度 --> <#-- 网易新闻广告 --> <#--右边模块结构--> <#--评论模块结构--> <#--引用模块结构--> <#--博主发起的投票-->
 
 
 
 
 
 
 
 
 
 
 
 
 
 

页脚

网易公司版权所有 ©1997-2017