Journal buffer-overflowed's Journal: For SamtheButcher: The basics of Procedural Languages (C) 41
UPDATE: I've implemented some of Cyberdine's helpful suggestions. I've also clarified a few bits of jargon.
Since b-over is BFAA bored, BFAA broke, and BFAA single so he's sitting over at his BFAA parents house munchin wings and watchin TV, and also as an apology to Sam for helping to crowd his inbox... I figure I'll post a quick procedural language tutorial for him.
Note since you've not posted ANYTHING requesting specific knowledge I'm going over this in a fairly low-brow manner. Feel free to ask in depth-questions in replies (anyone really, or correct my idiot ass if I screw something up).
Since tradition demands it, the Hello World program:
#include <stdio.h>
int main(void) {
printf ("Hello World!\r\n");
return 0;
}
This is of course the traditional opening program in just about *ANY* C book (or java, or anything) I've ever read. It's fairly self-explanatory.
Now, as a preface since I've fufilled my requirements to the programming gods by posting hello world, I suck at teaching. =)
We will now dissect Hello World for shits and giggles.
#include <stdio.h>
Top level goes preprocessor directives, include statements (which draw in header file interfaces to libraries or serve as libraries of a sort themselves, or serve as glue to bring multiple file projects together... etc.), defines, sometimes logic (#ifdefs for example) or macro definitions (don't worry bout this for now). The only one here is to the standard input/output header (stdio.h) which provides an interface under linux into glibc.
UPDATE: Preprocessor directives include anything proceeded by a '#' character. They are processed by the compiler before anything else. Hence if you do something like this; #ifdef _UNIX_ statements #endif it will only include that code if you have #define _UNIX_ 1 somewhere before it. This includes all #define statements, #includes, and the like. I had refrained from explaining this because it might be confusing.
int main() {
The main function, the entry point into the program. Properly written as follows:
int main (int argc, char *argv[]) {
Note I mix those two up occassionally (almost never write programs that take command line inputs). Argc (argument Count) is the number of arguments passed via STDIN(You know Unix at least a little, right Sam?), argv(argument Vector) are the actual arguments.
What's the * mean? * means pointer, I'll explain those later.
Next up we have the printf function call. This outputs stuff to STDOUT.
Then the return value. Main returns 0 (or normal exit). We could also use an:
exit(0)
here, but it wouldn't be officially correct.
Now, let's go into what happens when we run this through gcc.
gcc -o helloworld hello_world.c (This is a syntax screwup, check comments for the correct way for Makefiles [gratz Cyberdyne for the correction])
The compiler compiles it (this actually sums up a bunch of steps) and then it is linked dynamically to glibc. When you run the ELF binary helloworld it simply outputs:
Hello World!
If you wanted to link it statically (for instance, so it would run on linux computers which for some reason lack glibc). You could compile it in that manner. Also, -Wall helps detect syntax errors and typos (Once again, gratz Cyberdyne for pointing this out).
C is a procedural language, by procedural I mean it breaks things apart into procedures (or functions as they are more often called). For instance in the above example, main is a function. You could also write the same program as follows:
#include <stdio.h>
void say_hello (void) {
printf ("Hello World!\r\n");
}
int main(void) {
say_hello();
return 0;
}
Functionally it does the same thing, and in something this simple, there's no point in seperating printing out hello world from the main function. Note the return type of say_hello is void. It doesn't return anything (not even a non-typed pointer), hence the lack of a return statement. However, say you wanted to generate some random numbers between x and y. You'd probably want to do this quite often. Here's an example of that:
#include <time.h>
#include <stdio.h>
#include <random.h> //May not exist, no access to man pages right now.
void seed_random (void) {
time_t timeval; //A variable to store the time in secs since the Unix Epoch
time (&now); //Get the current time, pass it by reference
srandom (now); //Seed the random number generator with the current time
}
int roll_dice (int sides) {
int roll = random() % sides; /* Modulus division of a very large random number. Modulus gets the remainder. For instance 7 % 3 = 1. */
roll ++; //Since the result will be between 0 and our number -1
return roll; //Return the value
}
Seed random is a function to reseed the random number generator. To do so we pass our time_t value to the time function by reference (the & symbol) since it takes a pointer to a time value. roll_dice takes an interger argument for the number of sides to a dice, and then uses the random function %(modulus division, or calculating the remainder. IE: 7 % 3 = 1) the number of sides to generate a number. The result is then incremented by one to give a value range of 1 and sides. Note: In practice, we'd want to use a different time grabbing function, for instance gettimeofday() to get the time in u_secs.
It's now time to go into the best thing about C. Pointers. A pointer is simple a "pointer" or a reference to a section of memory. For instance say I have this value:
char arg = 'a';
And I then do this:
char *parg = &arg;
parg points to arg, if I use parg I'm actually using the value of arg(since parg points to arg), so if arg changes, parg also changes and vice versa(but I must reference the location it points to rather then the pointer). You can also have pointers to pointers and all other sorts of fun. We use pointers to cut down on memory usage, this is also why we pass things by reference. For instance when the time_t was passed by reference a pointer to it was passed, when that value was changed, the time_t we passed was also changed.
Next I'll go into the basics of loops.
We have the for loop, such as what follows:
for (a = 0;a < 5;a ++) {
//Do Stuff
}
This loop sets a (presumably int value) to 0, increments a by one every iteration, and ends the moment a is no longer less then 5.
There's also the while loop.
a = 0;
while (a < 5) {
//Do Stuff
a++;
}
Which does the same thing. A while loop escapes the moment the condition is no longer true on the next iteration.
Then we have the do while loop:
do {
//stuff
} (while <condition>);
Basically a fancier while that looks better. UPDATE: Technolust seems to think the differences here are important, so I'll go into them. A while will not execute the loop if it's condition is met before it starts. A do while will.
Next up are conditionals. There are two types
the if, else if and else statements:
if (something) {
//do something
} else if (something else) {
//do something
} else {
//do something
}
these are executed in order. If the first statement is met it stops, otherwise it goes to the next, if that statement isn't met, it executes the else.
Now the second type, switches.
A switch compares a series of cases to whatever is used in the switch.
For instance we have a value X, X = 1. We pass it to a switch as follows:
switch (x) {
case 1:
//do stuff
break;
default:
break;
}
It's basically a simplified if/else ladder. It compares X to each case, and if it meets the requirements of that case whatever is there is executed. The break statement stops comparisons (break also exits loops, but it's considered bad form), otherwise it'll go on down the rest of the conditions (yes you can do weird things with a switch). If it doesn't match anything, it executes default.
Dems the basics Sam. I'll go into enumerated data types, structures, macros and a little bit into OO and how it's different for ya sometime later. Oh, and lets not forget Scope and C99. YAY.
Since b-over is BFAA bored, BFAA broke, and BFAA single so he's sitting over at his BFAA parents house munchin wings and watchin TV, and also as an apology to Sam for helping to crowd his inbox... I figure I'll post a quick procedural language tutorial for him.
Note since you've not posted ANYTHING requesting specific knowledge I'm going over this in a fairly low-brow manner. Feel free to ask in depth-questions in replies (anyone really, or correct my idiot ass if I screw something up).
Since tradition demands it, the Hello World program:
#include <stdio.h>
int main(void) {
printf ("Hello World!\r\n");
return 0;
}
This is of course the traditional opening program in just about *ANY* C book (or java, or anything) I've ever read. It's fairly self-explanatory.
Now, as a preface since I've fufilled my requirements to the programming gods by posting hello world, I suck at teaching. =)
We will now dissect Hello World for shits and giggles.
#include <stdio.h>
Top level goes preprocessor directives, include statements (which draw in header file interfaces to libraries or serve as libraries of a sort themselves, or serve as glue to bring multiple file projects together... etc.), defines, sometimes logic (#ifdefs for example) or macro definitions (don't worry bout this for now). The only one here is to the standard input/output header (stdio.h) which provides an interface under linux into glibc.
UPDATE: Preprocessor directives include anything proceeded by a '#' character. They are processed by the compiler before anything else. Hence if you do something like this; #ifdef _UNIX_ statements #endif it will only include that code if you have #define _UNIX_ 1 somewhere before it. This includes all #define statements, #includes, and the like. I had refrained from explaining this because it might be confusing.
int main() {
The main function, the entry point into the program. Properly written as follows:
int main (int argc, char *argv[]) {
Note I mix those two up occassionally (almost never write programs that take command line inputs). Argc (argument Count) is the number of arguments passed via STDIN(You know Unix at least a little, right Sam?), argv(argument Vector) are the actual arguments.
What's the * mean? * means pointer, I'll explain those later.
Next up we have the printf function call. This outputs stuff to STDOUT.
Then the return value. Main returns 0 (or normal exit). We could also use an:
exit(0)
here, but it wouldn't be officially correct.
Now, let's go into what happens when we run this through gcc.
gcc -o helloworld hello_world.c (This is a syntax screwup, check comments for the correct way for Makefiles [gratz Cyberdyne for the correction])
The compiler compiles it (this actually sums up a bunch of steps) and then it is linked dynamically to glibc. When you run the ELF binary helloworld it simply outputs:
Hello World!
If you wanted to link it statically (for instance, so it would run on linux computers which for some reason lack glibc). You could compile it in that manner. Also, -Wall helps detect syntax errors and typos (Once again, gratz Cyberdyne for pointing this out).
C is a procedural language, by procedural I mean it breaks things apart into procedures (or functions as they are more often called). For instance in the above example, main is a function. You could also write the same program as follows:
#include <stdio.h>
void say_hello (void) {
printf ("Hello World!\r\n");
}
int main(void) {
say_hello();
return 0;
}
Functionally it does the same thing, and in something this simple, there's no point in seperating printing out hello world from the main function. Note the return type of say_hello is void. It doesn't return anything (not even a non-typed pointer), hence the lack of a return statement. However, say you wanted to generate some random numbers between x and y. You'd probably want to do this quite often. Here's an example of that:
#include <time.h>
#include <stdio.h>
#include <random.h>
void seed_random (void) {
time_t timeval; //A variable to store the time in secs since the Unix Epoch
time (&now);
srandom (now);
}
int roll_dice (int sides) {
int roll = random() % sides;
roll ++;
return roll;
}
Seed random is a function to reseed the random number generator. To do so we pass our time_t value to the time function by reference (the & symbol) since it takes a pointer to a time value. roll_dice takes an interger argument for the number of sides to a dice, and then uses the random function %(modulus division, or calculating the remainder. IE: 7 % 3 = 1) the number of sides to generate a number. The result is then incremented by one to give a value range of 1 and sides. Note: In practice, we'd want to use a different time grabbing function, for instance gettimeofday() to get the time in u_secs.
It's now time to go into the best thing about C. Pointers. A pointer is simple a "pointer" or a reference to a section of memory. For instance say I have this value:
char arg = 'a';
And I then do this:
char *parg = &arg;
parg points to arg, if I use parg I'm actually using the value of arg(since parg points to arg), so if arg changes, parg also changes and vice versa(but I must reference the location it points to rather then the pointer). You can also have pointers to pointers and all other sorts of fun. We use pointers to cut down on memory usage, this is also why we pass things by reference. For instance when the time_t was passed by reference a pointer to it was passed, when that value was changed, the time_t we passed was also changed.
Next I'll go into the basics of loops.
We have the for loop, such as what follows:
for (a = 0;a < 5;a ++) {
}
This loop sets a (presumably int value) to 0, increments a by one every iteration, and ends the moment a is no longer less then 5.
There's also the while loop.
a = 0;
while (a < 5) {
a++;
}
Which does the same thing. A while loop escapes the moment the condition is no longer true on the next iteration.
Then we have the do while loop:
do {
//stuff
} (while <condition>);
Basically a fancier while that looks better. UPDATE: Technolust seems to think the differences here are important, so I'll go into them. A while will not execute the loop if it's condition is met before it starts. A do while will.
Next up are conditionals. There are two types
the if, else if and else statements:
if (something) {
//do something
} else if (something else) {
//do something
} else {
//do something
}
these are executed in order. If the first statement is met it stops, otherwise it goes to the next, if that statement isn't met, it executes the else.
Now the second type, switches.
A switch compares a series of cases to whatever is used in the switch.
For instance we have a value X, X = 1. We pass it to a switch as follows:
switch (x) {
case 1:
break;
default:
break;
}
It's basically a simplified if/else ladder. It compares X to each case, and if it meets the requirements of that case whatever is there is executed. The break statement stops comparisons (break also exits loops, but it's considered bad form), otherwise it'll go on down the rest of the conditions (yes you can do weird things with a switch). If it doesn't match anything, it executes default.
Dems the basics Sam. I'll go into enumerated data types, structures, macros and a little bit into OO and how it's different for ya sometime later. Oh, and lets not forget Scope and C99. YAY.
argv, argc (Score:2)
You mixed them up here, too. The arguments themselves are called argv (argument Vector), and the number of arguments is called argc (argument Count).
Re:argv, argc (Score:1)
Re:argv, argc (Score:2)
This bit - printf ("Hello World!\n\r"); - for Unix systems, lines are terminated by a single linefeed (\n) character, for DOS-derived systems it's CRLF (\r\n), as opposed to the \n\r you used.
gcc -o helloworld hello_world.c - you change from "hello_world.c" to "helloworld". Minor, but once you start using Makefiles little inconsistencies like that will trip
Re:argv, argc (Score:1)
You can change the value of what a pointer points to, for instance a character array pointer, by using the * operand. I tried to clear that up, guess I failed. If parg points to the location of arg, if arg changes then parg is still pointing to arg (it's actually value doesn't change, but that's a nitpick, I'm trying to
Re:argv, argc (Score:2)
I missed that! But isn't it just \n? I thought \n meant the line ending character(s) for the target OS. As I remember (from a long time ago), DOS/Win compilers would translate it into a cr and lf. The only time you needed to worry was if you were checking input character by character...how I remember it anyway. In Linux, \n will send the cursor to the start of the next line. \r will just put it at the start. Nifty trick, try this:
printf
Re:argv, argc (Score:2)
No; \n represents the single byte for a newline character (ASCII code 10). Unix systems terminate lines with \n (LF), DOS and VMS with \r\n (CRLF), Macs with \r (CR). GCC regards any of these three (plus the \n\r used in the JE, just to be robust) as terminating a line of source code.
As I remember (from a long time ago), DOS/Win compilers would translate it into a cr and lf. The only time you needed to
Re:argv, argc (Score:1)
Re:argv, argc (Score:1)
Re:argv, argc (Score:2)
Yes; in Java, the functionality of argv and argc is combined into a single entity. Instead of argc, use argc.length, and instead of accessing argv[2] you use args[1] (Java puts the first argument in args[0], whereas C puts it in argv[1] and stores the name by which the program was called in argv[0]. On the other hand, apparently some systems put junk in C's argv[0] anyway...)
Wow.... (Score:2)
.... you ARE bored. :-)
Re:Wow.... (Score:1)
Re: (Score:2)
Re:You are the muthafukkin man. (Score:1)
Anyway, no problem. Least I can do.
Re: (Score:2)
Re:You are the muthafukkin man. (Score:1)
On windows, if you want something in the same paradigm, use Cygwin.
do- while (Score:2)
The main difference between a while loop and a do-while loop is that a do-while loop is ALWAYS executed at least once. A while loop may not be executed at all. This is important for someone not familiar with programming to grasp.
Pretty good intro, although you might want to go back and check for typos and define some of the programming lingo, and look at Cyberdyne's comments.
Re:do- while (Score:1)
Couple typos, but I'm not sure how to de-lingoize it much more. I'll address Sam's questions if he has any.
Anything you want to add or correct? For Sam(and for me, I should be perfect even while tired and under the influence dammit)?
Re:do- while (Score:1)
On another matter(keep in mind b-over is now tipsy), how do I go into programming lingo and keep it simple? If I go too deep he'll get lost unless he has some basis, or it'll be too dry to sink in. Do I really need to go into things like the scanner? I'm trying to avoid
Re:do- while (Score:2)
Re:do- while (Score:1)
Re:do- while (Score:2)
Re: (Score:2)
Re:do- while (Score:1)
The problem with thinking up examples is they have to be interesting. I'd rather get the basics out of the way and then toss out ideas for possible simple projects (and you can reference the theory through the JEs) so you have some questions to ask. Thus far, I've come pretty close to condensing CS101 into a journal entry. I should be most of the w
Re: (Score:2)
Re:do- while (Score:1)
Re: (Score:2)
Re:do- while (Score:1)
Quite.
do { } while ( ) doesn't look any *better* than while { }, in fact, it's more complex and even a bit more dangerous, since the first loop is different from the next in that there is no explicit precondition check, and can therefore fail a semantic precondition. In other words it invites for bugs.
Is a bit surprising that people learning to program seem to graps the concept of first doing something and then asking if I should do it again easier than vice versa.
Re:do- while (Score:2)
And now a bit on pointers... (Score:1)
int main(void){
/* Alright, first, I'm going to define a character value,
* then right off the bat, I'm going to _initialize_ it
* with a value, let's make it 'z'.
*/
char foo='z';
/* Now, while I COULD just add the next definition on
* the same line, I'm going to separate it out, so you
* can see the difference better.
*
* This definition is a character POINTER. Ergo, this
* variable isn't ACTUALLY a character variable, but
* rather the memory address OF a character variable
* (in thi
Re:And now a bit on pointers... (Score:1)
you may wonder why we have to give *bar a type (in this case char). Well, the reason for this is so that the compiler knows what kind of value it points to and hence how to perform certain arithmetic operations on it. For instance (and I'm only going to describe this generically for now), you can create a pointer to a character, and then point it to an array of characters. It will then point to the first value in that array. After that, you can simply increment the pointer by one
pointer, reference, address, dereference (Score:1)
As it so happens, our program stored it's variables beginning from address 1020, and each variable takes up 4 bytes. So a is t 1020,
Nitpick (Score:1)
Re:Nitpick (Score:1)
True, though when stepping through the code in a debugger, you WILL see '0'
In any case, you ALLWAYS need to initialise variables before using them, and any good compiler will at least give a warning on unitialised variables that are used. God knows how many bugs I've had just because of uninitialised matrices.
Re:Nitpick (Score:1)
Re:Nitpick (Score:1)
Yes, Kyo got to it first
anyways it is also anything "between" -1 and 2^16-1, to be completely correct
Re:Nitpick (Score:1)
Consider the re-nitpicking complete.
Re:Nitpick (Score:1)
Re:pointer, reference, address, dereference (Score:1)
always always always initialize your integer variables. The above example is incorrect, because it shows b as 0 after it is declared, which is not the case. If you were to attempt to use b after it was declared but before assigning it a value, it would return whatever the integer equivalent was of the memory that was sitting at that location. Not that this is a bad illustration of memory, but for a beginner it is vitally important to realize the distinction between declaration a
Re:pointer, reference, address, dereference (Score:1)
Point taken!!
Buffy here allready pointed it out to me
Re:And now a bit on pointers... (Score:1)
Anyway, thanks for replying, I thought you let you
Have fun in Baltimore,
-N
Re: (Score:2)