It's also easier to go up the stack to object oriented languages, particularly Java. The second chapter, first edition, of David Flanagan's Java in a Nutshell is still, in my opinion, the best intro to Java after having some experience with C.
It's also easier to go up the stack to object oriented languages, particularly Java. The second chapter, first edition, of David Flanagan's Java in a Nutshell is still, in my opinion, the best intro to Java after having some experience with C.
I don't agree. What's the benefit in having to painstakingly write trivial string operations using string.h and manually allocated buffers? What's the benefit in learning the ins and outs of undefined behavior?
That's the cool part, algos don't necessarily require strings.
Realize he's proposing first years where you have to LARP that they don't even know what an if-then-else construct is, or what is a function, or what is a loop, or what is recursion, or what is the concept of a memory map, or what is the concept of data or memory locations having a type (like float, long int, etc), or what is the concept of a variable. In 2016 most of them probably know, but schools feel the need to pretend. Also non-majors wanting a code experience will need an intro.
This will make "real C programmers" very annoyed because OS code requires "real C skills" not a training wheels subset of C, but oh well. You can't really expect first year students to write OS code anyway.
One hidden advantage is it would take enormous effort for a noob to put a C program on the internet, so this protects them from themselves until they pick up things in later higher level classes along the lines of buffer overflow protection and GIGO concept and unit testing and so on. If you teach them what is a variable, using framework-of-the-week, they're just going to get themselves or an employer powned thinking they know what they're doing after one class.
If you know what you'd have to do in C to implement a certain feature, you can guess what a high-level language is probably doing under the hood when you use its canned features.
To force people to learn that making assumptions based on undefined behaviour is dangerous and that computers are not mind-readers.
And you force people to write buffer manipulation code so they realize how good people using other languages have it.
I teach C, and every year I have a number of students nearly in tears, because somewhere in the huge program they accidentally malloced sizeof(T*) instead of sizeof(T), but of course that causes a crash 10 minutes later in a totally different piece of the code base.
My hope (it's not quite there yet, but getting closer) is that things like clang's sanitize modes will reach a point where any undefined behaviour immediately causes an abort. Then students can still figure out what they did wrong, but have a chance of finding the source of their bug.
In the beginning, the fear of getting some random Segmentation fault out of nowhere actually taught me more than any textbook, school or best practices blog could ever do. It also forced me to learn how to use debuggers :)
Also, many students previously did a course on Java, and clearly never really understood the basics, it's much easier in Java to play "keep tweaking and fixing the exceptions until it works, then don't touch it", particularly for introductory-level projects.
Really I wish I had access to it when I learned C.
It's hard to teach students not to over-rely on it, and trust everything it ever states. It seems best to first make them do some horrible debugging by themselves, and then move them onto valgrind late.
However if you deal with "student" problems I do not think this is the case. E.g. I taught a similar course to students and they appreciated that instead of
$ gcc -Wall -std=c99 foo.c
$ ./a.out
Segmentation Fault
they got something like $ gcc -Wall -std=c99 -g foo.c
$ ./a.out
...
==22907== Command: ./a.out
==22907==
==22907== Use of uninitialised value of size 8
==22907== at 0x4004F5: bar (foo.c:42)
==22907==
==22907== Invalid write of size 1
==22907== at 0x4004F5: bar (foo.c:42)
==22907== Address 0x0 is not stack'd, malloc'd or (recently) free'd
...
when e.g. writing to unallocated memory. I know for sure that there were often programs that were believed to be correct by students (and worse, often really worked, but not realiable), but had actually memory errors that were mostly reported by valgrind.I am not proposing to confront them with valgrind's details (I do not even know them), but explain that there is this tool that is a package in every popular Linux distro and ready to use to find these evil memory bugs (and they can be hard to hunt down if you are new to the language).
In particular I am interested in a false positive reported by Valgrind for a student exercise.
#define ALLOC(n, type) (type)malloc(n sizeof(type))
which makes it harder to have those types of bugs, though not impossible.
You can do that in a lot less time with, say, Array.sort in JavaScript. Explaining that signed overflow is undefined, and why it's undefined, is a whole lot of digression for little gain.
> And you force people to write buffer manipulation code so they realize how good people using other languages have it.
Seems like a lot of time to spend to make a point that would have been a lot more relevant in 1990 than in 2016.
Only then should they learn C and its horrors.
OO concepts were introduced after that, and the boilerplate code was explained. I'd done Basic, VB5, and what I'd call "C with iostreams" before college, and it felt like a fairly gentle exposure to classes and objects. Recursion took me longer to get a handle on, actually.
I'm so glad it was in C , it allowed me to understand how the computer works better.