<p>Besides all of these good answers, I want to add one thing. Make them familiar with the world of <strong>Competitive Programming</strong> and <strong>Problem Solving</strong> where they would learn by playing. They would learn how to approach and solve a problem. Some of the most common <em>competitive programming</em> and <em>problem solving</em> platforms are:</p>
<ul>
<li><a href="https://www.urionlinejudge.com.br/judge/en/login" rel="nofollow noreferrer">URI OJ</a> - There are a lot of problems here for the beginner from adding two numbers to much more.</li>
<li><a href="https://onlinejudge.org/" rel="nofollow noreferrer">UVa OJ</a> - Here, they would learn how computer program works for checking two files! Statistics of this site is better seen <a href="https://uhunt.onlinejudge.org/" rel="nofollow noreferrer">here</a> in uHunt.</li>
<li><a href="http://codeforces.com/" rel="nofollow noreferrer">Codeforces</a> - This is a good site for competitive programming, as well as problem solving. New problems come in almost every week. The most important part here is, one could see other's code after a contest. Editorials for problems are available. This is a Russian platform.</li>
<li><a href="https://atcoder.jp/contests/" rel="nofollow noreferrer">At Coder</a> - Similar platform like Codeforces, but this is a Japanese platform. Don't worry, in both of the platforms, English version is available.</li>
<li><a href="https://www.codechef.com/" rel="nofollow noreferrer">CodeChef</a> - This is another similar platform. This is an Indian site.</li>
<li><a href="https://www.hackerrank.com/" rel="nofollow noreferrer">Hacker Rank</a> - Besides basic programming, they also have tracks for Data Structures, Algorithms, Databases, AI etc. Though I do not recommend those tracks for a beginner.</li>
<li><a href="https://projecteuler.net/archives" rel="nofollow noreferrer">Project Euler</a> - There are so many interesting problems here. Here, only answer of one scenario should be submitted instead of submitting code.</li>
<li><a href="https://vjudge.net/" rel="nofollow noreferrer">Virtual Judge</a> -  This is a Chinese platform. Contests could be arranged here taking problems from different online Judges.</li>
<li><a href="https://toph.co/" rel="nofollow noreferrer">Toph</a> - A Bangladeshi platform for both competitive programming and problem solving.</li>
<li><a href="https://alpha.sustcseoj.com/" rel="nofollow noreferrer">SourceCode (Temporary Name)</a> - Our students made this platform, though it is in a very early stage. The name is not yet finalized. We take programming exams through it. There are several problems for problem solving.</li>
</ul>
<p>There are a lot of interesting things on the internet. We should encourage and entertain our new students with these tools, rather than compelling him to know complex things.</p>
<p>(My answer seemed not relevant to the question, but it is relevant as you could submit answers in C/C++.)</p>

CC BY-SA 4.0
2020-07-03T17:25:20.243Z
2020-07-03T17:25:20.243Z
Enamul Hassan
<p>It's important to teach that the name <code>C</code> refers to two diverging languages--a low-level language which is useful for systems programming because many operations which different platforms may handle differently are handled in a documented fashion characteristic of the actual execution environment, and a more recent high-level-only language which uses the same syntax as the low-level language, but which allows compilers to behave in arbitrary fashion if code attempts certain operations whose behaviors would be defined in the former language.</p>

<p>Given a piece of code like:</p>

<pre><code>unsigned mul_mod_65536(unsigned short x, unsigned short y)
{
  return (x*y) &amp; 0xFFFF;
}
</code></pre>

<p>compilers for the former language would multiply the values of x and y
using whatever semantics the platform uses for integer multiplication,
take the bottom 16 bits of that result, and return them.  On platforms where integer overflow would yield a result whose bottom 16 bits is correct, the above would yield the correct mod-65536 sum for all combinations of x and y.  The published rationale for C89 indicates that the authors of the Standard would have expected such behavior from most current (and IMHO presumably future) compilers.</p>

<p>On compiler processing the latter language, however, the above code may sometimes malfunction in totally nonsensical ways if the value of x*y would exceed 2147483647.  If, for example, code were to call <code>mul_mod_65536(i,65535)</code> some "modern" compilers would use the multiplication to infer that <code>i</code> cannot be greater than 32768, and thus "optimize out" code elsewhere in the program that would only be relevant if it were.  Thus, unlike some languages which specify that an overflow will wrap cleanly (like Java), or specify that it will trap (like C#, within <code>checked</code> contexts), "modern C" requires that programmers absolutely positively prevent overflows from occurring under any circumstances even in cases where one of the above behaviors would suffice (or even in circumstances where either would be equally useful).</p>

<p>Programmers need to be aware that there exists a lot of code which is written for the former kind of C, and also that some compilers like gcc and clang will be incompatible with such code unless explicitly forbidden from applying aggressive "optimizations".</p>

CC BY-SA 3.0
2017-12-22T22:23:24.780Z
2017-12-22T22:23:24.780Z
supercat
<h2>Too much, too fast</h2>

<p>"First semester". If I parse correctly, you say 60% students are <strong>new to programming</strong>.</p>

<p>You say "The following points knock them out: they don't know how to test, they don't know how to check for memory leaks, they have no concept of encapsulating". And you say "group assignments".</p>

<p>Taken together, it looks like this course is "introductory" only in this sense it will introduce part of students to the idea that this university doesn't want to teach them (programming or even teach them how to learn programming), but it wants to filter them out.</p>

<p>You cannot change that fact. You cannot help everyone, you can help some. </p>

<p>Either you want:</p>

<ul>
<li>to help programmers to become better</li>
<li>to help some non-programmers to become programmers (will work 10% of the time in your setting)</li>
<li>to help all non-programmers to learn a bit, but probably not enough to let them pass</li>
</ul>

<p>Presently your mini-course is a big mish-mash. Come on: someone needs to be informed how to google stuff? Really? And the next minute you talk about git? To help who, in what way...? Don't waste everyone's time, narrow it down:</p>

<ul>
<li><p>to help programmers to become better</p>

<ul>
<li>valgrind</li>
<li>coding style

<ul>
<li>best practices -> how to allocate memory, typedefs, file operations</li>
<li>basic program flow, some simple patterns</li>
</ul></li>
<li>git</li>
<li>pitfalls in general</li>
</ul></li>
<li><p>to help some non-programmers to become programmers (will work 10% of the time in your setting)</p>

<ul>
<li>you want to give them ready-made stuff; their heads are bound to explode, the more boilerplate you give them, the less the explosion

<ul>
<li>make 

<ul>
<li>boilerplate gcc flags included, etc</li>
</ul></li>
<li>pitfalls specific to this course</li>
<li>the rest will come later (i.e. someday they will decide they need to improve on memory handling - but not today for sure, someday they will decide to migrate version control out of their Facebook - not today)</li>
</ul></li>
</ul></li>
<li>to help all non-programmers to learn a bit, but probably not enough to let them pass

<ul>
<li>"how to google their problems"</li>
<li>"how to use the manpage"</li>
</ul></li>
</ul>

CC BY-SA 3.0
2017-12-22T12:28:47.103Z
Welcome to CSEducators. A somewhat different perspective, but a dose of reality. Thanks.
Buffy
CC BY-SA 3.0
2017-12-22T12:31:47.370Z
Sadly, enrollments are so high at this moment (late 2017) that many departments are, indeed, trying to winnow the students. I don't know if that is the situation here, but it has been discussed elsewhere. This happens every few years, actually, and is often followed by a drought. The fact that many of the topics discussed in this thread were omitted from the course in question may be an indicator that this is the case, actually.
Buffy
CC BY-SA 3.0
2017-12-22T13:32:37.630Z
Thank you, for making clear what i did know deep down, but didnt really consciously knew. If nothing better pops up in the next few days, youll get the accepted answer.
Git
CC BY-SA 4.0
2017-12-22T12:16:36.757Z
2020-04-27T13:45:36.690Z
2020-04-27T13:45:36.690Z
kubanczyk
<p>I think an important aspect to any best-practices list is the rationale behind it.  It is entirely too common for a programmer to, for example, insist that gotos and global variables are evil and then proceed to use exceptions and singletons to create the exact same problems that got those features proscribed in the first place.</p>

<p>So I suggest that when introducing a rule of thumb, you don't just give examples of code that follows the rule, but rather examples of the sort of awful code that led to the rule being created.  Let them understand <em>why</em> the rule exists both so they can avoid making similar mistakes and also recognize when the rule <em>isn't</em> applicable. (Of course, no examples will be as helpful as allowing them to write terrible code and then try to modify it, but you have limited time.)</p>

<p>A related recommendation that is somewhat tangential to the best practices lecture, but related to the question of how to help them complete the course successfully:
Don't assume that the more abstract explanations of topics are necessarily easier to understand than the ones that get into the gritty details.  </p>

<p>I've had a number of students who were completely confused when we tried to explain pointers using diagrams of boxes and arrows, but as soon as I sketched out a table of memory (with addresses as indices), explained that a pointer is just an integer that is used to "index memory", and then walked through a block of code, updating the table as I went, they understood it almost immediately.  (We put the abstractions back in place when it was time to work with higher level data structures, <em>after</em> they understood the fundamentals.)</p>

CC BY-SA 3.0
2017-12-21T22:33:55.220Z
Nice observations about pointers.
Robert Harvey
CC BY-SA 3.0
2017-12-21T22:41:10.020Z
@RobertHarvey I almost left it out of the answer, since it's not really a best practice, but I've *never* seen students move from "complete confusion" to "complete understanding" as quickly as I have after giving that explanation, so I decided it was worth mentioning anyway.
Ray
CC BY-SA 3.0
2017-12-22T19:02:07.243Z
Regarding *explained that a pointer is just an integer that is used to "index memory"*, this can be a double-edged sword. It can lead new C programmers to think they're in on the secret about "how things *really* work", which is actually oversimplified and wrong, and thereby insist on being allowed to do very wrong/against-best-practices things. Even `ptr+n` becomes confusing for new C programmers when they think that `ptr` *is* an integer rather than *has a representation as an integer*.
R.. GitHub STOP HELPING ICE
CC BY-SA 3.0
2017-12-22T19:14:27.003Z
@R.. Whenever I need to simplify things, I let them know that I'm doing so.  That's the best middle ground I've found between letting them believe that an approximate explanation is precise, and trying (and failing) to explain everything at once.  That said, `ptr` *is* an integer.  It's just not an `int`.  But even `int` is a closer approximation of its type than `&**magic[42]->&a`, which is frequently how they seem to view it without this explanation, so I'd be fine with them thinking of it along those lines *at first* as long as they understand it's an approximation of how things really are.
Ray
CC BY-SA 3.0
2017-12-22T19:31:23.423Z
@Ray: The only sense in which it "is" an integer is that the bits of its representation can be interpreted as an integer, which is also true for floating point types, and I wouldn't say that they "are integers". For C implementations common in the past 2-3 decades with flat linear address spaces, *as an implementation detail* there's also a partial algebraic correspondence between pointers and integers. I say "partial" because many operations that are defined on the int side are not defined on the pointer side. But other implementations are certainly still possible...
R.. GitHub STOP HELPING ICE
CC BY-SA 3.0
2017-12-22T19:32:12.590Z
...and may gain traction again with interest in memory-safety or with embedding C in nontraditional environments (like in a JS-based web ecosystem via web assembly or similar).
R.. GitHub STOP HELPING ICE
CC BY-SA 3.0
2017-12-22T19:47:05.797Z
@R.. True enough. I taught this at an introductory level, so that level of detail *remained* covered by the "There are a few details I'm glossing over" disclaimer, whereas the "`ptr+n` actually adds `n * sizeof(*ptr)` bytes issue might have actually been discussed eventually. I *could* have explained that a pointer is defined in terms of the behavior of certain operators when applied to it on the abstract machine, and that the implementation is permitted to use any representation that yields the correct behavior, per the as-if rule, but that would just confuse them worse.
Ray
CC BY-SA 3.0
2017-12-22T23:18:13.363Z
Pointers may work like mailbox numbers in the language invented by Dennis Ritchie's, but students need tor realize that the langauge favored by "modern" compilers is far less logical, and pointers will only behave like sensibly if certain ill-defined rules are followed.  Note that the rules used by compilers are similar to the ones in the Standard, but compilers sometimes disregard the Standard in cases where following it would disallow optimizations they want to perform, and think the Standard should allow.
supercat
CC BY-SA 3.0
2017-12-22T23:31:16.200Z
@R..: Ritchie's Language does offer "secret" insights into how real computers actually work.  It's important that students are aware, however, that some implementation lets people write code for actual machines while others are limited to programming "abstract" machines that impose rules more restrictive than those of actual machines, and which will misbehave in weird and arbitrary fashion if code deviates from those rules (even in cases where the actual machine would have behaved predictably).
supercat
CC BY-SA 3.0
2017-12-23T00:56:31.860Z
@supercat is demonstrating my point very well. :-)
R.. GitHub STOP HELPING ICE
CC BY-SA 3.0
2017-12-21T22:33:12.860Z
2017-12-21T22:33:12.860Z
Ray
<p><strong>Note:</strong></p>

<p><em>I was under the impression that this question was by a faculty asking for advice on best practices for teaching a course on C. Instead it's a question by a proactive student that is disappointed with the department's approach and wants to help educate his peers on best practices.</em></p>

<p><em>I believe that my answer is wrongly targeted but I'm leaving it here as I feel that it might hold some value to others.</em></p>

<p>--</p>

<p>When I went to school for programming our department had a very interesting approach which, in my opinion, helped to mitigate a lot of the confusion surrounding a first introduction.</p>

<p><strong>Provide a very rigid style guide</strong></p>

<ul>
<li>We had department-wide coding guidelines which were adhered to for all courses (much like when working for a company) so not only was code between students fairly consistent but also consistent between assignments for the <em>same</em> student. This is often overlooked and is in my opinion one of the most important things when teaching what literally amounts to be a <em>foreign language</em>.</li>
</ul>

<p><strong>Provide some form of static analysis for both style and logic</strong></p>

<ul>
<li>Every assignment was passed through a "style checker" written by the department that verified a combination of style conformity and basic linting for static error checking. This further reinforced adhering to a single style of coding and the linting was helpful and helped us to not be afraid of output warnings and errors.</li>
</ul>

<p><strong>Provide unit tests so that students can focus on the implementation rather than the formatting</strong></p>

<ul>
<li>Every assignment to be submitted was run through unit tests that verified input/output. This was tremendously helpful as it allowed us to spend less time on the math and more on the implementation and practical application of the code we were writing to solve a problem.</li>
</ul>

<p><strong>Focus on a standard and cross-platform tool-chain and leverage it to teach principals that are applicable to other environments; teach them the language not an IDE</strong></p>

<ul>
<li>Compilers and the aforementioned tools were available only from the department "Linux lab" computers. We were tasked with learning the command line and text editor of our choice (<code>nano</code>/<code>emacs</code>/<code>vi</code>) and compilation was done directly at the command line with <code>g++</code>. We were also taught how to <code>ssh</code> into the Linux lab so that we could work off-campus. This provided a simple environment without all of the extraneous features of IDEs and a basic introduction to both a Unix-like environment and command line compiling.</li>
</ul>

<p><strong>Put blinders on your students and choose to use a subset of the language to force students to think about solving problems with the language itself rather than through a library</strong></p>

<ul>
<li>All classes for teaching programming principals stripped everything to the bare minimum so that we were learning not only the core of the language (C++ in this case) but eschewed even the STL; for example, we programmed all of our data structures by hand. We learned the tools and the language which allowed us to later understand what a given library was doing under the hood rather than it being a black box.</li>
</ul>

<p><strong>Tell them where to go for resources</strong></p>

<ul>
<li>It might seem like second nature to us but new students don't know where to go for resources and may not think beyond their textbook. Websites that provide an overview of the language, its keywords and headers, such as <a href="http://en.cppreference.com/w/c/language" rel="nofollow noreferrer"><code>http://en.cppreference.com/w/c/language</code></a> that are easily browse-able on an internet device are excellent. Man pages are also useful but remember that this is a foreign concept so remember to demonstrate how to use it frequently during class. A small library of books as references can also provide additional insight on how to tackle a problem outside of a course textbook.</li>
</ul>

<p>For those who are new to programming, this rigid conformity is essential to block out so much of the background noise and flip-flopping on coding style that is so prevalent for new students.</p>

<p>There was no question for us about where top put braces, semi-colons, white-space, and comments. There was no question about basic linting. There was no question about whether a program worked or not since it was run through unit tests.</p>

<p>I cannot stress enough how effective this approach was for me as a student. It gave us blinders that shielded us from the unimportant details and allowed us to focus on the most important things in each lesson and made learning to program a very satisfying and extremely rewarding experience.</p>

CC BY-SA 3.0
2017-12-29T04:20:23.383Z
This answer is excellent, and tells me that you probably have quite a bit to contribute to this site (and I hope that you do!)  Did the highly regularized style specifications make it more difficult to detect cheating?
Ben I.
CC BY-SA 3.0
2017-12-23T08:43:07.003Z
2017-12-27T15:50:00.100Z
2017-12-27T15:50:00.100Z
Zhro
<h2>Lint</h2>
<p>I would not program in <code>C</code> without a lint tool e.g. <code>gcc -Wall</code> or <code>pclint</code>/<code>flex-lint</code>, unfortunately the latter two are proprietary.</p>
<p>However you need to show that error/warning messages are your friend. There are not an accident. Someone spent time writing them, to help you. Read them, and fix the underlying problem. Often I have seen people finding ways to get the error/warning to go away, but changing the code in a convoluted way, that makes it worse, but has no error.</p>
<h2>Brackets {} are not an option.</h2>
<p>I don't care what the standard says, always use brackets.</p>
<h2>Comments</h2>
<p>Well written code with good names, is better than code with bad names and comments. Use procedure/function names, and variable names to comment your code.</p>
<h3>Bad</h3>
<pre><code>i++; /*Increment i*/
i++; /*Increment index*/
</code></pre>
<h3>Better</h3>
<pre><code>index++;
</code></pre>
<h2>Local consistency</h2>
<p>Style must be locally consistent, and preferably globally consistent. Global consistency may suffer if there are more than one person on the team. But local consistency must never suffer.</p>
<h2>Nouns, verbs, adjectives</h2>
<p>Variable name should be nouns or for booleans adjectives.
Procedures should be verbs. Functions should be as for variables.</p>
<p>Full command/query separation is not easy in <code>C</code> as you would have to program Object Oriented.</p>

CC BY-SA 3.0
2017-12-21T17:27:28.843Z
C was created at Bell Labs. If you worked there it was a "firing offense" if you didn't brace all. I.E. Brackets are NOT an option. Make your fingers do it so you don't need to even think about it. If you have a good IDE, the close bracket will be correctly placed if you open a brace and hit return.
Buffy
CC BY-SA 3.0
2017-12-21T19:18:00.713Z
CQRS is probably out of scope for an introductory course anyway.
Robert Harvey
CC BY-SA 3.0
2017-12-21T21:18:46.350Z
I just looked-up CQRS. It does not seem to be the same thing as command query separation (CQS).
ctrl-alt-delor
CC BY-SA 3.0
2017-12-22T00:40:44.203Z
I would also add a note about "Global Variables" and "Code Reusability" to your list.
jjk_charles
CC BY-SA 3.0
2017-12-22T09:41:17.870Z
@jjk_charles Global variables are forbidden in the lecture and are an instant fail. Code Reusability is actually a good idea to have that explicit and not just implicit!
Git
CC BY-SA 3.0
2017-12-22T09:51:57.590Z
My $0.03: probably `i` is well-known enought not to adding much information over index. Similarly no points for guessing what `v` and `a` are in physics simulator. `pos[i] += v[i] * dt; v[i] += a[i] * dt;` is probably clearer than `positionOfObjectsArray[index] += velocityOfObjectArray[index] * timeDifference; velocityOfObjectArray[index] += accelerationOfObjectArray[index] * timeDifference;`.
Maja Piechotka
CC BY-SA 3.0
2017-12-22T19:05:37.453Z
A couple major points of disagreement. First, comments, **both are bad**. Commenting `i++` to explain what the statement does is not useful, it's clutter and trains new programmers not to actually be intentional about good comments. A good comment might be something like `/* Skip an additional element because the code below assumes... */` or similar. Comments are to explain purpose, not to translate C to English.
R.. GitHub STOP HELPING ICE
CC BY-SA 3.0
2017-12-22T19:10:05.147Z
Second, while being inflexible about braces or variable naming may be good for the purpose of a course, you need to prepare students to be flexible about coding style and policies, because they **will differ** in real-world work. Being led to believe they've been taught the "one true way" about anything that's a matter of style or tradeoffs sets them up to doubt the competence of programmers/teams that do things differently for well-justified reasons or just because it's not a big deal.
R.. GitHub STOP HELPING ICE
CC BY-SA 3.0
2017-12-22T20:34:21.897Z
@MaciejPiechotka - While you make an argument that i, v, and a are equally readable in context to the longhand variable names. I was only "pretty sure" what v and a meant, as I don't normally work with physics. The second version is not only more readable, but unmistakable. In your first example, I could assume that v stood for vector, and a for acid, or something. I cannot make that mistake in your second example. There is a lot of value in being 100% sure you eliminated a mistake over being 99% sure. Especially when it doesn't cost you anything to add the 1%.
EvSunWoodard
CC BY-SA 3.0
2017-12-22T22:43:54.977Z
@EvSunWoodard No, I'm claim they are _more_ readable as they are a) domain specific word no different than lingo of any other buissness client and b) if you have sufficiently long equations you may need to spill over to next lines making it less readable by sheer verbosity. Those are toy examples but consider `(legendre(x, k).plus(legendre(x, k - 1).times(Float64.valueOf(eta_k)).plus(legendre(x, k + 1)).times(Float64.valueOf(1 + eta_k)))).times(Float64.valueOf(0.5))`. If you know domain it's more or less clear - setting aside problem of lack of operator overloading in Java (...)
Maja Piechotka
CC BY-SA 3.0
2017-12-22T22:50:53.223Z
(cont.) `(legendre(x, k) + legendre(x, k - 1) * eta_k + legendre(x, k + 1) * (1 + eta_k)) * 0.5;` would be clearer. However changing `legendre` to `solutionToLegndreEquation` or `k` to `numberOfCalculationPoits` etc. would not help without looking at the original paper... which used the same notation so changing notation would make things even more confusing. In similar way changing `for (size_t i = 0; i < FOO_SIZE: i++) foo[i] = i;` to `for (size_t indexInFoo = 0; indexInFoo < FOO_SIZE; indexInFoo++) foo[indexInFoo] = indexInFoo;` doesn't help much as virtually everyone uses `i` for index.
Maja Piechotka
CC BY-SA 3.0
2017-12-23T12:31:33.270Z
Yes use abbreviation, if they are used in the domain, e.g. physics. OR tv for television, because these are well known, but don't make up new ones.
ctrl-alt-delor
CC BY-SA 3.0
2017-12-21T14:38:31.517Z
2017-12-21T14:38:31.517Z
2020-06-18T08:36:57.023Z
ctrl-alt-delor
<p>Your list is a bit narrow in one sense. I assume it is well matched to your specific course, but probably doesn't represent "best practice" in general. For example, <em>valgrind</em> is limited to linux, which suits you better than me. But the idea of including memory testing, for example, is a good idea no matter the specific tool. Similarly for <em>git</em>. There are alternatives, but code management and version control is the big idea. </p>

<p>But one item I find missing here, but also essential is some sort of tool for unit testing. There are <a href="https://en.wikipedia.org/wiki/List_of_unit_testing_frameworks#C" rel="noreferrer">many</a> available and building good clean code requires pre testing everything to arrive at a good result painlessly. </p>

<p>Another suggestion I'd make, though this may be your intent already, is that you show many of your ideas in the context of a large and complicated program. You state that dealing with such projects/programs is an issue in the course at the beginning of your post and that may actually be the biggest issue. So don't present your tool set using only "toy" programs. </p>

<p>If the projects are done in teams you may also want to include something specific about how to be successful in a team environment. Many of your students may not have experienced that. There is a book, in fact, named <a href="https://rads.stackoverflow.com/amzn/click/1576751554" rel="noreferrer">Teamwork is an Individual Skill</a> that has valuable hints for any professional. </p>

CC BY-SA 3.0
2017-12-21T14:05:09.847Z
We thought about using the final assignment from a previous year (around 800 LoC). Do you think that is big enough, or should we use a bigger project? If so, do you have one in mind? Since most open source projects that i have had a look on the code, have terrible code documentation.
Git
CC BY-SA 3.0
2017-12-21T14:10:03.440Z
If that is the scale of the assignment to come then it is probably a good choice. Others may need something bigger in a similar context. It is probably a mistake to overwhelm students unnecessarily. And you may need to doctor whatever code you find before use. You could also use the sessions to improve the code, of course. That might be especially valuable in this context. You don't mention whether the students start the project with a given codebase or start from scratch. That can affect how you proceed, but the toolset would likely be the same.
Buffy
CC BY-SA 3.0
2017-12-22T09:39:22.700Z
They start without any codebase, just the standard libraries.
Git
CC BY-SA 3.0
2017-12-21T13:49:15.770Z
2017-12-21T13:49:15.770Z
Buffy
<p>This might be controversial, but I would make a point to explain that <code>goto</code> is not always considered harmful (and explain that the context of Dijkstra's "Go To Statement Considered Harmful" was about using available control structures).  In C, there aren't very good control structures for releasing resources; in the absence of them, <code>goto</code> works well, and people should not be afraid to use it for that purpose.</p>

<p>People new to C inevitably have trouble doing manual resource management and end up with memory (or other resource) leaks.  Dealing with it is hard.  People then think C is harder than it is.  Trying to follow a single-entry, single-exit (SESE) pattern can reduce the cognitive burden and make code easier to maintain in the future.</p>

<p>For example:</p>

<pre><code>char* foo(const char* directory)
{
    char* path = make_full_path(directory, CONSTANT_FILENAME);
    if (path == NULL)
    {
        return NULL;
    }

    FILE* fp = fopen(path, "r");
    if (fp == NULL)
    {
        free(path);
        return NULL;
    }

    char line[1024];
    fgets(line, sizeof line, fp);

    char* copy = malloc(strlen(line) + 1);
    if (copy == NULL)
    {
        fclose(fp);
        free(path);
        return NULL;
    }

    strcpy(copy, line);

    fclose(fp);
    free(path);

    return copy;
}
</code></pre>

<p>Simpler:</p>

<pre><code>char* foo(const char* directory)
{
    char* path = NULL;
    FILE* fp = NULL;
    char* copy = NULL;

    path = make_full_path(directory, CONSTANT_FILENAME);
    if (path == NULL)
    {
        goto exit;
    }

    fp = fopen(path, "r");
    if (fp == NULL)
    {
        goto exit;
    }

    char line[1024];
    fgets(line, sizeof line, fp);

    copy = malloc(strlen(line) + 1);
    if (copy == NULL)
    {
        goto exit;
    }

    strcpy(copy, line);

exit:
    if (fp != NULL)
    {
        fclose(fp);
    }
    free(path);

    return copy;
}
</code></pre>

<p>And imagine that we need to introduce some new, temporary allocation to the code.  In the first version, that would require considering where the new allocation occurs and inspecting the various exit points to make sure that each exit point cleans up the new allocation if necessary.  In the second version, it requires only adding the variable to the beginning, initializing it to a sentinel value (e.g. <code>NULL</code>), and then unconditionally freeing it at the end.</p>

CC BY-SA 3.0
2017-12-22T09:33:37.487Z
Although very usefull,  the lecturer actually substracts points for each use of of the "goto" statement. but thank you for a clean example how to actually use it.
Git
CC BY-SA 3.0
2017-12-22T20:54:11.120Z
Why not factor out the resource management as a separate function?
Buffy
CC BY-SA 3.0
2017-12-23T01:24:58.703Z
@Buffy Because they're local variables, and it writing separate structs and functions to deal with resource management for every combination of such variables does not scale well.
jamesdlin
CC BY-SA 3.0
2017-12-23T01:38:59.830Z
Nor does repeating code every time a given combination recurs. Especially if things change and you have to revisit every instance. Abstraction is your friend.
Buffy
CC BY-SA 3.0
2017-12-23T04:03:42.600Z
@Buffy If you find yourself using the same combination of resource allocations frequently, yes, clearly you should abstract some of that away.  That won't be true all the time.
jamesdlin
CC BY-SA 3.0
2017-12-23T07:28:32.353Z
@Buffy Additionally, even if the resources could be freed by a single function, I would still advocate using `goto`.  It's still easier to maintain; if you need to change the signature or semantics of you resource deallocation function, you'd won't need to revisit every exit point.  Also, doing `goto exit;` at each exit point is simpler than `FreeMyResources(...); return NULL;` if you need to return something.
jamesdlin
CC BY-SA 3.0
2017-12-23T09:58:27.117Z
That's one of the two acceptable uses of `goto` (the other being breaking from two loops at once or jumping out of a loop when you found what you're looking for). I'm still not sure if I would bring that up in an introductory programming course, before they've learned the more important control structures (just imagine the result when a student forgot about `while`, but remembered `goto`.)
ilkkachu
CC BY-SA 3.0
2017-12-23T10:00:14.947Z
In any case, you could make more than one distinct `exit` label there so that each one just does the necessary cleanup, implicitly falling to the next one in order, e.g. `exit3: fclose(); exit2: free(); exit1: return`.
ilkkachu
CC BY-SA 4.0
2020-07-03T17:29:07.393Z
I disagree. `goto` should not be used in C /C++ and similar language. It should be used in assembly where no other looping or branching technique does not exist. One simple `goto` could ruin the readability of the whole program. Your code is just for a simple program. What if when they would write hundreds of lines of code? This is my personal opinion. Thanks.
Enamul Hassan
CC BY-SA 4.0
2020-07-03T17:56:47.953Z
@EnamulHassan 1. There are *many* things (particularly in C) that can ruin code readability. Heaven forbid that people are taught how to use `goto` *responsibly* to keep code readable! 2. I agree that structured alternatives should be used instead of `goto` *when available* (e.g. `for`, `while`). That's Dijkstra's paper. However, the fact remains that C *lacks* error handling or resource management constructs, making `goto` the only sane solution for a large codebase. (Note that C is *not* C++. I would not recommend `goto` for C++ since C++ does have a resource management construct: RAII.)
jamesdlin
CC BY-SA 4.0
2020-07-03T17:57:47.227Z
3. `goto` for resource management is *especially* important for large, complex programs.  For a *simple* program, releasing resources manually at each exit point is less of a problem.  For a *large* program, resource management is an even bigger problem, and using `goto` is far less error-prone.
jamesdlin
CC BY-SA 3.0
2017-12-21T22:41:53.923Z
2017-12-21T22:41:53.923Z
jamesdlin
<p>Two important concepts that seem absent from the list, and that I often find are barely developed in even fairly advanced students are testing and debugging. I would suggest some brief introduction along the following lines:</p>

<p>Unit test and integration test; test scaffolding; test-first strategy; exhaustive test vs. (targeted) random test vs. testing manually determined corner cases.</p>

<p>Use of assertions; logging, possibly at various debug levels; insertion of <code>printf()</code> calls for adhoc debugging; use of a debugger: break points, single-stepping, observing variables, watchpoints; code simplification to create an <a href="https://stackoverflow.com/help/mcve">MCVE</a>.</p>

CC BY-SA 3.0
2017-12-21T19:16:41.317Z
Welcome to CSEducators. I agree that understanding assertions is an important idea.
Buffy
CC BY-SA 3.0
2017-12-21T19:01:31.723Z
2017-12-21T19:01:31.723Z
njuffa
<p>If you want to teach the students some valuable real life skills, helping them in writing programs without bugs, teach them about <strong>sequence points</strong> and <strong>integer promotion</strong>.</p>

<p>If a C programmer does not understand those concepts, he or she is bound to make some serious mistakes sooner or later.</p>

<pre><code>#include &lt;stdlib.h&gt;
#include &lt;stdio.h&gt;

static int n = 100;

static int f1(void) {
    n++;
    return n;
}

static int f2(void) {
    n++;
    return n;
}

static int f3(int a, int b, int c, int d)
{
    printf("Undefined behaviour allows the compiler to do anything!\n");
    printf("n = %d, a = %d, b = %d, c = %d, d = %d\n", n, a, b, c, d);
    return n + a + b + c + d;
}

int main(int argc, char *argv[])
{
    unsigned int a = 10;
    signed int b = -10;

    if (a &lt; b) {
        printf("This is executed despite that (%u &lt; %d) is not true\n", a, b);
    }

    n = f3(n, f1(), f2(), n++);

    return EXIT_SUCCESS;
}
</code></pre>

<p>Compiled with gcc:</p>

<pre><code>This is executed despite that (10 &lt; -10) is not true
Undefined behaviour allows the compiler to do anything!
n = 103, a = 103, b = 103, c = 102, d = 100
</code></pre>

<p>Compiled with clang:</p>

<pre><code>This is executed despite that (10 &lt; -10) is not true
Undefined behaviour allows the compiler to do anything!
n = 103, a = 100, b = 101, c = 102, d = 102
</code></pre>

<p>Even if the students do not fully grasp those two concepts, being aware of them is important.</p>

CC BY-SA 3.0
2018-01-28T22:29:35.287Z
2018-01-28T22:29:35.287Z
hlovdal
<p>That's really a nice question and I appreciate that you consider the noise around programing like version control (git) and coding style.</p>

<p>View things important to me are:</p>

<p><strong><em>Flowcharts:</em></strong> or the art of coding on a piece of paper. When I was a student, our teacher insisted on designing the logic on paper before typing it into the machine. Maybe this sounds old school but for larger projects I still take the pencil first. This helps to understand and focus on logic.</p>

<p><strong><em>Algorithms:</em></strong> or defining the problem and finding a solution to it. Mostly C programs are likely command line programs and no full blown apps. So the best use  and challenge for C is to learn concepts of <strong><em>Algorithms</em></strong> and <strong><em>Computing</em></strong>
It's always fun to me to draw concepts on a whiteboard, this helps to get some imagination and creativity for the topic.</p>

<p><strong><em>Debugging:</em></strong> or how to get to know what your machine is doing right now. Programming is like manipulating bits and bytes in the Memory (tag: Von Neumann architecture). To visualize what's going helps to understand what the machine is doing and much more help to find and understand your mistakes (semantic failures).
With the debugger you can walk through your code and see variable and memory change. Especially when it comes to different types, arrays, pointers, and memory location (stack, heap, registers, etc.) it is good to know how to look that up.</p>

<p>If you like to teach "how to google their problem" it would be an advice to teach how to <strong><em>ask the right question</em></strong></p>

CC BY-SA 3.0
2018-01-31T10:41:35.970Z
>"ask the right question" thats what i meant =)
Git
CC BY-SA 3.0
2018-01-29T21:24:58.257Z
2018-01-29T22:07:19.903Z
2018-01-29T22:07:19.903Z
chris.stckhmr
<p>At our University, we have in the first semester a very difficult C Introductory Course, that consists of presenting a shortened version of the language specification: What are for/while loops, if clause, what is a pointer and so on.</p>

<p>But they never show how good C code in a more complicated application should look. What version control is, what <a href="https://valgrind.org" rel="nofollow noreferrer">Valgrind</a> is (a gnu tool for detecting memory leaks) and so on.
For the many new (about 60%) to programming or C, the group projects are quite a knockout (about 40%). </p>

<p>Some motivated students and I decided to offer a "best practices" session before the first assignment is handed out and after the lecture has finished.
For the students to have a better chance of finishing this course successfully.</p>

<p>Our selected Chapters are these:</p>

<ul>
<li>how to compile (clang and gcc and their flags and warnings)</li>
<li>valgrind</li>
<li>make </li>
<li>coding style

<ul>
<li>best practices -> how to allocate memory, typedefs, file operations</li>
<li>basic program flow, some simple patterns</li>
</ul></li>
<li>git</li>
<li>pitfalls specific to this course and C in general</li>
<li>how to ask the right question (and in turn how to google their problems)</li>
<li>how to use the  manpage</li>
</ul>

<p>Are there points missing? Is there something that we shouldn't do?
In short, how to improve the content. We are planning on 3 Sessions with around 3 hours each.</p>

CC BY-SA 3.0
2017-12-21T13:33:16.230Z
Welcome to CSEducators. We hope to see more of you.
Buffy
CC BY-SA 3.0
2017-12-21T18:38:12.730Z
As a working software engineer I implore you: teach ideas rather than tools. E.g. how/why to use version control rather than focusing on git.
Jake
CC BY-SA 3.0
2017-12-21T19:16:27.410Z
If this is a first semester C course, your curriculum shouldn't contain  *any* of the tools your propose.  They need to know how to link, compile and debug.
Robert Harvey
CC BY-SA 3.0
2017-12-21T19:23:36.563Z
`<shamelessPlug>`Dear HNQ visitors, [this question](https://cseducators.stackexchange.com/questions/4058/enjoyable-and-or-fun-way-to-explain-cmake) was asked yesterday, and is related enough to this one that it might also benefit from your expertise. `</shamelessPlug>`
Ben I.
CC BY-SA 3.0
2017-12-22T09:43:23.307Z
@Jake the reason for git is, that many students, send their code via email and facebook. Wich is quite contraproductive, if they do the merge all by hand every few days.
Git
CC BY-SA 3.0
2017-12-22T09:45:49.910Z
@RobertHarvey, how would you propose for them to  share the code in the groupproject? Make, makes submission, compiling and debugging way easier in the way that they dont need to enter every flag, and also every groupmember uses the same setup for debugging execution and compiling.
Git
CC BY-SA 3.0
2017-12-22T09:49:02.103Z
@drewbenn Im a student, as are the other parties involved planning this 3 session course. Also, shell commands are not in the scope of this.
Git
CC BY-SA 3.0
2017-12-22T09:55:53.600Z
For C - checking the return values instead of assuming it will succeed. Even if this is `if (someCall() == false) { fprintf(stderr, "error <some description>\n"); abort(); }`.
Maja Piechotka
CC BY-SA 3.0
2017-12-22T10:28:57.763Z
@drewbenn The following points knock them out: they dont know how to test, they dont know how to check for memory leaks, they have no concept of capsulating for example memory allocation(single function for memory allocation and initialisation), program flow -> clean exit if error is encountered, etc
Git
CC BY-SA 3.0
2017-12-22T15:35:12.587Z
@gismo: Would the source control be maintained for them?  Source control is not a mountain of detail I would want in my first-semester C class.  Is this a two-semester class?  See also Jake's comment above.
Robert Harvey
CC BY-SA 3.0
2017-12-22T15:57:41.537Z
@RobertHarvey If you mean by "maintained" hosted, the university provides a git server with unlimited repos. Its a single semester.  Why is everybody focusing on the class? We would just do about 3 sessions of about 3 hours. The focus on git is because the uni provides one. Additionally to why, we would just introduce a basic workflow with maybe the cherrypick functionality (binary search for the last working revision)
Git
CC BY-SA 3.0
2017-12-22T19:24:02.243Z
Is there any possibility that a different language could be used? C is not the easiest to learn, especially if you want to teach safe, effective C.
DylanSp
CC BY-SA 3.0
2017-12-22T19:24:45.437Z
Also, [this article](https://blog.regehr.org/archives/1393) on teaching C is probably a good source.
DylanSp
CC BY-SA 3.0
2017-12-22T21:27:52.547Z
What about gdb? A debugger allows students to reason about code interactively.
Winny
CC BY-SA 3.0
2017-12-23T00:03:18.420Z
*" the reason for git is [...]"* That is the reason for *source control*. @Jake was asking you to distinguish between the category of tool and the particular implementation you're going to cover (chosen in this case because the school hosts a `git` repository). So, `gcc` is just one compiler; `gdb` is just one debugger; `valgrind` is just a particular profiler/leak-detector. If your students stay in this business they will replace tools,  but they will keep using the same classes of services.
dmckee --- ex-moderator kitten
CC BY-SA 3.0
2017-12-23T09:38:57.780Z
I'm very happy to see you encouraging the use of `make`. I use it extensively now and believe that it is a staple of programming that everyone should know. I would also recommend demonstrating how to use `#include` and the breaking up of a project into multiple files; include guards, etc.
Zhro
CC BY-SA 3.0
2017-12-23T10:03:41.447Z
Would this be an introductory course on programming, an introductory course on C (where the students have programmed before in some other language), or a best-practices programming course (which has more to do with engineering practices, and not just the programming part)?
ilkkachu
CC BY-SA 3.0
2017-12-23T11:20:00.797Z
How to use the debugger.
Dawood ibn Kareem
CC BY-SA 3.0
2017-12-26T14:15:12.753Z
@ilkkachu They had a python lecture wich is basicly just a crash course (1 Month) before the c lecture.
Git
<curriculum-design><best-practice><coding-style><c>
What should be included in a best practices C course?
# What should be included in a best practices C course?

(Asked by: username_0 on 2017-12-21)

At our University, we have in the first semester a very difficult C Introductory Course, that consists of presenting a shortened version of the language specification: What are for/while loops, if clause, what is a pointer and so on.

But they never show how good C code in a more complicated application should look. What version control is, what [Valgrind](https://valgrind.org) is (a gnu tool for detecting memory leaks) and so on.
For the many new (about 60%) to programming or C, the group projects are quite a knockout (about 40%).

Some motivated students and I decided to offer a "best practices" session before the first assignment is handed out and after the lecture has finished.
For the students to have a better chance of finishing this course successfully.

Our selected Chapters are these:

* how to compile (clang and gcc and their flags and warnings)
* valgrind
* make
* coding style
  + best practices -> how to allocate memory, typedefs, file operations
  + basic program flow, some simple patterns
* git
* pitfalls specific to this course and C in general
* how to ask the right question (and in turn how to google their problems)
* how to use the manpage

Are there points missing? Is there something that we shouldn't do?
In short, how to improve the content. We are planning on 3 Sessions with around 3 hours each.

**Tags:** curriculum-design, best-practice, coding-style, c

> **Comments:**
> **username_1**: Welcome to CSEducators. We hope to see more of you.  
> **username_2**: As a working software engineer I implore you: teach ideas rather than tools. E.g. how/why to use version control rather than focusing on git.  
> **username_3**: If this is a first semester C course, your curriculum shouldn't contain  *any* of the tools your propose.  They need to know how to link, compile and debug.  
> **username_4**: `<shamelessPlug>`Dear HNQ visitors, [this question](https://cseducators.stackexchange.com/questions/4058/enjoyable-and-or-fun-way-to-explain-cmake) was asked yesterday, and is related enough to this one that it might also benefit from your expertise. `</shamelessPlug>`  
> **username_0**: @username_2 the reason for git is, that many students, send their code via email and facebook. Wich is quite contraproductive, if they do the merge all by hand every few days.  
> **username_0**: @RobertHarvey, how would you propose for them to  share the code in the groupproject? Make, makes submission, compiling and debugging way easier in the way that they dont need to enter every flag, and also every groupmember uses the same setup for debugging execution and compiling.  
> **username_0**: @drewbenn Im a student, as are the other parties involved planning this 3 session course. Also, shell commands are not in the scope of this.  
> **username_5**: For C - checking the return values instead of assuming it will succeed. Even if this is `if (someCall() == false) { fprintf(stderr, "error <some description>\n"); abort(); }`.  
> **username_0**: @drewbenn The following points knock them out: they dont know how to test, they dont know how to check for memory leaks, they have no concept of capsulating for example memory allocation(single function for memory allocation and initialisation), program flow -> clean exit if error is encountered, etc  
> **username_3**: @gismo: Would the source control be maintained for them?  Source control is not a mountain of detail I would want in my first-semester C class.  Is this a two-semester class?  See also username_2's comment above.  
> **username_0**: @RobertHarvey If you mean by "maintained" hosted, the university provides a git server with unlimited repos. Its a single semester.  Why is everybody focusing on the class? We would just do about 3 sessions of about 3 hours. The focus on git is because the uni provides one. Additionally to why, we would just introduce a basic workflow with maybe the cherrypick functionality (binary search for the last working revision)  
> **username_6**: Is there any possibility that a different language could be used? C is not the easiest to learn, especially if you want to teach safe, effective C.  
> **username_6**: Also, [this article](https://blog.regehr.org/archives/1393) on teaching C is probably a good source.  
> **username_7**: What about gdb? A debugger allows students to reason about code interactively.  
> **username_8**: *" the reason for git is [...]"* That is the reason for *source control*. @username_2 was asking you to distinguish between the category of tool and the particular implementation you're going to cover (chosen in this case because the school hosts a `git` repository). So, `gcc` is just one compiler; `gdb` is just one debugger; `valgrind` is just a particular profiler/leak-detector. If your students stay in this business they will replace tools,  but they will keep using the same classes of services.  
> **username_9**: I'm very happy to see you encouraging the use of `make`. I use it extensively now and believe that it is a staple of programming that everyone should know. I would also recommend demonstrating how to use `#include` and the breaking up of a project into multiple files; include guards, etc.  
> **username_10**: Would this be an introductory course on programming, an introductory course on C (where the students have programmed before in some other language), or a best-practices programming course (which has more to do with engineering practices, and not just the programming part)?  
> **username_11**: How to use the debugger.  
> **username_0**: @username_10 They had a python lecture wich is basicly just a crash course (1 Month) before the c lecture.  

---

## 11 answers

### Answer by username_14 on 2017-12-22. Score: 8 | Accepted answer

## Too much, too fast

"First semester". If I parse correctly, you say 60% students are **new to programming**.

You say "The following points knock them out: they don't know how to test, they don't know how to check for memory leaks, they have no concept of encapsulating". And you say "group assignments".

Taken together, it looks like this course is "introductory" only in this sense it will introduce part of students to the idea that this university doesn't want to teach them (programming or even teach them how to learn programming), but it wants to filter them out.

You cannot change that fact. You cannot help everyone, you can help some.

Either you want:

* to help programmers to become better
* to help some non-programmers to become programmers (will work 10% of the time in your setting)
* to help all non-programmers to learn a bit, but probably not enough to let them pass

Presently your mini-course is a big mish-mash. Come on: someone needs to be informed how to google stuff? Really? And the next minute you talk about git? To help who, in what way...? Don't waste everyone's time, narrow it down:

* to help programmers to become better

  + valgrind
  + coding style
    - best practices -> how to allocate memory, typedefs, file operations
    - basic program flow, some simple patterns
  + git
  + pitfalls in general
* to help some non-programmers to become programmers (will work 10% of the time in your setting)

  + you want to give them ready-made stuff; their heads are bound to explode, the more boilerplate you give them, the less the explosion
    - make
      * boilerplate gcc flags included, etc
    - pitfalls specific to this course
    - the rest will come later (i.e. someday they will decide they need to improve on memory handling - but not today for sure, someday they will decide to migrate version control out of their Facebook - not today)
* to help all non-programmers to learn a bit, but probably not enough to let them pass
  + "how to google their problems"
  + "how to use the manpage"

> **Comments:**
> **username_1**: Welcome to CSEducators. A somewhat different perspective, but a dose of reality. Thanks.  
> **username_1**: Sadly, enrollments are so high at this moment (late 2017) that many departments are, indeed, trying to winnow the students. I don't know if that is the situation here, but it has been discussed elsewhere. This happens every few years, actually, and is often followed by a drought. The fact that many of the topics discussed in this thread were omitted from the course in question may be an indicator that this is the case, actually.  
> **username_0**: Thank you, for making clear what i did know deep down, but didnt really consciously knew. If nothing better pops up in the next few days, youll get the accepted answer.  

---

### Answer by username_15 on 2017-12-21. Score: 11

I think an important aspect to any best-practices list is the rationale behind it. It is entirely too common for a programmer to, for example, insist that gotos and global variables are evil and then proceed to use exceptions and singletons to create the exact same problems that got those features proscribed in the first place.

So I suggest that when introducing a rule of thumb, you don't just give examples of code that follows the rule, but rather examples of the sort of awful code that led to the rule being created. Let them understand *why* the rule exists both so they can avoid making similar mistakes and also recognize when the rule *isn't* applicable. (Of course, no examples will be as helpful as allowing them to write terrible code and then try to modify it, but you have limited time.)

A related recommendation that is somewhat tangential to the best practices lecture, but related to the question of how to help them complete the course successfully:
Don't assume that the more abstract explanations of topics are necessarily easier to understand than the ones that get into the gritty details.

I've had a number of students who were completely confused when we tried to explain pointers using diagrams of boxes and arrows, but as soon as I sketched out a table of memory (with addresses as indices), explained that a pointer is just an integer that is used to "index memory", and then walked through a block of code, updating the table as I went, they understood it almost immediately. (We put the abstractions back in place when it was time to work with higher level data structures, *after* they understood the fundamentals.)

> **Comments:**
> **username_3**: Nice observations about pointers.  
> **username_15**: @RobertHarvey I almost left it out of the answer, since it's not really a best practice, but I've *never* seen students move from "complete confusion" to "complete understanding" as quickly as I have after giving that explanation, so I decided it was worth mentioning anyway.  
> **username_16**: Regarding *explained that a pointer is just an integer that is used to "index memory"*, this can be a double-edged sword. It can lead new C programmers to think they're in on the secret about "how things *really* work", which is actually oversimplified and wrong, and thereby insist on being allowed to do very wrong/against-best-practices things. Even `ptr+n` becomes confusing for new C programmers when they think that `ptr` *is* an integer rather than *has a representation as an integer*.  
> **username_15**: @R.. Whenever I need to simplify things, I let them know that I'm doing so.  That's the best middle ground I've found between letting them believe that an approximate explanation is precise, and trying (and failing) to explain everything at once.  That said, `ptr` *is* an integer.  It's just not an `int`.  But even `int` is a closer approximation of its type than `&**magic[42]->&a`, which is frequently how they seem to view it without this explanation, so I'd be fine with them thinking of it along those lines *at first* as long as they understand it's an approximation of how things really are.  
> **username_16**: @username_15: The only sense in which it "is" an integer is that the bits of its representation can be interpreted as an integer, which is also true for floating point types, and I wouldn't say that they "are integers". For C implementations common in the past 2-3 decades with flat linear address spaces, *as an implementation detail* there's also a partial algebraic correspondence between pointers and integers. I say "partial" because many operations that are defined on the int side are not defined on the pointer side. But other implementations are certainly still possible...  
> **username_16**: ...and may gain traction again with interest in memory-safety or with embedding C in nontraditional environments (like in a JS-based web ecosystem via web assembly or similar).  
> **username_15**: @R.. True enough. I taught this at an introductory level, so that level of detail *remained* covered by the "There are a few details I'm glossing over" disclaimer, whereas the "`ptr+n` actually adds `n * sizeof(*ptr)` bytes issue might have actually been discussed eventually. I *could* have explained that a pointer is defined in terms of the behavior of certain operators when applied to it on the abstract machine, and that the implementation is permitted to use any representation that yields the correct behavior, per the as-if rule, but that would just confuse them worse.  
> **username_13**: Pointers may work like mailbox numbers in the language invented by Dennis Ritchie's, but students need tor realize that the langauge favored by "modern" compilers is far less logical, and pointers will only behave like sensibly if certain ill-defined rules are followed.  Note that the rules used by compilers are similar to the ones in the Standard, but compilers sometimes disregard the Standard in cases where following it would disallow optimizations they want to perform, and think the Standard should allow.  
> **username_13**: @R..: Ritchie's Language does offer "secret" insights into how real computers actually work.  It's important that students are aware, however, that some implementation lets people write code for actual machines while others are limited to programming "abstract" machines that impose rules more restrictive than those of actual machines, and which will misbehave in weird and arbitrary fashion if code deviates from those rules (even in cases where the actual machine would have behaved predictably).  
> **username_16**: @username_13 is demonstrating my point very well. :-)  

---

### Answer by username_20 on 2017-12-21. Score: 8

This might be controversial, but I would make a point to explain that goto is not always considered harmful (and explain that the context of Dijkstra's "Go To Statement Considered Harmful" was about using available control structures).  In C, there aren't very good control structures for releasing resources; in the absence of them, goto works well, and people should not be afraid to use it for that purpose.
People new to C inevitably have trouble doing manual resource management and end up with memory (or other resource) leaks.  Dealing with it is hard.  People then think C is harder than it is.  Trying to follow a single-entry, single-exit (SESE) pattern can reduce the cognitive burden and make code easier to maintain in the future.
For example:
char* foo(const char* directory)
{
    char* path = make_full_path(directory, CONSTANT_FILENAME);
    if (path == NULL)
    {
        return NULL;
    }

    FILE* fp = fopen(path, "r");
    if (fp == NULL)
    {
        free(path);
        return NULL;
    }

    char line[1024];
    fgets(line, sizeof line, fp);

    char* copy = malloc(strlen(line) + 1);
    if (copy == NULL)
    {
        fclose(fp);
        free(path);
        return NULL;
    }

    strcpy(copy, line);

    fclose(fp);
    free(path);

    return copy;
}

Simpler:
char* foo(const char* directory)
{
    char* path = NULL;
    FILE* fp = NULL;
    char* copy = NULL;

    path = make_full_path(directory, CONSTANT_FILENAME);
    if (path == NULL)
    {
        goto exit;
    }

    fp = fopen(path, "r");
    if (fp == NULL)
    {
        goto exit;
    }

    char line[1024];
    fgets(line, sizeof line, fp);

    copy = malloc(strlen(line) + 1);
    if (copy == NULL)
    {
        goto exit;
    }

    strcpy(copy, line);

exit:
    if (fp != NULL)
    {
        fclose(fp);
    }
    free(path);

    return copy;
}

And imagine that we need to introduce some new, temporary allocation to the code.  In the first version, that would require considering where the new allocation occurs and inspecting the various exit points to make sure that each exit point cleans up the new allocation if necessary.  In the second version, it requires only adding the variable to the beginning, initializing it to a sentinel value (e.g. NULL), and then unconditionally freeing it at the end.

> **Comments:**
> **username_0**: Although very usefull,  the lecturer actually substracts points for each use of of the "goto" statement. but thank you for a clean example how to actually use it.  
> **username_1**: Why not factor out the resource management as a separate function?  
> **username_20**: @username_1 Because they're local variables, and it writing separate structs and functions to deal with resource management for every combination of such variables does not scale well.  
> **username_1**: Nor does repeating code every time a given combination recurs. Especially if things change and you have to revisit every instance. Abstraction is your friend.  
> **username_20**: @username_1 If you find yourself using the same combination of resource allocations frequently, yes, clearly you should abstract some of that away.  That won't be true all the time.  
> **username_20**: @username_1 Additionally, even if the resources could be freed by a single function, I would still advocate using `goto`.  It's still easier to maintain; if you need to change the signature or semantics of you resource deallocation function, you'd won't need to revisit every exit point.  Also, doing `goto exit;` at each exit point is simpler than `FreeMyResources(...); return NULL;` if you need to return something.  
> **username_10**: That's one of the two acceptable uses of `goto` (the other being breaking from two loops at once or jumping out of a loop when you found what you're looking for). I'm still not sure if I would bring that up in an introductory programming course, before they've learned the more important control structures (just imagine the result when a student forgot about `while`, but remembered `goto`.)  
> **username_10**: In any case, you could make more than one distinct `exit` label there so that each one just does the necessary cleanup, implicitly falling to the next one in order, e.g. `exit3: fclose(); exit2: free(); exit1: return`.  
> **username_12**: I disagree. `goto` should not be used in C /C++ and similar language. It should be used in assembly where no other looping or branching technique does not exist. One simple `goto` could ruin the readability of the whole program. Your code is just for a simple program. What if when they would write hundreds of lines of code? This is my personal opinion. Thanks.  
> **username_20**: @EnamulHassan 1. There are *many* things (particularly in C) that can ruin code readability. Heaven forbid that people are taught how to use `goto` *responsibly* to keep code readable! 2. I agree that structured alternatives should be used instead of `goto` *when available* (e.g. `for`, `while`). That's Dijkstra's paper. However, the fact remains that C *lacks* error handling or resource management constructs, making `goto` the only sane solution for a large codebase. (Note that C is *not* C++. I would not recommend `goto` for C++ since C++ does have a resource management construct: RAII.)  
> **username_20**: 3. `goto` for resource management is *especially* important for large, complex programs.  For a *simple* program, releasing resources manually at each exit point is less of a problem.  For a *large* program, resource management is an even bigger problem, and using `goto` is far less error-prone.  

---

### Answer by username_9 on 2017-12-23. Score: 7

**Note:**

*I was under the impression that this question was by a faculty asking for advice on best practices for teaching a course on C. Instead it's a question by a proactive student that is disappointed with the department's approach and wants to help educate his peers on best practices.*

*I believe that my answer is wrongly targeted but I'm leaving it here as I feel that it might hold some value to others.*

--

When I went to school for programming our department had a very interesting approach which, in my opinion, helped to mitigate a lot of the confusion surrounding a first introduction.

**Provide a very rigid style guide**

* We had department-wide coding guidelines which were adhered to for all courses (much like when working for a company) so not only was code between students fairly consistent but also consistent between assignments for the *same* student. This is often overlooked and is in my opinion one of the most important things when teaching what literally amounts to be a *foreign language*.

**Provide some form of static analysis for both style and logic**

* Every assignment was passed through a "style checker" written by the department that verified a combination of style conformity and basic linting for static error checking. This further reinforced adhering to a single style of coding and the linting was helpful and helped us to not be afraid of output warnings and errors.

**Provide unit tests so that students can focus on the implementation rather than the formatting**

* Every assignment to be submitted was run through unit tests that verified input/output. This was tremendously helpful as it allowed us to spend less time on the math and more on the implementation and practical application of the code we were writing to solve a problem.

**Focus on a standard and cross-platform tool-chain and leverage it to teach principals that are applicable to other environments; teach them the language not an IDE**

* Compilers and the aforementioned tools were available only from the department "Linux lab" computers. We were tasked with learning the command line and text editor of our choice (`nano`/`emacs`/`vi`) and compilation was done directly at the command line with `g++`. We were also taught how to `ssh` into the Linux lab so that we could work off-campus. This provided a simple environment without all of the extraneous features of IDEs and a basic introduction to both a Unix-like environment and command line compiling.

**Put blinders on your students and choose to use a subset of the language to force students to think about solving problems with the language itself rather than through a library**

* All classes for teaching programming principals stripped everything to the bare minimum so that we were learning not only the core of the language (C++ in this case) but eschewed even the STL; for example, we programmed all of our data structures by hand. We learned the tools and the language which allowed us to later understand what a given library was doing under the hood rather than it being a black box.

**Tell them where to go for resources**

* It might seem like second nature to us but new students don't know where to go for resources and may not think beyond their textbook. Websites that provide an overview of the language, its keywords and headers, such as [`http://en.cppreference.com/w/c/language`](http://en.cppreference.com/w/c/language) that are easily browse-able on an internet device are excellent. Man pages are also useful but remember that this is a foreign concept so remember to demonstrate how to use it frequently during class. A small library of books as references can also provide additional insight on how to tackle a problem outside of a course textbook.

For those who are new to programming, this rigid conformity is essential to block out so much of the background noise and flip-flopping on coding style that is so prevalent for new students.

There was no question for us about where top put braces, semi-colons, white-space, and comments. There was no question about basic linting. There was no question about whether a program worked or not since it was run through unit tests.

I cannot stress enough how effective this approach was for me as a student. It gave us blinders that shielded us from the unimportant details and allowed us to focus on the most important things in each lesson and made learning to program a very satisfying and extremely rewarding experience.

> **Comments:**
> **username_4**: This answer is excellent, and tells me that you probably have quite a bit to contribute to this site (and I hope that you do!)  Did the highly regularized style specifications make it more difficult to detect cheating?  

---

### Answer by username_17 on 2017-12-21. Score: 6

Lint
I would not program in C without a lint tool e.g. gcc -Wall or pclint/flex-lint, unfortunately the latter two are proprietary.
However you need to show that error/warning messages are your friend. There are not an accident. Someone spent time writing them, to help you. Read them, and fix the underlying problem. Often I have seen people finding ways to get the error/warning to go away, but changing the code in a convoluted way, that makes it worse, but has no error.
Brackets {} are not an option.
I don't care what the standard says, always use brackets.
Comments
Well written code with good names, is better than code with bad names and comments. Use procedure/function names, and variable names to comment your code.
Bad
i++; /*Increment i*/
i++; /*Increment index*/

Better
index++;

Local consistency
Style must be locally consistent, and preferably globally consistent. Global consistency may suffer if there are more than one person on the team. But local consistency must never suffer.
Nouns, verbs, adjectives
Variable name should be nouns or for booleans adjectives.
Procedures should be verbs. Functions should be as for variables.
Full command/query separation is not easy in C as you would have to program Object Oriented.

> **Comments:**
> **username_1**: C was created at Bell Labs. If you worked there it was a "firing offense" if you didn't brace all. I.E. Brackets are NOT an option. Make your fingers do it so you don't need to even think about it. If you have a good IDE, the close bracket will be correctly placed if you open a brace and hit return.  
> **username_3**: CQRS is probably out of scope for an introductory course anyway.  
> **username_17**: I just looked-up CQRS. It does not seem to be the same thing as command query separation (CQS).  
> **username_18**: I would also add a note about "Global Variables" and "Code Reusability" to your list.  
> **username_0**: @username_18 Global variables are forbidden in the lecture and are an instant fail. Code Reusability is actually a good idea to have that explicit and not just implicit!  
> **username_5**: My $0.03: probably `i` is well-known enought not to adding much information over index. Similarly no points for guessing what `v` and `a` are in physics simulator. `pos[i] += v[i] * dt; v[i] += a[i] * dt;` is probably clearer than `positionOfObjectsArray[index] += velocityOfObjectArray[index] * timeDifference; velocityOfObjectArray[index] += accelerationOfObjectArray[index] * timeDifference;`.  
> **username_16**: A couple major points of disagreement. First, comments, **both are bad**. Commenting `i++` to explain what the statement does is not useful, it's clutter and trains new programmers not to actually be intentional about good comments. A good comment might be something like `/* Skip an additional element because the code below assumes... */` or similar. Comments are to explain purpose, not to translate C to English.  
> **username_16**: Second, while being inflexible about braces or variable naming may be good for the purpose of a course, you need to prepare students to be flexible about coding style and policies, because they **will differ** in real-world work. Being led to believe they've been taught the "one true way" about anything that's a matter of style or tradeoffs sets them up to doubt the competence of programmers/teams that do things differently for well-justified reasons or just because it's not a big deal.  
> **username_19**: @MaciejPiechotka - While you make an argument that i, v, and a are equally readable in context to the longhand variable names. I was only "pretty sure" what v and a meant, as I don't normally work with physics. The second version is not only more readable, but unmistakable. In your first example, I could assume that v stood for vector, and a for acid, or something. I cannot make that mistake in your second example. There is a lot of value in being 100% sure you eliminated a mistake over being 99% sure. Especially when it doesn't cost you anything to add the 1%.  
> **username_5**: @username_19 No, I'm claim they are _more_ readable as they are a) domain specific word no different than lingo of any other buissness client and b) if you have sufficiently long equations you may need to spill over to next lines making it less readable by sheer verbosity. Those are toy examples but consider `(legendre(x, k).plus(legendre(x, k - 1).times(Float64.valueOf(eta_k)).plus(legendre(x, k + 1)).times(Float64.valueOf(1 + eta_k)))).times(Float64.valueOf(0.5))`. If you know domain it's more or less clear - setting aside problem of lack of operator overloading in Java (...)  
> **username_5**: (cont.) `(legendre(x, k) + legendre(x, k - 1) * eta_k + legendre(x, k + 1) * (1 + eta_k)) * 0.5;` would be clearer. However changing `legendre` to `solutionToLegndreEquation` or `k` to `numberOfCalculationPoits` etc. would not help without looking at the original paper... which used the same notation so changing notation would make things even more confusing. In similar way changing `for (size_t i = 0; i < FOO_SIZE: i++) foo[i] = i;` to `for (size_t indexInFoo = 0; indexInFoo < FOO_SIZE; indexInFoo++) foo[indexInFoo] = indexInFoo;` doesn't help much as virtually everyone uses `i` for index.  
> **username_17**: Yes use abbreviation, if they are used in the domain, e.g. physics. OR tv for television, because these are well known, but don't make up new ones.  

---

### Answer by username_1 on 2017-12-21. Score: 6

Your list is a bit narrow in one sense. I assume it is well matched to your specific course, but probably doesn't represent "best practice" in general. For example, *valgrind* is limited to linux, which suits you better than me. But the idea of including memory testing, for example, is a good idea no matter the specific tool. Similarly for *git*. There are alternatives, but code management and version control is the big idea.

But one item I find missing here, but also essential is some sort of tool for unit testing. There are [many](https://en.wikipedia.org/wiki/List_of_unit_testing_frameworks#C) available and building good clean code requires pre testing everything to arrive at a good result painlessly.

Another suggestion I'd make, though this may be your intent already, is that you show many of your ideas in the context of a large and complicated program. You state that dealing with such projects/programs is an issue in the course at the beginning of your post and that may actually be the biggest issue. So don't present your tool set using only "toy" programs.

If the projects are done in teams you may also want to include something specific about how to be successful in a team environment. Many of your students may not have experienced that. There is a book, in fact, named [Teamwork is an Individual Skill](https://rads.stackoverflow.com/amzn/click/1576751554) that has valuable hints for any professional.

> **Comments:**
> **username_0**: We thought about using the final assignment from a previous year (around 800 LoC). Do you think that is big enough, or should we use a bigger project? If so, do you have one in mind? Since most open source projects that i have had a look on the code, have terrible code documentation.  
> **username_1**: If that is the scale of the assignment to come then it is probably a good choice. Others may need something bigger in a similar context. It is probably a mistake to overwhelm students unnecessarily. And you may need to doctor whatever code you find before use. You could also use the sessions to improve the code, of course. That might be especially valuable in this context. You don't mention whether the students start the project with a given codebase or start from scratch. That can affect how you proceed, but the toolset would likely be the same.  
> **username_0**: They start without any codebase, just the standard libraries.  

---

### Answer by username_21 on 2017-12-21. Score: 3

Two important concepts that seem absent from the list, and that I often find are barely developed in even fairly advanced students are testing and debugging. I would suggest some brief introduction along the following lines:

Unit test and integration test; test scaffolding; test-first strategy; exhaustive test vs. (targeted) random test vs. testing manually determined corner cases.

Use of assertions; logging, possibly at various debug levels; insertion of `printf()` calls for adhoc debugging; use of a debugger: break points, single-stepping, observing variables, watchpoints; code simplification to create an [MCVE](https://stackoverflow.com/help/mcve).

> **Comments:**
> **username_1**: Welcome to CSEducators. I agree that understanding assertions is an important idea.  

---

### Answer by username_22 on 2018-01-28. Score: 2

If you want to teach the students some valuable real life skills, helping them in writing programs without bugs, teach them about sequence points and integer promotion.
If a C programmer does not understand those concepts, he or she is bound to make some serious mistakes sooner or later.
#include 
#include 

static int n = 100;

static int f1(void) {
    n++;
    return n;
}

static int f2(void) {
    n++;
    return n;
}

static int f3(int a, int b, int c, int d)
{
    printf("Undefined behaviour allows the compiler to do anything!\n");
    printf("n = %d, a = %d, b = %d, c = %d, d = %d\n", n, a, b, c, d);
    return n + a + b + c + d;
}

int main(int argc, char *argv[])
{
    unsigned int a = 10;
    signed int b = -10;

    if (a < b) {
        printf("This is executed despite that (%u < %d) is not true\n", a, b);
    }

    n = f3(n, f1(), f2(), n++);

    return EXIT_SUCCESS;
}

Compiled with gcc:
This is executed despite that (10 < -10) is not true
Undefined behaviour allows the compiler to do anything!
n = 103, a = 103, b = 103, c = 102, d = 100

Compiled with clang:
This is executed despite that (10 < -10) is not true
Undefined behaviour allows the compiler to do anything!
n = 103, a = 100, b = 101, c = 102, d = 102

Even if the students do not fully grasp those two concepts, being aware of them is important.


---

### Answer by username_23 on 2018-01-29. Score: 2

That's really a nice question and I appreciate that you consider the noise around programing like version control (git) and coding style.

View things important to me are:

***Flowcharts:*** or the art of coding on a piece of paper. When I was a student, our teacher insisted on designing the logic on paper before typing it into the machine. Maybe this sounds old school but for larger projects I still take the pencil first. This helps to understand and focus on logic.

***Algorithms:*** or defining the problem and finding a solution to it. Mostly C programs are likely command line programs and no full blown apps. So the best use and challenge for C is to learn concepts of ***Algorithms*** and ***Computing***
It's always fun to me to draw concepts on a whiteboard, this helps to get some imagination and creativity for the topic.

***Debugging:*** or how to get to know what your machine is doing right now. Programming is like manipulating bits and bytes in the Memory (tag: Von Neumann architecture). To visualize what's going helps to understand what the machine is doing and much more help to find and understand your mistakes (semantic failures).
With the debugger you can walk through your code and see variable and memory change. Especially when it comes to different types, arrays, pointers, and memory location (stack, heap, registers, etc.) it is good to know how to look that up.

If you like to teach "how to google their problem" it would be an advice to teach how to ***ask the right question***

> **Comments:**
> **username_0**: >"ask the right question" thats what i meant =)  

---

### Answer by username_12 on 2020-07-03. Score: 0

Besides all of these good answers, I want to add one thing. Make them familiar with the world of **Competitive Programming** and **Problem Solving** where they would learn by playing. They would learn how to approach and solve a problem. Some of the most common *competitive programming* and *problem solving* platforms are:

* [URI OJ](https://www.urionlinejudge.com.br/judge/en/login) - There are a lot of problems here for the beginner from adding two numbers to much more.
* [UVa OJ](https://onlinejudge.org/) - Here, they would learn how computer program works for checking two files! Statistics of this site is better seen [here](https://uhunt.onlinejudge.org/) in uHunt.
* [Codeforces](http://codeforces.com/) - This is a good site for competitive programming, as well as problem solving. New problems come in almost every week. The most important part here is, one could see other's code after a contest. Editorials for problems are available. This is a Russian platform.
* [At Coder](https://atcoder.jp/contests/) - Similar platform like Codeforces, but this is a Japanese platform. Don't worry, in both of the platforms, English version is available.
* [CodeChef](https://www.codechef.com/) - This is another similar platform. This is an Indian site.
* [Hacker Rank](https://www.hackerrank.com/) - Besides basic programming, they also have tracks for Data Structures, Algorithms, Databases, AI etc. Though I do not recommend those tracks for a beginner.
* [Project Euler](https://projecteuler.net/archives) - There are so many interesting problems here. Here, only answer of one scenario should be submitted instead of submitting code.
* [Virtual Judge](https://vjudge.net/) - This is a Chinese platform. Contests could be arranged here taking problems from different online Judges.
* [Toph](https://toph.co/) - A Bangladeshi platform for both competitive programming and problem solving.
* [SourceCode (Temporary Name)](https://alpha.sustcseoj.com/) - Our students made this platform, though it is in a very early stage. The name is not yet finalized. We take programming exams through it. There are several problems for problem solving.

There are a lot of interesting things on the internet. We should encourage and entertain our new students with these tools, rather than compelling him to know complex things.

(My answer seemed not relevant to the question, but it is relevant as you could submit answers in C/C++.)


---

### Answer by username_13 on 2017-12-22. Score: -1

It's important to teach that the name C refers to two diverging languages--a low-level language which is useful for systems programming because many operations which different platforms may handle differently are handled in a documented fashion characteristic of the actual execution environment, and a more recent high-level-only language which uses the same syntax as the low-level language, but which allows compilers to behave in arbitrary fashion if code attempts certain operations whose behaviors would be defined in the former language.
Given a piece of code like:
unsigned mul_mod_65536(unsigned short x, unsigned short y)
{
  return (x*y) & 0xFFFF;
}

compilers for the former language would multiply the values of x and y
using whatever semantics the platform uses for integer multiplication,
take the bottom 16 bits of that result, and return them.  On platforms where integer overflow would yield a result whose bottom 16 bits is correct, the above would yield the correct mod-65536 sum for all combinations of x and y.  The published rationale for C89 indicates that the authors of the Standard would have expected such behavior from most current (and IMHO presumably future) compilers.
On compiler processing the latter language, however, the above code may sometimes malfunction in totally nonsensical ways if the value of x*y would exceed 2147483647.  If, for example, code were to call mul_mod_65536(i,65535) some "modern" compilers would use the multiplication to infer that i cannot be greater than 32768, and thus "optimize out" code elsewhere in the program that would only be relevant if it were.  Thus, unlike some languages which specify that an overflow will wrap cleanly (like Java), or specify that it will trap (like C#, within checked contexts), "modern C" requires that programmers absolutely positively prevent overflows from occurring under any circumstances even in cases where one of the above behaviors would suffice (or even in circumstances where either would be equally useful).
Programmers need to be aware that there exists a lot of code which is written for the former kind of C, and also that some compilers like gcc and clang will be incompatible with such code unless explicitly forbidden from applying aggressive "optimizations".


---

