当前位置:  开发笔记 > 编程语言 > 正文

你没有从老师那里学到什么C的重要概念?

如何解决《你没有从老师那里学到什么C的重要概念?》经验,为你挑选了20个好方法。

9月份,我将向工程学院的学生们提供C语言的第一次讲座(通常我会教数学和信号处理,但我也做过很多C语言的实际工作,没有给他们讲课).计算机科学不是他们的主题(他们更多地研究电子和信号处理),但他们需要有良好的编程背景(其中一些可能会成为软件开发人员)

今年将是他们学习C的第二年(他们应该知道指针是什么以及如何使用它,但当然,这个概念尚未被同化)

除了经典的东西(数据结构,经典算法......),我可能会把我的一些讲座集中在:

在用C编码之前设计算法(并用伪代码编写)(在编码之前考虑)

使您的代码可读(注释,变量名称,...)和

指针,指针,指针!(它是什么,如何以及何时使用它,内存分配等......)

根据您的经验,您的老师从未教过您的C中最重要的概念是什么?我应该关注哪个特定点?

例如,我应该将它们介绍给某些工具(lint,......)吗?



1> Matthieu..:

const在指针上下文中使用关键字:

以下声明之间的区别:

 A)   const char* pChar  // pointer to a CONSTANT char
 B)   char* const pChar  // CONSTANT pointer to a char
 C)   const char* const pChar  // Both

所以用A:

const char* pChar = 'M';
*pChar = 'S'; // error: you can't modify value pointed by pChar

和B:

char OneChar = 'M';
char AnotherChar = 'S';
char* const pChar = &OneChar;
pChar = &AnotherChar; // error: you can't modify address of pChar



2> jeremyalan..:

我的老师花了很多时间教我们,指针是可怕的小goobers,如果不正确使用可能会导致很多问题,他们从来不打扰向我们展示它们真正有多强大.

例如,指针算法的概念对我来说是陌生的,直到我已经使用C++几年:

例子:

c [0]相当于*c

c [1]相当于*(c + 1)

循环迭代:for(char*c = str;*c!='\ 0'; c ++)

等等...

而不是让学生害怕使用指针,教他们如何适当地使用它们.

编辑:由于注释引起了我的注意,我刚刚读了一个不同的答案,我认为在讨论指针和数组之间的细微差别(以及如何将两者放在一起以促进一些相当复杂的结构)方面也有一些价值,以及如何const在指针声明方面正确使用关键字.


@Brian:我不能不同意.恐惧使学生不能学习新事物.在修复了他们的前几个内存泄漏,段错误和越界错误之后,他们会得到对指针的尊重,但是他们永远不会那么远.
就个人而言,作为一名教师,我认为教师应该同时教授.学生既需要了解指针的力量,也需要尊重它们.初学者应该有点害怕指针,但不要害怕他们从不使用它们然后真正理解它们......

3> scvalex..:

他们真的应该学习使用辅助工具(即编译器以外的任何东西).

1)Valgrind是一个很好的工具.它非常容易使用,它可以完美地跟踪内存泄漏和内存损坏.

它将帮助他们理解C的记忆模型:它是什么,你能做什么,以及你不应该做什么.

2)GDB + Emacs与gdb-many-windows.或者其他任何集成调试器.

它会帮助那些懒惰的人用铅笔和纸张逐步完成代码.


不仅限于C; 这是我认为他们应该学习的内容:

1)如何正确编写代码:如何编写不可维护的代码.读到这一点,我发现至少有三项我犯了罪.

说真的,我们为其他程序员编写代码.因此,对我们来说,写清楚写聪明更重要.

你说你的学生实际上不是程序员(他们是工程师).所以,他们不应该做一些棘手的事情,他们应该专注于清晰的编码.

2)STFW.当我开始编程时(我开始使用Pascal,而不是转到C语言),我通过阅读书籍来做到这一点.我花了无数个小时试图弄清楚如何做事.

后来,我发现我必须弄清楚的所有内容已经被许多其他人完成,并且至少有一个人已经在网上发布了它.

你的学生是工程师; 他们没有太多时间投入编程.所以,他们有这么短的时间,他们应该花时间阅读其他人的代码,或许,可能会习惯于成语.


总而言之,C是一门非常容易学习的语言.他们在编写任何超过几行的东西时会遇到很多麻烦,而不是学习独立的概念.



4> Jon..:

当我不得不使用C作为学校中较大项目的一部分时,能够正确使用gdb(即根本不能),最终预测谁将完成他们的项目,谁不会.是的,如果事情变得疯狂,你有大量的指针和内存相关的错误gdb将显示奇怪的信息,但即使知道这可以指向人们正确的方向.

还提醒他们C不是C++,Java,C#等是个好主意.当你看到有人像C++中的字符串一样处理char*时,这种情况最常出现.



5> Robert..:

unsigned vs signed.

位移运算符

比特屏蔽

位设置

整数大小(8位,16位,32位)


+1用于位移 - 也是位掩码.

6> Paul Biggar..:

面向对象:

struct Class {
    size_t size;
    void * (* ctor) (void * self, va_list * app); // constructor method
    void * (* dtor) (void * self);                // destructor method
    void (* draw) (const void * self);            // draw method
};

(代码来源)


不适合初学者!
+1注意到你可以在没有用你的语言明确支持的情况下做OO.
C++为你做了所有这些工作*所以你可以专注于实际编码,而不是手工完成.我知道它们是不同的语言,但C++几乎在任何方面都是优越的.你可以干净地用C++做这个(答案),让编译器处理细节.那么,为什么不学习C++并使用它而不是模仿它.我认为不使用C++而不是C的唯一两个原因是编译器选项(嵌入式系统)和现有代码库.
嗯,评论用于评论.
OP指出,学生主要学习电子和信号处理.所以编译器选项很可能是学习在C中做这样的事情的原因.

7> azheglov..:

便携性 - 很少在学校教授或提及,但在现实世界中出现很多.



8> freespace..:

宏的(危险的)副作用.



9> Draemon..:

使用valgrind



10> groovingandi..:

工具很重要,所以我建议至少提一下

Makefile以及构建过程的工作原理

GDB

皮棉

编译器警告的用处

关于C,我认为重要的是要强调程序员应该知道"未定义的行为"究竟意味着什么,即知道即使它似乎与当前的编译器/平台组合一起工作也可能存在未来的问题.

编辑:我忘了:教他们如何搜索并在SO上提出正确的问题!



11> Karl Voigtla..:

使用一致且可读的编码风格.

(这应该可以帮助您查看他们的代码.)

相关:不要过早优化.首先了解瓶颈的位置.



12> dicroce..:

知道当你递增指针时,新地址取决于该指针所指向的数据的大小...(IE,char*递增和unsigned long*之间的区别是什么)...

首先要确切了解分段故障究竟是什么,以及如何处理它们.

知道如何使用GDB很棒.知道如何使用valgrind很棒.

开发C编程风格......例如,当我编写大型C程序时,我倾向于编写相当面向对象的代码(通常,特定.C文件中的所有函数都接受一些(1)特定的struct*并对其进行操作. ..我倾向于有foo*foo_create()和foo_destroy(foo*)ctor和dtors ...)...



13> William Purs..:

理解链接器.任何使用C的人都应该理解为什么"static int x;" 在文件范围不会创建全局变量.编写一个简单的程序,其中每个函数都在自己的翻译单元中并分别编译每个函数在学习C的早期阶段不够频繁.



14> Bastien Léon..:

始终有效警告.使用GCC,至少使用-Wall -Wextra -Wstrict-prototypes -Wwrite-strings.

I/O很难.scanf()是邪恶的.gets()应该永远不会被使用.

当您打印未被'\n'终止的内容时,stdout如果您想立即打印它,则必须刷新,例如

printf("Type something: ");
fflush(stdout);
getchar();

const尽可能使用指针.例如void foo(const char* p);.

使用size_t存储大小.

Litteral字符串一般不能修改,所以制作它们const.例如const char* p = "whatever";.



15> JesperE..:

破坏的内存可以触发各种奇怪的错误.

调试器可能骗你.


说调试器如何骗你是有帮助的.例如,他们将内存初始化为零,并更改线程排序(在某些情况下隐藏竞争条件).

16> Tobias Wärre..:

我认为整体想法似乎非常好.这些是一些额外的东西.

    调试器是一个好朋友.

    检查边界.

    确保指针在使用之前实际指向某个东西.

    内存管理.



17> Markus Pilma..:

希望之前没有发布过(只是非常快速地阅读),但我认为当你必须使用C时,非常重要的是了解数据的机器表示.例如:IEEE 754浮点数,大与小端,结构对齐(这里:Windows vs Linux)......为了实现这一点,制作一些有点谜题(解决一些问题而不使用任何功能)非常有用然后printf打印结果,有限数量的变量和一些逻辑运算符).此外,了解链接器如何工作,整个编译过程如何工作等基本知识也很有用.但特别是理解链接器(没有它,很难找到某种错误...)

这本书帮助我提高了我的C和C++技能:http://www.amazon.com/Computer-Systems-Programmers-Randal-Bryant/dp/013034074X

我认为对计算机体系结构的深入了解会使好的和坏的C程序员之间产生差异(或者至少它是一个重要的因素).



18> Bryan Oakley..:

教他们单元测试.



19> Harvey..:

一般最佳实践如何?

总是假设其他人已经编写了您的代码,并且它在互联网上免费提供,并且比您在截止日期之前生成的任何内容更好地编写和测试.

提前退货/避免其他条款

初始化所有变量

每个功能一页作为指导(即一起使用较小的代码片段)

何时使用switch,if-else if或hash表

避免全局变量

始终检查您的输入和输出(我不相信我自己的代码.)

大多数功能应返回状态

[致其他人:随意编辑此内容并添加到列表中]

关于检查输入:

我曾经匆忙写了一个大程序,并且在我的函数中编写了各种Guard Clauses,输入检查.当我第一次运行该程序时,那些快速流动的子句中的错误甚至无法读取它们,但程序没有崩溃,可以干净地关闭.这是一个简单的问题,通过列表和修复错误快速的错误.

将Guard子句视为运行时编译器警告和错误.



20> 小智..:

我认为你不应该是教学工具.那应该留给Java老师.它们很有用并且被广泛使用但与C无关.调试器与它们希望获得的访问权限一样多.很多时候你得到的是printf和/或闪烁的LED.

教他们指针,但教他们好,告诉他们他们是一个整数变量代表在记忆中的位置(在大多数课程中他们也有一些组装训练,即使它是为了一些想象的机器,所以他们应该能够理解)和不是一个星号前缀变量,它以某种方式指向某个东西,有时变成一个数组(C不是Java).教他们C数组只是指针+索引.

让他们编写将溢出和段错误的程序,然后确保他们理解为什么会发生这种情况.

标准库也是C,让他们使用它并让他们的程序在你的私人测试中痛苦地因为使用了gets()和strcpy()或者双重释放了某些东西.

强制他们处理不同类型的变量,endianness(你的测试可以在不同的arch中运行),float to int conversion.让他们使用掩码和按位运算符.

即教他们C.

我得到的是C语言中的一些批处理,也可以在GW-BASIC中完成.

推荐阅读
夏晶阳--艺术
这个屌丝很懒,什么也没留下!
DevBox开发工具箱 | 专业的在线开发工具网站    京公网安备 11010802040832号  |  京ICP备19059560号-6
Copyright © 1998 - 2020 DevBox.CN. All Rights Reserved devBox.cn 开发工具箱 版权所有