26

I am tutoring a few students who are having significant trouble learning the basics of their first programming language: C++. I have known many excellent and bright students who have failed or dropped their first CS course. Everyone I am tutoring gives a similar account of his or her experience in class: the instructor moves along too quickly, nothing in the lectures make any sense, et al. Prior to this CS class, most of these struggling students had not expressed any interest in computers as anything more than word processors, web browsers, or some other form of entertainment. The computer is a blackbox that works, so why mess with it?

My best guess is that they are having trouble connecting the abstractions of computer science with familiar concepts. That is to say, these student might know how to learn math, biology, or physics, but those techniques are not working when it come to programming.

Does anyone have any suggestions or advice? The students I am helping do not deserve to fail this class. It is clear that the instructor is not taking into account the learning style of these students. That is to say, the instructor is failing not his students.

2
  • 2
    Commenters: if you have an answer, leave it as an answer: do not leave it as a comment. If your answer has already been added, vote it up. If you want to discuss the topic of this question with others, use chat.
    – user8
    Sep 18, 2011 at 11:11
  • 1
    Don't? From my experience there are enough people who program and shouldnt...
    – user2528
    Sep 23, 2011 at 23:56

13 Answers 13

42

There are a few things that practically every beginner struggles with. Students need to know how to read code before they can learn how to write code.

  • The sequential nature of imperative languages. People have trouble understanding that functions are executed in sequence, one item at a time, like a recipe. One way to overcome this is to show some code working through a debugger.
  • The assignment operator (=) in C-style languages is extremely misleading. You need to explain very carefully that a = 5 means "assign 5 to variable a, not "a is equal to 5".
  • For beginners, it's safe to describe functions as structured blocks of code that other functions can jump to. Also, beginners have trouble understanding that in C++, function arguments are identified by order, not by name.
  • Most imperative programming languages have some declarative components and some procedural components, and C++ is no exception. Make sure the student understands that some parts of the code describe the structure of the program, and other parts (functions) describe what the program should do.
  • Stepping through a program with the debugger is an extremely important and often-neglected teaching tool.
  • Expressions have types. 3+3 is an integer, 3.5 + 3 is a double, "3" + "3" (in C#) is a string, x == 5 * 3 + 25 is a boolean (or integer in C++). Spend a lot of time to make sure the student is completely comfortable with this notion.
  • Variable scope is something that beginners get confused all the time. Explain to the student how scope works, and make sure they know that an x defined in one scope is different from an x defined in another scope.
  • Every variable is referenced at least three times in its lifetime: declaration, assignment (often done on the same line as declaration), consumption. If any of these is missing, then there's a conceptual mistake somewhere. For the same reason, if you're analyzing a working program, you can always look for these three things in the code to figure out the purpose of a variable.
  • for loops shouldn't be taught until adequate examples of iteration using while loops is given. The shorthand syntax is confusing, and it leaves students wondering why they can't just use while loops. Having a cheat sheet that describes a for loop in terms of a while loop can be helpful.
  • Arrays and pointers are fairly easy to teach, but a nightmare to learn. In other words, until it clicks, practice is important.
  • The idea that code is text and that a compiled program is in fact a file is elusive to some beginners. Be sure to show them the .cpp, .h and binary files in the shell.

The OOP components of C++ are a whole different beast entirely, and I kind of hope the instructor doesn't get there -- because OOP is best taught using languages that were designed from the ground up to be OOP. In my experience, teaching OOP through C++ has never gone well.

5
  • 2
    "People have trouble understanding that functions are executed in sequence"? I think that's the very thing virtually no-one has problems with (except, perhaps, people who have already learned some functional language before starting procedural). But I agree about everything else you say. Sep 18, 2011 at 0:14
  • 3
    +1 for stepping with the debugger, so they get a sense of the difference between the program itself and the execution of it. Sep 18, 2011 at 0:26
  • 4
    @leftaroundabout You'd be surprised. Math is mostly declarative, so imperative languages can throw off anyone who's learned algebra. Sep 18, 2011 at 1:15
  • 2
    This answer seems to be a bit of just "rattling off concepts." The concepts are undoubtedly correct and are certainly important, but teaching this way is a little like trying to teach someone how to drive by rattling off rules of the road.
    – riwalk
    Sep 20, 2011 at 16:04
  • @Stargazer712 Everyone learns the rules of the road before they're allowed to try the road test. I could present fluffy broad-stroke ideas like "practice is key" or "be creative" or "think logically", but those things are presumably quite obvious to any instructor, as well as to most students. One could also teach abstract things like discrete math or language theory as a precursor to programming, but that only becomes important when the mechanics are so complex that problems can't be solved by intuition alone. Sooner or later people have to stop being zen and start teaching content. Sep 20, 2011 at 19:03
19

Have you taught programming before?

I taught programming to CS and non-CS majors for four years. The first semester, my experience was like yours, until I learned a few things.

What seemed vacuously simple to me was not at all simple to the beginners.

Regardless of language, you need to put a mental framework in place - things so obvious you don't even realize you know them, such as:

  • Computers only do one thing at a time. (Anybody who says they have parallelism and pipelining, go away. Come back when the students know something.) Computers can only do a small number of different things, and they can't begin to do one step until the previous one is finished. I'm only saying this, because computers seem to do so many things, and do them instantaneously, that to a beginner it looks like they do everything at once, and read your mind as well.

  • Variables are important. It is essential to understand that the name of a variable, and its contents at run time, are two entirely different things. Beginners struggle with this. If I say "Write a program to input your name and then say Hello to you", they need to figure out that they need a variable to hold their name, and they have to think up a name for the variable, and they are tempted to name it after themselves and wonder what "input" means.

  • There is a huge difference between the time at which you write/edit the program, and the time at which it executes. During their first exercises, they need to be reminded of this fairly often.

The language I used was BASIC, because it is very simple for beginners. It's not hard to move on to other languages after they've built up a set of basic programming abilities.

We would often write a program on the board, and then "play computer". That is, put an X next to the current statement, manually do it, then move the X to the next statement. Variables were rectangles on the board, where we would write the current contents. When an assignment happened, we would erase it and put in the new value.

One trick I developed was a simulated decimal computer, with 1000 memory locations, each capable of holding a 4-digit number. There was a small set of "opcodes" like load the accumulator, add, store, jump, etc. I would have them write little programs in this "machine language" and then single-step it to see it working. Then later, concepts like variables, jumping, and so on are much easier to explain.

Hope that helps.

4
  • I like that simulated computer idea. Do you have a formal language for it, or do you just discuss the ideas in pseudocode/plain English? Sep 18, 2011 at 3:09
  • @Rei: I wrote (in BASIC) a simulator called Simple. It was all keyboard interface. The user could enter values into "memory"; then they could single-step it and examine the accumulator and memory at each point, if they wanted. I think this was really important because it got them doing it, not just talking about it. Sep 18, 2011 at 15:43
  • Ahh okay. Thanks, I should try something like that. Sep 18, 2011 at 20:34
  • This should be the #1 answer in my opinion.
    – riwalk
    Sep 20, 2011 at 16:02
12

In my opinion C++ is an overkill as a first language.

If I were you, and had sufficient time at hand, I'd go about introducing concepts of programming and CS using Python (or similar).

When the concepts are clear, i.e., when they are comfortable with basic data structures, indirection, basic algorithms etc, I'd slowly introduce C++ and they will very quickly be able to relate to what they already would have learnt.

8
  • 2
    I agree, but profs usually don't have the right to choose what language to teach, much less TAs. Sep 17, 2011 at 21:06
  • 4
    I disagree on Python. I went through my first CS 101 class on C++ and then switched to a school that taught CS 101 in Python. The Python students were SO confused on even the basics when we all took the same CS 201 class... But all the C++ students excelled. Sep 18, 2011 at 4:04
  • @OghmaOsiris, Frankly, I don't know enough about Python, but may be what you witnessed could simply have been the manifestation of a self-selection bias. After all, C++ is hell of scary for some students (especially for the most inexperienced students in programming). Sep 18, 2011 at 5:11
  • @Oghma What was the 201 class? If it's anything low-level, it should probably be its own branch with C as a prerequisite. Sep 18, 2011 at 5:35
  • 1
    @OghmaOsiris: Hmmm I have to disagree, well not disagree, share a different experience in my univeristy switching to python as a first language has proven very helpful as far a I'm aware (the first was Java no C++). I don't think individual experiences count as poof that one is better that the other, that is a never-ending flame war. I might argue though that Python might be a great programming language to start with because it does not get on your way, it actually does that better that most programming languages, that gets many students....
    – Trufa
    Sep 18, 2011 at 7:11
4

Here's what I would advice:

  1. Give them all the details they need to figure it out
  2. Encourage them to try to understand the details
  3. Make sure they have the details stored in compact form whenever they need them

Basically I would advice you to create single a4 paper which has all necessary details required. Some kind of reference manual which has all the details. Some books can also help, for example "The C programming language" -book helped tremendously because it had all the necessary details available in compact form. The compression of information is necessary part in creating the a4 paper which contains all the details.

0
3

Programming is substantially different from the other common domains a student encounters. Many students before college have succeeded by merely paying attention in class and perhaps doing a few homework assignments with easy problems and the answers in the back of the book. It's more about memorizing processes, then creating them. It's also the first time for a lot of students to get the wrong answer repeatedly (syntax errors, logic errors, seg faults, etc). This can drain student motivation when working on programs.

To truly know what's going on with programming, they'll need to PRACTICE a LOT. An often overlooked technique is to have them write out psuedo code in whatever their native language is first. Ask them to keep expanding that until they have a fairly detailed solution to the problem. Then its a matter of translating that into real code.

3

When I was in college, I used to be a tutor for the intro to programming course among other courses. The problem you are describing is not uncommon. Depending on what your specific role is, you may have different approaches you want to take.

First, if this is a widespread problem affecting significant portions of the students in the class, if you have access to do so, I would approach the professor teaching the course with specific feedback about what concepts students are failing to grasp, so that he or she may either incorporate additional review of that material as it comes up again in the term, or improve the curriculum for future terms.

If you teach a discussion section for the course in addition to your lab time, that would be a wonderful time to expound on the things that were confusing in lecture and help make them more concrete and make sure fundamentals were all understood.

If the only time you work with these students is during your time in the tutoring lab, you can still use this time to teach the students either one on one, or a few at a time, the conceptual building blocks they need in order to understand and complete their homework.

They may feel so lost in class they don't even know where to stop and ask questions. If that is the case, go back to the basics with them. Where were they in the course when they last understood what was going on? If they are unsure, or "never" understood, you may have to go all the way back to the beginning to explaining hello world, teaching them things like what a variable is, how the computer takes their list of "instructions" and tries to do them in order, but the computer's not as "smart" as us so you have to be very literal and say things exactly right for the computer to understand, etc.

That's actually a point of struggle and frustration I've seen quite frequently in the non-majors programming courses. Students write some code. It seems "about" right, but then they go to compile it and it gives an error, a very cryptic error. And they have no idea what's wrong with it. And stare at their code for hours. Then finally figure out it was something that seems trivial, like a missing semi-colon, or a brace in the wrong place. Then they go compile it again, and there's still an error, it's something else. They spelled a variable name differently the second time they used it. And so on. So they ask a friend or tutor or someone for help, and they can answer off the top of their head "oh just add this there and then it will work." So their experience is that programming is a bit "mysterious" and extremely frustrating and way more trial and error than it should be.

That is an area as a tutor, where you have a lot of room to help. Depending on their frustration level, I might have different approaches to helping them figure out why their code isn't working. If they're sort of getting it, I might give them hints and try to help them figure out on their own. But if they're just at the end of their rope about ready to give up frustrated, I'll often give them a couple freebie answers, and then try to at least ask them questions like "do you understand why this change fixed your program?"

For some students, especially non-majors, they may not have the methodical attention to detail necessary to be a good programmer or enjoy programming. You can hand-hold them through strategies to help them pay attention to the details, and be methodical enough to solve the problems even if it is a challenge for them.

But anal-retentive about the students indenting their code "properly"--so often, beginning programmers create problems with nesting and scope because they have non-matching braces or the like because they don't pay attention to what's nested under what. Give them a checklist of "things to check when your program won't compile", like indent all the code properly and make sure the braces match, make sure all the lines end in semicolons, especially around the line number where the first error shows up, etc.

Teach them to compile early and compile often. Write the minimum skeleton code (say, hello world), compile/test. Add a few lines, compile again. Its much easier to find errors if you're only looking at a small bucket of changes not a big bucket.

Help them learn how to break down a problem into smaller solvable problems. This is the same thing we do as professional programmers solving much harder problems we don't know how to solve. You keep breaking it down into pieces until you get to something that you either know how to solve or can do some research to learn how to solve. "What steps would you need to take to get to a working solution?" Well, first you'd need some skeleton code (hello world). Do you know how to do that? Yes, great, so when we're done talking you can start by doing that! Then it needs to read a file as input. Did you remember reading about that in chapter 4? Not really? Why don't you go have a look at that after you get hello world running, and see how far close you can get to getting that working and then call me back and I'll help you some more when you get stuck on that. The first few times you may just need to make a numbered list for them of the steps necessary to solve the problem, so that they can learn from example how to decompose the problem.

If they are getting some but not all of the material in class, encourage them to ask questions in class, because nine times out of ten, they aren't the only student not understanding, and the professor probably did just gloss over something important.

If they are spending "hours" staring at one bug but not figuring it out, that's a waste of their time, they're not learning much from it. Often bugs are insight problems, and its a matter of coming up with the right insight to solve it, and they may not have a knack for those types of problems. Suggest other general approaches to take when they get stuck: ask another friend in the class for help (get to know some classmates if necessary to do so), start their homework way ahead of time so they have time to stop, and later come into the tutor lab and ask questions during the open hours, or go to the professor's office hours. If they're used to cramming, which works well for memorization subjects, they will hit a wall of frustration when they're faced with programming which is more about problem solving than memorization. Show them how to look up examples of syntax from their textbook, stackoverflow, etc. Encourage them to post a question on a private class question forum if there is one.

Teach them how to narrow down where the code stops working. Comment stuff out till you get back to something that runs, and then slowly add stuff back in until you get that segfault again.

A lot of these ideas could be turned into handouts if they come up a lot. Strategies is usually the part professors gloss over--they're spending their time on the syntax, the semantics of how to write loops, arrays, i/o, etc. But not enough time spent on "what do I do when I try to run my code and it just doesn't compile or crashes on me?"

When it comes to conceptual things, especially fundamentals, like "what is a variable", or "what is a loop?" not understanding that will prevent them from being able to keep up with the rest of the course. In a lecture-based course, the professor may not have time to answer every question or help that lightbulb go off for every single student. And that's part of why tutors are so important for learning programming. They may need individualized instruction with additional analogies to make a particular topic concrete.

Since you are teaching in C++, I would imagine classes come up as an abstract topic that some students struggle to "get". Often the abstraction of classes is taught with examples corresponding to some random real world object, like an "ATM machine", and analogies are made to the real world object. You might have variables to keep track of how much money is inside, you have methods, which are like rules that tell the atm machine how to respond to particular conditions, etc. Sometimes one analogy is the one that "sticks" for a particular person, and other students grasp a different one better.

Whenever possible, draw pictures for them. Like a sequence diagram of what happens over time to help them see the big picture of what the code they are writing does. User clicks this button. Then the program should respond by doing x, y, and z. Draw an array like a bunch of PO Boxes at the post office that can each hold only one number, and pointers like arrows pointing to the "address" on the front of the box. Etc.

2

Of all the wonderful choices for programming languages out there, this college uses C++ as its intro CS class for non-CS majors?? In the hands of talented instructor, it might be remotely conceivable-- but why make it so hard?

When I learned "Pascal" in my college intro-CS class, we spent the first 3 weeks working with "Karel the robot". This was a very simple sandbox Logo-like programming environment where all the basic concepts (including recursion) were explored thoroughly before doing it in Pascal. In "Karel the robot", you control a robot in 2D space using a small set of simple commands. This gives students a useful concrete grounding that they can draw upon for what happens next.

Perhaps there are now more modern instructional programming languages that fill the role of "Karel the Robot"? Probably too late for your students now, however.

5
2

In addition to what was said, I assume that as beginners they only need to scratch the surface, so tailor your curriculum accordingly to avoid complex stuff.

0-give them a simple problem (say evaluate an expression).

1-give them time to figure it out.

2-give them the answer.

3-go through the answer line by line

4-ask them to compare your answer with their attmpt

5-ask them to derive the lesson from this problem

6-add a further step to the SAME problem, say a condition requiring an IF statement

7-repeat the above task on several problems. By then they would have grasped the basics of the language and how to use the environment. The would be ready for what comes next.

Also,

-have a bonus simple problem for them to try at home every 2 classes or so

-engage with each student to see what is the point that is stopping him from going further

-provide easy reference material, forget complex topics and complex books

-get their feedback frequently and use it

-ask them to prepare for the next topic before they come to class

2

What helped me when I went through CS 101 was learning the logic before even looking at code. We went through truth tables and prepositional calculus just so we would start thinking "this is true or false" and not "this equals this or that".

That right there was when everything clicked for me. Once I figured out that programming is basically just manipulating true/false values at its core, then it all became relatively simple.

And this made it so it didn't matter what language I was using, logic is the same everywhere. Syntax might be confusing, but I can say things like "Ok, in Obj C I send messages to classes like this and in C++ messages were sent like this other way. But the algorithm hasn't changed at all." etc.

2

There's an ACM or IEEE article somewhere that goes into some of the details of why beginners (even CS graduates starting in the field) need to sit behind a senior programmer and watch them code a problem.

Professionals often pair for difficult problems. Students are too often told not to. Advantages of pairing (taking turns at keyboard): 1. The student gets told what he is doing wrong immediately. Instant feedback. 2. When the learner watches the teacher the learner picks up on things the teacher would have never thought to point out.

Rather than let a student develop bad practices, they are nipped in the bud. (I would flip #1 with #2 here and let the student watch the Instructor/TA FIRST)

Teaching CS with a static set of powerpoint slides doesn't lend well to the temporal process of writing a program. (Granted there are tricks you can do with growing functions line by line, but they're usually awkward.)

Learners need to know where to start writing, and where to stop and compile. Our brains are mostly wired to read left to right top to bottom, but a program is like a whole choose your own adventure book crammed into a single page!

Too often a beginner will copy a whole program and then compile. Even a professional might give a first crack at it that way, before realizing they should have left all of the functions empty, and compiled the program, then iteratively added into a working skeleton.

Also, related is the ridiculous idea that CS should be taught without a computer and just pencil and paper. I wonder how many employed programming professionals really think this is the best way, or if it's just what CS instructors do because they themselves don't like working with computers? Any attempt to remove a computer from the picture is a mean one. Doing so makes programming less fun and less interactive than it should be. We are long past the days of entering data into a punch card and patiently waiting. Today's professional developers are fans of instant gratification. Luckily most students are too.

Obviously the drawing of pretty designs with pencil and paper before and during the development process is a powerful tool for both professional and beginner programmers. This like the "hands on keyboard" time should be also be spent pairing! Maybe here it might make sense to let the student attempt the first round before watching the teacher, although even with this it's probably worth seeing the teacher's real thought process.

Lastly, The hot keys and editing tricks that the professional developer employs aren't "noise" to the student's learning. Most importantly, they engage and interest the student. Second, they raise awareness to common development needs. Furthermore the most basic of these practices are often easy to execute but not obvious initially. A young wood shop student can easily learn how to remove a nail with the claw of a hammer, but in most cases must first be told that's what the claw is for. Some extremely easy to do things are just not trivial to learn without being taught. Even professional developers forget about these "tricks" all the time, and benefit from refactoring tools like resharper to remove redundant or unreached code etc.

1
  • 1
    btw, If someone could point me to the title of that article I'd appreciate it!
    – David
    Sep 18, 2011 at 5:31
2

Computer programming is often one of the first courses where the cognitive skill of synthesis is required for a passing grade. That skill is very difficult to impart to someone else. You can explain all the components they have available to them and how they work. You can give a multitude of examples of how other people have used synthesis to combine those components into a more useful whole, but there's only so much you can do without something "clicking" in the student's mind.

In my experience it's the skill of synthesis that most often eludes people who don't "get" programming. They have a perfect understanding of the parts, like variables, functions, and loops, but they ask questions like, "I understand why it works, but how did you know you needed to put a loop there?" You just plain have to practice until you get it.

2

To misquote Aaron Hillegass, remind them that they're not stupid, it's just hard. Programming is difficult to train your mind to, it's a whole other way of thinking, and whilst they might be struggling with the basics they're probably quite aware they are and it'll be making them fairly despondent.

I say this as someone who failed his first year CS course as well, I'd programmed a lot before and got all the concepts (VB, yeah baby) but C++ just wouldn't click for me. I ended up going back to the very basics and working it from there, then it clicked, but if someone had said "You're not an idiot, this is just hard" it'd have made my life easier.

0

You said "these student might know how to learn math, biology, or physics, but those techniques are not working when it come to programming".

There is a reason for this, programming requires something those other discipline don't necessarily require: creativity and ... fantasy. The capability to "imagine things at work". I personally found such a requirement is more present (of course , with all the due exceptions) form people coming from technical school (electronics and electromechanics in particular: they have to "imagine electric flows and how they control each other", since they cannot see them!) than from "pure science" (where everything looks like turning around math).

For this last cases, the "visual cognition" must be helped. It is important not just to focus on notion and text (the type -> compile -> look the errors cannot work if you are not able to "read" the errors) but to provide a way to visualize things, either at design time (by simulating what goes on the machine: be prepared with a white-board and set of colored post-it) and at execution time.

For this last part to be successful, essential notion of operating systems and "how programs runs into a machine" (and what that machine in fact is) must be given. And a nd not intimidating IDE must be given. I normally a "customized Code-Blocks" with many things removed to "don't distract". The notion of project made of sources to generate objects to be linked with library must be given BEFORE starting to talk about a language.

The C++ traditional hello world requires an entry point and an output device. Student must be already familiar with it. The success of this kind of courses depends on the very first days. You need to stimulate a visualization of what happens inside a computer to let them understanding what programming is.
The rest is syntax (science) and abstraction (fantasy)

Not the answer you're looking for? Browse other questions tagged or ask your own question.