C Programming |
|
'unsigned' can also be combined with char or int types e.g. unsigned char
C doesn't have an intrinsic string type. A string is an array of characters.
Arrays are declared with brackets [ ] after the variable name with the array
size between the brackets (dynamic arrays are covered later).
char name[15];
Declares a character array of 15 characters.
Statements end with a semicolon. Statements can be grouped with braces, for
example in do...loop or if...then constructs.
Speaking of if..then - C has if...else if...else constructs similar to Basic. The word then is not spelled out in C. Here is an if...then:
| if(x > 6){ | |
| statements; | |
| } | |
If only a single statement needs to execute dependent on the if condition, the braces are not necessary:
| if(x > 6) | |
| statement; | |
Note that although the statement is placed on the next line, this is not necessary - whitespace (a character which is not a number, symbol, or letter) is not significant in C, since the compiler knows to look for semicolons or matching braces to determine where lines end.
A single equal sign always indicates assignment in C. To test for equality, a double equal sign is used:
| if(k == 6){ | |
| statements; | |
| } | |
C isn't terribly particular about what you're doing when. Given the above, consider this:
| if((k = x) == 6){ | |
| statements; | |
| } | |
The first line actually does two things. It assigns the value of x to variable k. It also compares the variable's value to numeric 6. The assignment is made regardless of the outcome of the comparison. This may seem to promote terrible confusion, but it's actually a wonderful shorthand - in one line you can call a function, assign the result to a variable, and check the outcome of the function.
Let's look at functions for a second. In Basic, a function returns a value (or reference) and a subroutine does not. In C, they're all called functions. Here's a function:
| int Calc(){ | |
| int result; | |
| statements; | |
| return(result); | |
| } | |
Note that in Basic, the returned value is set by assigning a value to a "variable" with the same name as the function. In C, the value is returned with the reserved word return. This next function does not return a value:
| void Calc(){ | |
| statements; | |
| } | |
Function parameters are declared within the parentheses:
| int Mult(int arg1, int arg2){ | |
| return(arg1 * arg2); | |
| } | |
Ok, so now back to equality and shorthand. Given the above function, you can do something like this:
| if((area = Mult(x,y)) > 30){ | |
| statements; | |
| } | |
That first line calls function Mult, passing it the values of x and y. Mult returns the result, which is assigned to variable area. The result is then compared against the constant 30.
C's inequality is a little different than Basic, too:
| if(x != 6){ | |
| statements; | |
| } | |
| ! | Logical Not | |
| ~ | Bitwise Not | |
| & | Address of, bitwise AND | |
| * | Contents of, multiplication | |
| % | Modulus | |
| | | (shifted backslash) bitwise OR | |
| ^ | Exclusive Or | |
| && | Logical AND | |
| || | (shifted backslash) logical OR |
The difference between logical and bitwise is significant. To examine bitwise operators, recall binary:
| 5 | 00000101 |
The above assumes an 8 bit byte. Now:
x = 5;
y = ~x;
The variable y will be assigned the bitwise NOT of x. This means you invert
each of the bits, which would be 11111010.
Now is where signed versus unsigned variables becomes important. If y is an
unsigned variable, then the value of y will be 250. If y is a signed variable,
the high bit indicates that the value is negative, and the actual value is the
two's complement of the number (it gets subtracted from 128 in the case of an
8-bit byte). The value of y, then, would be -6.
If this makes your brain hurt, don't worry about it. The ones you'll want to deal with is the logicals. Once you're doing bit twiddling in your sleep (and that day may never come) then you'll know which one you want. SO, to refresh your memory on logical (boolean) operators:
1 AND 2 = 0
2 AND 2 = 2
1 OR 2 = 3
3 OR 1 = 3
You still have to look at the binary representations to understand what's going on. Here's the first one, 1 AND 2
| 1 | 00000001 | |
| 2 | 00000010 | |
| 0 | 00000000 |
The second one, 2 AND 2
| 2 | 00000010 | |
| 2 | 00000010 | |
| 2 | 00000010 |
The third, 1 OR 2
| 1 | 00000001 | |
| 2 | 00000010 | |
| 3 | 00000011 |
The comparison is made for each bit. For an AND to be true, both bits must be 1. For OR to be true, either one or both bits must be 1.
In C, the first one is written 1 && 2, the second is 2 && 2, and the third is 1 || 2. Usually you're using this in an if statement:
| if(1 || 2){ | |
| statements; | |
| } | |
As with the then of if...then, there is no explicitely typed next in for...next. We again use the brace. A C for statement is in three parts, separated by semicolons and surrounded by parentheses. The first part is usually used to set an initial value to the loop variable. The second is used to compare the loop variable to decide whether or not to execute the loop statements, and the third is usually used to increment or decrement the loop variable. Consider the Basic statement For x = 1 to 5. In C, this would be written:
| for(x = 0; x <= 5; x = x + 1){ | |
| statements; | |
| } | |
Notice that <= is used (less than or equal to) because in Basic the 5 is inclusive. Each of the three parts in a C for is optional - this is actually legal:
for(;;){
Note that the semicolons are not optional. Why would you omit any of the parts? Let's say that you already have some meaningful value in your loop variable x.
for(;x < 80; x = x + 1){
so the loop will begin executing with whatever value is in x. If x is already >= to 80, the loop statements won't execute at all.
Likewise, let's say you're manipulating the x variable within the loop, so you don't need the increment/decrement part:
| for(x = 0; x < 80;){ | ||
| if(y < 10) | ||
| x = x + 1; | ||
| else | ||
| x = x + 2; | ||
| } | ||
Some more shorthand
Because it's so frequently done, C has a shorthand for incrementing or decrementing
a variable by 1:
x++;
is the same as:
x = x + 1;
and
x--;
is the same as
x = x - 1;
These are called post increment and post decrement, respectively. A pre increment looks like this:
++x;
This becomes important if you're doing several things on one line. For the following, let's assume that the value of x is 5.
| if(x++ == 6){ | |
| statements; | |
| } | |
The operative word here is post-increment. What this means is that the last thing the compiler will do for that first line is to increment the variable. Since the value of x is 5, and 5 != 6, the statements within the if block will not execute. On the other hand,
| if(++x == 6{ | |
| statements; | |
| } | |
the statements within the if block will execute because the compiler will increment x before performing the comparison.
Some more shorthand:
x += 2;
is the same as
x = x + 2;
This works for other mathematical operators, too:
x /= 2;
is the same as
x = x / 2;
In Basic, if you find yourself within a loop and you want out of it, you do so by:
Exit For
In C, this is accomplished with the reserved word break. C has an additional reserved word, continue, which does not have an equivalent in Basic. continue causes program execution to go to the top of the loop. If this is a for loop,
| for(x = 0; x <= 50; x = x + 1){ | |
| statements; | |
| if(x > 20) continue; | |
| morestatements; | |
| } | |
The 'morestatements' won't be executed for values of x above 20. The loopstatements above the if test will execute for all values of x from 0 to 50.
C has an equivalent to Basic's do...while construct. Once again we use braces, but guess what - we do actually use the word while!
| do{ | |
| statements; | |
| }while(x < 4); | |
Look carefully at the last line. The while reserved word closes the loop with a conditional test. There is a semicolon after while to let the compiler know where the statement ends. You can also do this:
| while(x < 4){ | |
| statements; | |
| } | |
There's a subtle difference. If the value of x is above 4, the first example will execute once, but control will continue to the statement after while afterward because the condition isn't true. In the second example, however, the statements within the while block won't execute at all because the test is false at the onset.
Because of the versatility of the for...next construct, there's actually almost no functional difference between for...next and do...while in C - that is, you can construct a for...next that will act just like a do...while, and you can construct a do...while that will act just like a for...next.
| for(x = 0; x < 5; x++){ | |
| statements; | |
| } | |
| x = 0; | |
| do{ | |
| statements; | |
| }while(++x < 5); | |
are functionally equivalent.
There are times when one is more convenient than the other, but you may so prefer one to the other that you use the one almost exclusively. The only right or wrong is whether or not the program works, so do what feels good.
Speaking of programs, here's the shortest possible C program:
| int main(int argv, char **argc){ | |
| return(0); | |
| } | |
According to the C language specification, all C programs must have a function main. main must return an integer, and must accept the arguments listed above. Microsoft modified this for Windows® ever so slightly. A windows program must have a function WinMain() which returns an integer and has a bunch of arguments that will be detailed later. Here's the shortest possible windows program (well, minus a couple of lines):
| LRESULT CALLBACK WndProc( | ||||||
| HWND hwnd, // handle to window | ||||||
| UINT uMsg, // message identifier | ||||||
| WPARAM wParam, // first message parameter | ||||||
| LPARAM lParam // second message parameter | ||||||
| ){ | ||||||
| UINT nID; | ||||||
| switch(uMsg){ | ||||||
| case WM_COMMAND: | ||||||
| nID = LOWORD(wParam); | ||||||
| switch(nID){ | ||||||
| case IDC_BTNFND: | ||||||
| OnFind(); | ||||||
| break; | ||||||
| default: | ||||||
| break; | ||||||
| } // EndSwitch command id | ||||||
| return(0); | ||||||
| break; | ||||||
| case WM_SETCURSOR: | ||||||
| return(0); | ||||||
| break; | ||||||
| default: | ||||||
| return(DefWindowProc(hwnd,uMsg,wParam,lParam)); | ||||||
| } // EndSwitch message ID | ||||||
| return(0); | ||||||
| } // End WndProc() | ||||||
int APIENTRY WinMain(HINSTANCE hInstance,
HINSTANCE hPrevInstance,
LPSTR lpCmdLine,
int nCmdShow)
{
WNDCLASS wcls;
MSG msg;
ghInst = hInstance;
wcls.cbClsExtra = 0;
wcls.cbWndExtra = 0;
wcls.hbrBackground = (HBRUSH)(COLOR_WINDOW + 1);
wcls.hCursor = LoadCursor(hInstance,"IDC_ARROW");
wcls.hIcon = NULL;
wcls.hInstance = hInstance;
wcls.lpfnWndProc = WndProc;
wcls.lpszClassName = "W32AppClass";
wcls.lpszMenuName = "Win32 App";
wcls.style = 0;
RegisterClass(&wcls);
hwndMain = CreateWindow("W32AppClass","Main",WS_VISIBLE
| WS_OVERLAPPEDWINDOW | WS_SYSMENU,100,100,400,600,NULL,NULL,hInstance,0);
while(GetMessage(&msg,hwndMain,0,0) == TRUE){
TranslateMessage(&msg);
DispatchMessage(&msg);
};
UnregisterClass("W32AppClass",hInstance);
return 0;
}