1. 为什么很多人觉得c语言只要学会了指针基本上差不多掌握这门语言
从事嵌入式开发十几年,只要使用的编程语言有三种,C/C++ Java三种,其中C语言使用的时间最长,这门编程语言的最大特别是语法细节简介,但是灵活性非常强,从大的方面看要真正掌握一种编程语言,需要真正的项目实战,只是停留在理论层面上很难认清编程语言背后的本质,记得刚学习C语言阶段,基本上一个多月就把基础语法学习完了,并且做了大量的实习题目,觉得这门编程语言就这么回事了。
于是从学校的图书馆里面借了一本将近1000页的linux内核讲解书籍,开始先从战略上藐视对手,在战术上重视在开始几十页进展的还是比较顺利,始终觉得掌握好了基础的语法,后面的就是变通和灵活运用的问题了,还能变出什么幺蛾子结果,看到后面简直就是在阅读天书了,才知道了自己认识的浅薄,只是掌握点语法皮毛就想着挑大梁这种想法在编程行业显得非常的幼稚,编程行业除了理论之外实战经验显得非常重要。
回到题目中的C语言的核心知识点指针,C语言关键语法点指针,数组,结构体,回调,递归,函数等等,剩下就是这些个概念在项目实战中的应用了,指针对于初学者来讲就是一种双刃剑,如果真的掌握理解了,能在编程中提升非常大的效率,如果没有掌握对于很多初学者来讲就是一种折磨,很多人觉得学不好C语言版本的数据结构,其实很重要的一个障碍就是指针,如果对于指针了解清楚,再去切入数据结构的学习就会显得轻松许多,指针作为C语言里面最重要的语法一点不为过,但是认为掌握了指针C语言就会显得非常肤浅。
任何一种编程语言的背后都是大量的编程模式以及编程的套路,这些只有在真正的项目实战中才能掌握,而且对于一种编程语言越是做的时间长越是觉得自己的肤浅,更加不敢称之为精通,倒是现在很多初生牛犊在简历上写上精通几种编程语言,越是干的时间长越是忌讳提到精通两个字眼,所以讲只是掌握了指针就说掌握一门编程语言的一半显得认识不足,真正掌握编程语言还是靠项目实战,不是所谓几个重点语法这么简单的事情。
学习一种编程语言需要掌握几个重点要素,首先掌握理论基础,世要真正的明白,虽然编程语言是一种实践性的语言,但实践的前提是掌握理论基础,很多人不懂C语言的指针就是因为没有彻底明白指针的含义,只想着快点追赶进度,结果欲速则不达,越是重要的概念越是要彻底掌握明白;第二点就是实战,在掌握理论基础上就是通过项目实战获取经验,纸上谈兵永远也不做不了真正的项目,想尽一切办法去做项目实战,没有别的途径,直面问题的本质,希望能帮到你。
很高兴能回答你的问题
C语言作为编程老祖,很多软件工具脚本都是用C语言或C++来编写的。那么C语言到底学成什么样才算学的比较好?
我上大学一年级的时候,就开始接触C语言了,C语言自认为学的还可以。像数据、变量、循环、判断等都是手到擒来。但学到第8章,也就是学到了指针那一块,就感觉有一点懵了,老师也说指针是比较费脑力的,死记硬背是不可取的,需要理解它的含义。
在学习指针之前,基本都没了解面向对象是什么意思。但学到了指针就懂得面向对象与面向过程的差异。(简单来说,前者就是以对象为基础,设定其属性啊,行为等。后者就是以完成它的过程为主,比如说:计算两个数相加。前者可以设计为小猫计算两个数,也可以是小猫2......,而后者就是计算,而且可以具体到是哪两个数相加。)面向对象对于现在的编程语言还是很重要的。
个人觉得,指针与面向对象密切相关,导致在C语言中指针就变得尤其重要,像我后面学习的Python、java就没有指针一说,但出现了很多类。相对C语言来说,多出了很多很多类。可能是指针被封装起来了吧。
更多精彩,敬请期待!
指针远远不是C语言的全部,
只是在C语言学习道路上相对而言比较难理解的一块。
毕竟从一个高级语言的角度去理解地址,比较抽象。
作为一个高级语言,数据类型,流程控制,函数这些才是高级语言的重点。
说差不多掌握这门语言,应该就是指的指针的难度,和学习的耗时。
也对,也不对,学会指针只是入门了。位运算与文件学会才能写应用。
只要学过嵌入式开发对指针必定是秒懂,无非就是内存寻址。脱离了硬件去学C只能学点皮毛。充其量也只能说会点语法而已。线程进程信号量系统调用各种通讯协议这些才是精华所在。
c语言是结构性(相对面向对象编程语言)高级编程语言。单纯语言本身来讲,语法结构大致类同。c语言的一大特点是对内存操作的灵活性,如果理解了对内存操作和管理的知识点,基本就掌握了这门语言。而指针便是c语言对内存操作的金钥匙。要想掌握c语言,也必须要精通指针相关知识点。
如果不算数据结构、操作系统和算法这些东西。纯粹从语言角度来看,掌握指针技巧,确实可以认为基本掌握语言了。要想更加精进的话,可以考虑学习各个硬件平台了。
比如SIMD在各个CPU平台的实现等。做一些针对性的硬件优化是可以考虑的。多媒体库就做了大量的硬件针对性优化。这个内容也算是核心技术的一部分了。核心技术的另一部分可以认为是算法和操作系统知识的应用。
首先说明的是指针是C语言的一个难点,但是不是全部。就好比不会指针,很多编程技巧无法掌握,同样掌握指针也不见得你能做什么。很多编程技巧需要在实际项目中去体会和学习。等觉得自己像编译器一样思考,自己写的每句代码,都很清楚编译器背后是怎么处理的时候再说自己熟练掌握C语言了。
最后总结来说,掌握指针只是C语言"真正"入门的一个表现。
语言本身掌握不算难,重点是算法,数据结构,编程思想...
我一般自己设计编译器 c指针按我自己的想法来写 怎么的
2. c语言指针面试常见问题
c语言指针面试常见问题
指针的使用,一直是c语言面试题中必考的部分,因为指针本身使用的复杂性与普适性,所以考点非常多,而且也可以与其他知识相互结合,因此我们将会使用五篇专题的篇幅来介绍指针。
分析下面的程序,指出程序中的错误:
本题解析
没有正确为str分配内存空间,将会发生异常。问题出在将一个字符串复制进一个字符变量指针所指地址。虽然编译的时候没有报错,但是在运行过程中,因为越界访问了未被分配的内存,而导致段错误。
相关知识点
在处理与指针相关的问题时,首先需要搞明白的就是内存,因为指针操作的就是内存。
第一个,就是内存的分区。这也是经常会被考察的一个考点。
写出内存分为几大区域
对于这个问题,有几种不同的说法,有的说内存分为五大分区,有的说分为四大分区,我们先来看五大分区的说法:
认为内存分为五大分区的人,通常会这样划分:
1、BSS段( bss segment )
通常是指用来存放程序中未初始化的'全局变量和静态变量 (这里注意一个问题:一般的书上都会说全局变量和静态变量是会自动初始化的,那么哪来的未初始化的变量呢?变量的初始化可以分为显示初始化和隐式初始化,全局变量和静态变量如果程序员自己不初始化的话的确也会被初始化,那就是不管什么类型都初始化为0,这种没有显示初始化的就 是我们这里所说的未初始化。既然都是0那么就没必要把每个0都存储起来,从而节省磁盘空间,这是BSS的主要作用)的一块内存区域。BSS是英文Block Started by Symbol的简称。BSS段属于静态内存分配。 BSS节不包含任何数据,只是简单的维护开始和结束的地址,即总大小。以便内存区能在运行时分配并被有效地清零。BSS节在应用程序的二进制映象文件中并不存在,即不占用 磁盘空间 而只在运行的时候占用内存空间 ,所以如果全局变量和静态变量未初始化那么其可执行文件要小很多。
2、数据段(data segment)
通常是指用来存放程序中已经初始化的全局变量和静态变量的一块内存区域。数据段属于静态内存分配,可以分为只读数据段和读写数据段。字符串常量等,但一般都是放在只读数据段中。
3、代码段(code segment/text segment)
通常是指用来存放程序执行代码的一块内存区域。这部分区域的大小在程序运行前就已经确定,并且内存区域通常属于只读, 某些架构也允许代码段为可写,即允许修改程序。在代码段中,也有可能包含一些只读的常数变量,例如字符串常量等,但一般都是放在只读数据段中 。
4、堆(heap)
堆是用于存放进程运行中被动态分配的内存段,它的大小并不固定,可动态扩张或 缩减。当进程调用malloc等函数分配内存时,新分配的内存就被动态添加到堆上(堆被扩张); 当利用free等函数释放内存时,被释放的内存从堆中被剔除(堆被缩减)
5、栈 (stack)
栈又称堆栈, 是用户存放程序临时创建的局部变量,也就是说我们函数括号“{}” 中定义的变量(但不包括static声明的变量,static意味着在数据段中存放变 量)。除此以外, 在函数被调用时,其参数也会被压入发起调用的进程栈中,并且待到调用结束后,函数的返回值 也会被存放回栈中。由于栈的先进先出特点,所以 栈特别方便用来保存/恢复调用现场。从这个意义上讲,我们可以把堆栈看成一个寄存、交换临时数据的内存区。
而四大分区的说法,则这么认为:
1、堆区:
由程序员手动申请,手动释放,若不手动释放,程序结束后由系统回收,生命周期是整个程序运行期间。使用malloc或者new进行堆的申请,堆的总大小为机器的虚拟内存的大小。
说明:new操作符本质上是使用了malloc进行内存的申请,new和malloc的区别如下:
(1)malloc是C语言中的函数,而new是C++中的操作符。
(2)malloc申请之后返回的类型是void*,而new返回的指针带有类型。
(3)malloc只负责内存的分配而不会调用类的构造函数,而new不仅会分配内存,而且会自动调用类的构造函数。
2、栈区:
由系统进行内存的管理。主要存放函数的参数以及局部变量。在函数完成执行,系统自行释放栈区内存,不需要用户管理。整个程序的栈区的大小可以在编译器中由用户自行设定,VS中默认的栈区大小为1M,可通过VS手动更改栈的大小。64bits的Linux默认栈大小为10MB,可通过ulimit -s临时修改。
3、静态存储区:
静态存储区内的变量在程序编译阶段已经分配好内存空间并初始化。这块内存在程序的整个运行期间都存在,它主要存放静态变量、全局变量和常量。
注意:
(1)这里不区分初始化和未初始化的数据区,是因为静态存储区内的变量若不显示初始化,则编译器会自动以默认的方式进行初始化,即静态存储区内不存在未初始化的变量。
(2)静态存储区内的常量分为常变量和字符串常量,一经初始化,不可修改。静态存储内的常变量是全局变量,与局部常变量不同,区别在于局部常变量存放于栈,实际可间接通过指针或者引用进行修改,而全局常变量存放于静态常量区则不可以间接修改。
(3)字符串常量存储在静态存储区的常量区,字符串常量的名称即为它本身,属于常变量。
(4)数据区的具体划分,有利于我们对于变量类型的理解。不同类型的变量存放的区域不同。后面将以实例代码说明这四种数据区中具体对应的变量。
4、代码区:
存放程序体的二进制代码。比如我们写的函数,都是在代码区的。
通过上面的不同说法,我们也可以看出,这两种说法本身没有优劣之分,具体的内存划分也跟编译器有很大的关系,因此这两种说法都是可以接受的,搞明白内存的分区之后,指针的使用才能够更加的灵活。
;3. C语言包括哪些知识点
数据类型,运算符与表达式;程序结构:顺序,选择,循环; 数组,函数,预处理命令,指针,结构体与共用体,文件,位运算;
当然,C程序的灵魂是算法。
4. 有关C语言指针的问题,超难,高手进!!!
整个函数的作用是-->在以listelement * listpointer为单向链表头的单向链表中的最尾段动态申请一个listelement结构的空间来存放要求加进单向链表的int data数据.并返回该链表的头指针....
以下是对程序代码的详细解释...
listelement * AddItem (listelement * listpointer, int data) {
//listpointer指向需要执行加入数据的单向链表的指针.这个指针可以指向任一条数据结构为listelement的单向链表
//data指的是要加入单向链表的具体数据
listelement * lp = listpointer; //使lp指向即将进行链表编历的头指针,这句为关键语句!
if (listpointer != NULL) { //如果链单不止一个有效项...则...
while (listpointer -> link != NULL)
listpointer = (listelement *) listpointer -> link; //这两名加起来为一个循环体! 其作用是编历整个链表的项.并保证listpointer指向链表中的最后一项!逻辑规定链表中的最后一项的listpointer -> link为NULL 其中listpointer = (listelement *) listpointer -> link中的(listelement *)为强制数据类型转换!目的是100%确保link为指向listelement结构的指针...这句话其实在正常的逻辑下是多余的.除非link除了指向本链表的下一个数据项外,还有别的作用! 但这样的可能性很少....
listpointer -> link = (struct listelement *) malloc (sizeof (listelement)); //动态申请一个listelement结构空间,并把申请到的首地址作为listpointer -> link! 由于前面的循环体的作用,使得listpointer -> link确保为链单中的最后一项...
listpointer = listpointer -> link; //使listpointer指向最后一项的实体,以便加入指定data数据项....看,这句listpointer = (listelement *) listpointer -> link是多么的相似!?(其执行结果肯定是一样的) 从这里可以看出,在前面循环体内的(listelement *)肯定是多余的!!!
listpointer -> link = NULL; //使listpointer在逻辑上成为本链表的最尾部!
listpointer -> dataitem = data; //加入数据
return lp; //返回本链表的头指针! 这和函数的第一句是对应的,是关键语句,绝不能少的!
}
else { //如果链表为空,也就是一个数据项都没有的话,则动态申请一个,并把data数据加到里面保存,然后使刚动态生成的listpointer为链表头指针! (以下的语句作用是就如此,我不多说了)
listpointer = (struct listelement *) malloc (sizeof (listelement));
listpointer -> link = NULL;
listpointer -> dataitem = data;
return listpointer;
}
}
PS:在高级语言里,指针的强制类型转换是经常用到的技巧!但由于各编译器的不同,会造成很多意想不到的逻辑错误!!!(很多时候,你以为确实是按自己的意思转换成指定的类型了,但实际上却完全不是这么一回事! 并这个错误有时是很难很难检测到底是为什么的!!!) 指针,用好了天下无敌,用不好就是一滴老鼠屎搞臭一锅汤!!! 这样情况的应用,用汇编是最不容易出错的!
PS:举个在G++编译器里一个容易误解的指针例子...两个不同的指针定义-->char *lp=new char[255]; 和 char lp[255];
里具体语句的lp[1]的含义到底有什么样的区别!? 这个例子,相信很多人都会觉得是一样没区别的(这是在C++标准里说明的)...但实际上,如果是在G++编译器里的话.定义为char lp[255];中的lp[1]的意义就是以lp为头指针的下一个单元!在这里,是我们常规并正确的理解! 但是,如果宝义成char *lp=new char[255];的话,则在G++编译器里lp[1]无解(结果是随机乱指一通)!!!虽然编译时不会出错,但结果肯定是错误的! 解决的方法超级郁闷.只能通过lp++来一步步寻址!(而不能通过lp[n]的方式直接寻址,当然如果还有效率高的方法,但这在逻辑上很容易让人混乱,那就是先把lp[0]转成DWORD类型再加上n之后再强制转成相应的指针类型!)
5. c语言指针程序题,程序如下,答案是3,6。我想知道为什么答案是3,6而不是6,3希望您能帮我详细解答一下。
呵呵,你被主函数中的a,b和子函数中的a,b所混淆了!
(1)主函数中的a,b是变量名,a=3,b=6,内容为3和6 。
(2)子函数中的a,b是指针变量,是指向整型变量的指针变量【(int * a,int * b)】。k也是指针变量,调用子函数fun时【fun(x,y)】,是将a,b的地址传过来了,不是a,b的值!在子函数内部,
k=a;a=b;b=k;交换的是就是的地址(注意:这里的a,b实际上是x,y,也就是主函数中的&a,&b),也就是将主函数中的变量地址交换了而已,就是将变量换个地方而已,变量名和变量的值都没有变!
指针变量是C语言中比较难的一个知识点,尤其是指向指针的指针、指向多维数组的指针。希望你多看书,多练习,认真领会。
6. c语言指针,下面这题看不懂,求解😭
while (*y++)
因为++运算符优先级比*高,所以先对指针y加1,再取出指针y指向的 字符
如果取出的字符不为0( ) 就循环
因为字符串数组 a[]={hello} 是依字符'