指针是C的精华,也是初学者的梦魇

4.1

FAQ:指针的好处有哪些?

Answer:(1)可以动态分配数组;

(2)可以对多个相似变量一般访问;

(3)按照引用传递函数参数;

(4)适合各种动态分配的数据结构,尤其是树和链表;

(5)指针方式遍历数组,比如解析字符串;

(6)高效,按照引用 “复制”数组和结构,尤其在作为函数参数的时候。

(7).etc

4.2

FAQ:想通过以下代码声明一个指针并且为它分配一些空间,但是不行,为什么?

char *p;

*p=malloc(10);

Answer:代码本意声明的指针是 p;类型是 char * ,而不是 *p,当操作指针本身时,比如对指针赋值,或者修改指向时,只需要使用指针的名字即可;

p=malloc(10);

当需要访问指针指向的内存时,才需要 *作为间接操作符:

*p='A';

然而,如果在定义的时候初始化该指针可能会容易犯以上错误比如

char *p=malloc(10);

所以分开写的时候应该注意;malloc时去掉*;

题外话:如果C++中还是有点差别的,malloc需要显示的强制类型转换

char *p;

p=(char *)malloc(10);

当然使用完成后需要free释放;

free(p);

不要写成free(*p)哦;

指针指向的空间被free后,没有被重置为NULL,或者指向一个有效的内存区域、

在free后要及时处理被free的指针,例如令其指向NULL。

野指针该如何避免?

在指针声明时,要养成将其初始化的习惯。如下:

int *p = NULL;

默认将其初始化为NULL

在free后面,加上重置指针的代码,如下:

free(p);

p = NULL;

重置为NULL

#include <stdio.h>#include <string.h>#include <stdlib.h>int main(int argc,char *argv[]){char *p = NULL;  //初始化为NULLp = (char *)malloc(100);if(p==NULL){return 0;}strcpy(p,"faq");  //向内存拷贝值printf("p : %s\n",p);     //打印值if(p!=NULL){free(p);p = NULL;  //在释放完后,再将指针的值置为空}//free释放的是指针所指向的内存空间,而不是指针的值。//所以释放后指针还是指向原来的地址if(p1!=NULL){free(p1);  //如果再次释放,就会出现野指针错误。}getchar();return 0;}

4.3

FAQ:*p++是自增p还是p所指向的变量:

Answer:“*和++”两者优先级相同,(

primer上说++优先级高,但我网上查了下,好多说二者优先级一样,从右向左。

这两种解释的结果是一样的。哪个是对的?

* 有两个意思,理论上

作为 乘法 运算符,级别低于 ++(自增)。

作为 指针取值 运算符,级别同 ++(自增)一样。

这里不仅仅是优先级的问题!

)需要按从右到左的顺序执行。;所以 *p++ 等价*(p++),所以结果是自增p返回增加前所指向的值;

如果需要增加指向的变量++ 那就使用(*p)++;如果副作用的顺序无关紧要也可以 ++*p,等价于 ++(*p);返回++后的值,

关于 ++ 和--在前在后的影响:谁在前先返回哪个!

ref.:https://jingyan.baidu.com/article/eae07827809adf1fec54851f.html

*++p
//相当于*(++p),指针p先后移,如果是数组,则指向下一个元素,然后++p返回指针下移后的指针。然后*取下移指针后所指向的值.

4.4 指针操作

FAQ:我用指针操作int数组的时候遇到了麻烦,下边的代码有什么问题?

int arry[5],i,*ip;

for(i=0;i<5;i++)

arry[i]=i;

ip =arry;

printf("%d\r\n",*(ip+3*sizeof(int)));

我以为最后会打印3 ,但是打印了一堆垃圾;

Answer:这样打印不对,做了一些无用功,c语言当中的指针算术运算是自动采纳它所指向的对象对象的大小;

printf("%d\r\n",*(ip+3));这样打印数组第3个数据,这样的运算不用考虑指针指向的元素的大小。

4.5 FAQ:我有一个char *类型的指针碰巧指向了一个int 型变量,我想跳过他们,((int*)p)++;这样的代码不行吗?

Ansswe:在C语言中,类型转换操作符并不意味着“把这些而二进制位看作另一种类型,并作相应处理”,这是一个转换操作符,根据定义它只能生成一个右值,(rvalue)不能进行赋值或者自增操作,所以上述写法是不合法的,(编译器如果过了,要么错误,要么进行了非标准拓展)。

如果达到目的可以尝试下边操作

p=(char *)((int*)p+1);

或者因为 p是char *;

p+=sizeof(int);

明白操作的话下边可能是合适的;

int *ip=(int*)p;//先强制把p 是 int* ;

p=(char *)(ip+1);//操作之后转回来char*;

为了不李代桃僵,实际使用最好还是同类型操作;

4.6 为什么不能对void*进行指针进行算术操作?(参考11.26)

4.7 关于解析外部结构的代码,但是却崩溃了,显示出 unsigned access(未对齐的访问)的信息,这是什么意思?

作为函数参数的指针

4.8FAQ:我有个函数,它应该接受并初始化一个指针;

void f(int *p)

{

static int dummy=5;

p=&dummy;

}

但是当我如下调用时,

int *ip;

f(ip);

调用者的指针没有任何变化。

Answer:你确定函数初始化的是你希望它初始化的东西吗?C语言中参数是通过值传递的,上述代码中被调用函数仅仅修改传入的指针副本,薇乐大道期望的效果你需要传入指针的地址(函数需要变成接受指向指针的指针)

void f(int **p)

{

static int dummy=5;

*p=&dummy;

}

。。。。

调用时

int *ip;

f(&ip);

这里实际是在模拟通过引用传递参数,另一种办法就是函数返回指针:

int * f()

{

static int dummy=5;//考虑一下为什么这里是static ,可以阅读博客《C语言深度剖析内存管理》学习笔记;

return &dummy;

}

。。。

int *p=f();

4.9 FAQ:能否像下边这样用 void **通用指针作为参数,使函数模拟按照引用传递参数?

void f(void **);

double *dp;

f((void**)&dp);

Answer:这样的代码不可移植,但是可能是有效的,有时候也会鼓励这样使用,但是它依赖一种假设:所有的内部表示都是一样的(这很常见,但并不一定如此)

C语言中没有通用的指针类型。void *可以作为通用指针的原因:当它和其他类型相互赋值的时候,如果需要,他可以自动转换为其他类型。但是如果试图这样转换所指类型为 void *之外的类型的 void ** 指针时,就不会自动转换了。当使用 void **指针的时候 (例如:使用*操作符访问 void **指针所指向的 void*的值的时候),编译器无法知道void * 的值是否是其他类型指针转换而来的,因此,编译器只能认为它仅仅是个void *类型的指针,不能对它进行任何隐式转换。换而言之,你使用的任何 void **的值必须的确是某个位置的void* 值的地址。(void **)&dp这样的类型编译器虽然可以接收,但是不能移植,而且也不会达到你要的目的,如果void**指针指向的值不是void*类型,而且他的大小或内部大小也和 void*不相同,则编译器就不能正确的访问它。

如果要使上边的代码正确工作,你需要使用一个中间的void*变量;

double *dp;

void *vp=dp;

f(&vp);

dp =vp;

类似的

void incme(double *p)

{

*p+=1;

}

可以这样做

int i=1;

double d=i;

incme(&d);

i=d;

但是如果像以下这样:

int i=1;

incme((double*)&i);这个代码就不对了;

4.10FAQ:我有一个函数extern int f(int*);它接收指向int型的指针。我怎样用引用方式传入一个常量?调用f(&5),视乎不行。

Answer:C99中可以使用“复合字面量”:

f((int[]){5});

C99之前是不能这样做的,必须先定义一个临时变量,然后取地址传给函数

int five =5;

f(&five);

C语言中接收指针而不是值的函数可能往往是希望改变指针指向的值,因此传入一个常数指针可能不是一个好主意。事实上,如果f被定义成接收 int*,则向他传入

const  int 的指针的时候是需要被诊断的,(如果函数能保证不修改传入指针指向的值,则它可以被定义成接收 const int *参数)。

4.11FAQ: C语言可以”按照引用传参”吗?

Answer:C是不支持的,C++是可以的。C编译器本质只是在模拟按照引用传参。另一方面,类似函数的宏可以提供一种“名称传参”的形式。

其他指针问题(函数指针)

4.12FAQ:我看到了指针调用函数的不同语法形式,这是什么情况?

Answer:最初,函数指针操作必须*操作符和(一对括号)转换为一个”真正的“,函数才能调用。

int r,(*fp)(),func();

fp=func;

r=(*fp)();

fp是个函数指针  *fp是个函数,括号内加上函数参数,在*fp外加上括号为了优先级正确,就完成了一个完整函数调用;,而函数总数通过指针进行调用的,所有 “真正的”函数名在表达式和初始化中总是隐式的退化为指针,所以无论 fp是函数名还是函数的指针 r=fp();都是合法的,(函数指针后跟参数列表的方法,除了调用它所指的函数外,其他什么也做不了,没有歧义)使用显示*号调用被允许是因为为了保证老版本编译器移植编译,也是推荐的用法。

4.13FAQ:通用指针类型是什么?当我把函数指针赋值给 void * 的时候,编译不过?

Answer:没有什么通用指针类型,void*指针只能保存对象(也就是数据)指针,将函数指针转换为void*的指针是不可移植的,(某些机器上,函数指针可能很大,比任何一个数据类型指针都大),

但是可以确保的是,所有函数指针类型都可以互相转化,只要在调用前转回了正确类型就行。因此,可以使用任何函数类型 (通常是  int (*)()或者 void (*)(),返回int或者void 函数),作为通用函数指针。

如果你需要一个既能容纳数据指针又能容纳函数指针的地方,可移植的方案是,void * 和 通用函数指针的组合,比如任务控制块结构。

未完待续;后续会把运行截图上传完善。

如有错误欢迎留言指正;

《你必须知道的的495个C语言问题》阅读笔记-(第4章)指针篇相关推荐

  1. 《CUDA高性能并行计算》----2.2 需要知道的CUDA API和C语言拓展

    本 节 书 摘 来 自 华 章 出 版 社 <CUDA高性能并行计算> 一 书 中 的 第2章,第2.2节, 作 者 CUDA for Engineers: An Introduction ...

  2. c语言中变量可以用x1表示没,你必须知道的495个C语言问题 读书笔记

    1.数值类型的选择:溢出特征重要而负值不重要,操作二进制位时避免符号扩展的问题,应该使用unsigned(无符号值) char 8位 -127~127 最大值255 short int 和 int 均 ...

  3. 《抓住听众心理——演讲者要知道的100件事》一20.人们学习的最优长度是20分钟...

    本节书摘来异步社区<抓住听众心理--演讲者要知道的100件事>一书中的第1章,第20节,作者: [美]Susan M. Weinschenk 译者: 杨妩霞 , 杨煜泳 责编: 赵轩,更多 ...

  4. 《抓住听众心理——演讲者要知道的100件事》一2.听众需要上下文

    本节书摘来异步社区<抓住听众心理--演讲者要知道的100件事>一书中的第1章,第1.2节,作者: [美]Susan M. Weinschenk 译者: 杨妩霞 , 杨煜泳 责编: 赵轩,更 ...

  5. 《抓住听众心理——演讲者要知道的100件事》一第 1 章 人们是怎样思考和学习的...

    本节书摘来异步社区<抓住听众心理--演讲者要知道的100件事>一书中的第1章,第1.1节,作者: [美]Susan M. Weinschenk 译者: 杨妩霞 , 杨煜泳 责编: 赵轩,更 ...

  6. 项目经理应该知道的97件事

    项目经理应该知道的97件事 基本信息 原书名: 97 Things Every Project Manager Should Know 原出版社: O'Reilly Media 作者: (美)Barb ...

  7. 你应该知道的25个非常有用的CSS技巧

    在我们的前端CSS编码当中,经常要设置特殊的字体效果,边框圆角等等,还要考虑兼容性的问题, CSS网页布局,说难,其实很简单.说它容易,往往有很多问题困扰着新手,在中介绍了非常多的技巧,这些小技巧与知 ...

  8. 关于机器学习,你应该知道的3个热门专业术语

    https://www.toutiao.com/a6683842829510246923/ 2019-04-25 22:43:48 关于机器学习,你应该知道的3个热门专业术语 原创: 吴郦军.罗人千 ...

  9. 有哪些事情是你成为程序员之后才知道的?

    来源 | 三太子敖丙(ID:JavaAudition) 昨天我教练问我:"有哪些事情是你成为程序员之后才知道的."我就写下来了. 身穿一件微微起球的格子衫,背着工整的双肩包,头发乱 ...

最新文章

  1. 关于双目立体视觉的三大基本算法及发展现状的总结
  2. Wix学习整理(7)——在开始菜单中为HelloWorld添加卸载快捷方式
  3. 嵌入式程序员应知道的0x10个基本问题
  4. 比特币现金扬声器系列II将领先的比特币一起带来
  5. 九度 1550 分糖果
  6. 前端需要了解的 Cookies 和 WebStorage
  7. Nginx 访问日志轮询切割
  8. Python爬虫实战之解密HTML
  9. linux防火墙之牛刀小试
  10. 七牛云主机全线升级,「两大资源池」实现多云容灾
  11. 一文读懂机器学习(转)
  12. 学前端的记录帖html+css b站千峰19版
  13. android 行政区域,最新Android使用Jsoup获取省市县行政区划代码行政编码(附源码与Json数据)...
  14. itchat 运行记录
  15. 域策略(4)——设置统一锁屏壁纸(此策略仅适用于企业版、教育版和 Server SKU版)
  16. Python 自动化开发【初级】到精通-张子夜-专题视频课程
  17. php中文拼音模糊,两种php中文字符转拼音问题解决方法
  18. Python基础Pro | (17) 电子邮件
  19. 从零开始构建一个高可靠的RabbitMQ镜像集群
  20. 九宫怎么排列和使用_剪映零基础入门教程第三十七篇:一学就会系列之九宫格小程序配音...

热门文章

  1. Sheldon Numbers
  2. LED照明各国认证及标准发展趋势
  3. 你们中国人真TM假,微信居然能撤回…
  4. pm_原型设计——墨刀使用教程
  5. 2021好看的新年雪花飘倒计时单页网站源码分享
  6. 使用Tushare接口做中证500基差图
  7. 鸿蒙系统沙箱,鸿蒙计划加速!亦来云成操作系统的救命稻草?
  8. 百度音乐接口-——可以根据这做一个在线音乐播放器哦
  9. RNN-循环神经网络-吴恩达读书笔记
  10. SpringBoot整合knif4j Api文档