Computer Science Educators Asked by Git on August 21, 2021
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 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:
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.
"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:
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
to help some non-programmers to become programmers (will work 10% of the time in your setting)
Correct answer by kubanczyk on August 21, 2021
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:
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++.)
Answered by Enamul Hassan on August 21, 2021
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
Answered by chris.stckhmr on August 21, 2021
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 <stdlib.h>
#include <stdio.h>
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 = %dn", 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 truen", 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.
Answered by hlovdal on August 21, 2021
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
Provide some form of static analysis for both style and logic
Provide unit tests so that students can focus on the implementation rather than the formatting
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
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
Tell them where to go for resources
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.
Answered by Zhro on August 21, 2021
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".
Answered by supercat on August 21, 2021
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.
Answered by jamesdlin on August 21, 2021
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.)
Answered by Ray on August 21, 2021
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.
Answered by njuffa on August 21, 2021
if they are new to programming start with flip-flops. I usually refer to Lombardi's "This year, we are going to start from the beginning. This, gentleman, is a football". It makes it funnier when they are British.
You can delete this answer as I don't have comment permissions.
debian
eclipse-cdt
svn/git
cmake
jenkins
unit test
250,000 lines of code is more reasonable than 800. Also, if you need to add a comment to code it means that the code is unintelligible.
Edit:
As requested in the comment. I think starting with a brief introduction to electrical engineering and discreet mathematics is appropriate in an introductory programming course. The list above is not complete or accurate, but it's something that can be setup in a day and increases the productivity of other programming tasks that are part of your lesson.
Also, implementing strcpy is a good task for anyone from an arts background.
Answered by Abdul Ahad on August 21, 2021
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.
I don't care what the standard says, always use brackets.
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.
i++; /*Increment i*/
i++; /*Increment index*/
index++;
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.
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.
Answered by ctrl-alt-delor on August 21, 2021
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 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 that has valuable hints for any professional.
Answered by Buffy on August 21, 2021
Get help from others!
Recent Answers
Recent Questions
© 2024 TransWikia.com. All rights reserved. Sites we Love: PCI Database, UKBizDB, Menu Kuliner, Sharing RPP