C Tutorials
|
Here are the tutorials we have written so far:
Pointers are variables that 'point' to an area of memory. They are one of the hardest parts of C to understand, but they are also very useful. Note: in C, a character is surrounded by apostrophes, eg, 'h' and a string is surrounded by inverted commas, eg, "hello my name is". To declare pointers, you put an * in front of the variable name. eg: char* p. This declares a character pointer to a random byte of memory. Now, if we make an array: char a[20]; and point p at it: p = a; p is now pointing to the adress in memory of the first character of a. Now, say a contains "xyz", p is pointing to 'x'. To acces the char that p is pointing to you use the * operator, ie *p is 'x'. Now, say we want to change the character that p is pointing to to 'f' we say *p='f'. Now a holds the string "fyz". Say you want to change the second letter in the array to 'g', you can say *(p+1)='g' or you can actually move where p is pointing to by 1. ie, p=p+1; //move adress of p 1 char further forward in memory *p='g'; //set char at that adress to 'g' The boring theory bit out of the way, why would you want to a pointer? Well, say you wanted to plot pixels on the screen. Then you point a pointer to video memory and write into it (for more details, download the example: Pixel Plotting in 256 Colour VGA in the examples section). Pretty powerful stuff! Something a bit more basic: if you wanted to change every occurence of the letter 'a' in a string to a capital 'A' then you could do it nicely with pointers. char a[20]; //make array of chars 20 long char* p=a; //make a pointer to array srtcpy(a, "alex met alexandra"); //copy string "alex met alexandra" into array a while ( *p!=0 ) //remember that the last character in an array is a 0, so this will loop until p points to the end of the string { if ( *p=='a' ) //if p is pointing to a little 'a' *p='A'; //replace it with a big 'A' p++; //move where p is pointing to forward by one char } so, array a will now hold "Alex met AlexandrA". This is a very efficient way of carrying out such an operation. - By James Crisp
If you are using mode 13h, and you are plotting pixels straight to memory, then you cannot use your normal graphic functions, that enable you to draw lines. You have to draw them yourself. This is why the following functions were written. Note that some of them refer to plot_pixel(int x, int y, char c). This is just your pixel plotting function.
How to draw lines Horizontal lines void simple_hoz_line(int x1, int x2, int y, char c){
The above code, could be used to draw horizontal lines, between two points x1, and x2. However there are some limitations, x1 must be smaller than x2. Also the line, is not clipped against the edges of the screen. If you indicate, a pixel such as (500, 134), it would actually output to (180, 135). This is because, there would be an overflow. You could add checks to the line drawing mechanism, but it would slow it down. The things that you would be looking for, are things such as boundary checking (is all the line on the screen, or even worse, is the line on the screen at all) and co-ordinate switching (if x1 is greater than x2, you might want to swap them around).
Vertical lines
There are two ways of drawing a line. You can use the equation of the line, or the Bresenham's algorithm. The easiest to implement (and the only one I will talk about for now) , is equation of the line way. This is done, by taking the equation in the form - By Pascal Hakim
#define BLAA 0 /* for cold restart */ /* #define BLAA 0x1234 /* for warm restart */ #define BOOT_SEG 0xffffL #define BOOT_OFF 0x0000L #define BOOT_ADR ((BOOT_SEG << 16) | BOOT_OFF) #define DOS_SEG 0x0040L #define RESET_FLAG 0x0072L #define RESET_ADR ((DOS_SEG << 16) | RESET_FLAG) int main() { void ((far *fp)()) = (void (far *)()) BOOT_ADR; *(int far *)RESET_ADR = BLAA; (*fp)(); return 0; //s'pose this is not really needed! }
A "char" has 8 bits = 1 byte. A "short int" has 16 bits = 2 bytes. A "long int" has 32 bits = 4 bytes.
lets just work with char's at the moment. Operator: << and >> Say you have c=0110 0110 (i'll split the numbers up into lots of 4 so its easier to read). If you do c>>1 that means shift all bits in c to the right by 1. So c=c>>1 makes c==0011 0011. The >> operator just adds a blank zero on where there would have been an empty space. A char is always 8 bits so if we shift everything to the right by one, we have to fill the space left over on the left. Similarly, << makes the bits shift left. so if c=01100110 then c<<1 == 11001100 (it adds a zero on at the right). Why would you want to do this, you ask? Well, take normal base 10 numbers.
If you say shift the digits left in 0123 you get 1230 ... notice something? Yes, its been multiplied by 10. Similarly, if you do >> then its divided by ten. So with binary, which is base 2, a << multiplies by 2 and >> divides by 2. All without having to worry about division and remainder and all that. It really comes in handy when you are thinking about things in terms of 2, for instance when I need to divide by 1024 I just use NUM>>10 since 1024 equals 2 to the power of 10. In the old days, assembler programmers used << and >> wherever possible since they were many many times faster than using a division. But that doesn't really matter now in this age of pentiums... except maybe the stupid computers at school :) Operator: | & ^ ! Well, these operate on bits as well. | = OR & = AND ^ = Exclusive OR ! = COMPLEMENT Lets write it out like sums in first form, so we can see just whats going on: 00101100 | 10100100 ---------- = 10101100 Here, in the answer there is a ONE in the position where there is a ONE in the first OR second OR both numbers. 00101100 & 10100100 ---------- = 00100100 Here, in the answer there is a ONE in the position where there is a ONE in the first AND the second number. 00101100 ^ 10100100 ---------- = 10001000 Here, in the answer there is a ONE in the position where there is a ONE in the first OR second but NOT both. (hence the term "exclusive OR") ! 00101100 [The complement operator only takes one number, not two.] ---------- = 11010011 Here, in the answer there is a ONE in the position where there was a ZERO in the original number, and a ZERO where there was a ONE in the original number, ie. it flipped all the 1's to 0's and vice-versa. Here are some worked examples. Say you are given a variable "flags" and it has some bits set. You want to check if the second bit (from the right) is set. Now, a number with only the second bit set is 00000010 which = 0x02 in hex. So we AND it: if(flags&0x02) { do stuff... }
Because, say for example, flags=01110110. Then 01110110 & 00000010 = 00000010 which equals 2. because this is not zero, the if statement is true. *** remember, in C, if something is not zero it is 'true' *** Say flags was equal to 01110100 (ie. the second bit was NOT set). Then 01110100 & 00000010 = 00000000 which is zero. i.e. the if statement would have been false, and the { do stuff } section would not have been executed. Get it ?!?! :) - By Andrew Snow |