Tuesday, September 28, 2010

I see now

I know why it works now.

Lesson 1: Pointers are nice because they let you manipulate variables outside of the function you happen to be in.

Lesson 2: Pointers are nice because they let you manipulate pointers outside of the function you happen to be in.

Lesson 3: I need to stop treating pointers like they're not variables.

I got this to work by more or less following examples in the book, but now I realize why it works.

I had a pointer: FILE *plxfilepointer

plxfilepointer doesn't point to anything yet. It's (probably) NULL, I don't know if it gets specifically set to that or if I have to do it manually.

I can't pass the pointer to the function that opens the file. Well... actually I can, but it gets passed by value and the local function's pointer dies when the function ends.

So, what I did instead was pass the address of the pointer - that is NOT to say the address the pointer contains, but the actual address in memory of where the pointer is. That was what lesson 3 above means. A pointer is a variable that holds a memory address that has its own memory address. I didn't NOT know that, it's just easy to forget when push comes to shove in the code.

Ok, so I pass my function the address of my pointer: loadfile(&plxfilepointer)

Here is the part that I finally understand: an integer holds an integer and has its own memory address, and a pointer holds the memory address to another place in memory and also has its own memory address. What holds the memory address of a pointer and also has its own memory address? A pointer to a pointer. So, the proper variable to pass the memory address of a pointer to is a pointer to a pointer.

So, the loadfile() prototype is:

void loadfile (FILE **a)

**a is a pointer to a pointer, and when I pass it &plxfilepointer it pointers to plxfilepointer, which we want to hold a memory address to our file.

inside loadfile is: *a = fopen("test.plx", "rb");

Ah, so if I dereference a pointer to a pointer, I get the value of the pointer I point to, so I can set the pointer I point to to anything I want - in this case the memory address of the file I loaded. There has to be a better way to say that.

So when the function is over, what is destroyed? Only my pointer to the pointer.

I got this to work with trial and error (and lots of sketching) last night, and I was super upset that it worked without me knowing why it worked. I had to go to bed before I could figure that out, but I figured it out just laying in bed and focusing. That's good - it probably means I'm committing a lot of what I'm learning to memory.

The punchline: I need to stop treating pointers like magic, and I need to not get tripped up by the asterisks. Oh, and I'd have never made it work in the first place if I hadn't drawn out what was happening in memory.

Monday, September 27, 2010

found a better way

Ok, gotta go to bed, but I found a better way. Plus, I think I know how it works. Followup in the morning.

whooooaaa....

Holy smokes it worked.



I had to draw it out, and figure out how to NOT intentionally declare what I wanted to return (which is where void* came into play), but it worked. I don't 100% know why..... but it's good enough for now!

The WRONG way I was doing it was that I was treating the FILE data type like I would INT. A shorter version of the wrong way:

FILE loadfile(FILE *filepointer)
{
filepointer = fopen("test.plx", "rb");
return filepointer;
}

int main()
{
FILE *plxfilepointer;
plxfilepointer = loadfile(plxfilepointer);
...
}

That threw a big fit with compiler errors like "incompatible types when assigning to type 'struct FILE *' from type 'FILE'|"

So what I realized is that FILE is special somehow and I'd have to cheat a bit. Ultimately I wanted to return a pointer to the right place. So I knew I could declare the file pointer in main(), but then I needed to pass THAT variable a legit address to "be".

I had to get my function to want to return a pointer of any kind, not a FILE pointer.... I still don't think I understand this fully.

What I also don't understand fully is this:

plxfilepointer = loadfile(&plxfilepointer);

Ok, so I pass it the address of my FILE pointer, and then what?

void* loadfile(FILE **filepointer)
{
*filepointer = fopen("test.plx", "rb");
return *filepointer;
}

Am I doing (FILE **filepointer = &plxfilepointer)? That seems circular. The address of my FILE pointer is copied to the function as a pointer to a pointer?

return *filepointer is returning a pointer (because I'm dereferencing a pointer to a pointer, which is a pointer) and making it equal to plxfilepointer.

I understand why THAT works... I wanted to return a pointer to my pointer in main(). I just don't understand why passing the address of my FILE pointer to the function worked.

The wrong way

Well, my original intention was to show how variables declared in functions, including pointers, would be destroyed after the a function returned, but now I'm hitting new problems.

I wanted to compartmentalize the loading of the file because it would make this code a bit more portable - I could just copy the functions I needed to the next iteration of what I'm working on. I really don't want to load the file in the main part of the loop because I'd only be able to do it once. What if I wanted to close the file and load a different one without restarting the program. I can think of a way to do this without having functions for doing it, but I'd rather do it this way to practice. I could just pass arguments to the function that said whether or not to reload on or whatever.

I actually "discovered" pointers to pointers by drawing it out and realized "boy it would be nice if I could have a pointer to a pointer". It probably isn't the right solution to this problem, but we'll see.

The right way and wrong way

I wrote a piece of code, what I had referred to as the most advanced I had done yet.



The only lingering unknown is what the pointer that fread() returns is really pointing to. Did it really load the whole file into RAM? What if the file was too big?

Right now it's straightforward code, but I want compartmentalize the file loading code into a function. The next two posts will be the wrong way to do this, and what I hope is the right way.

huh?

Does pastebin stuff expire after a certain time?

Friday, September 24, 2010

embedding pastebin test

I need a better solution for showing code here:






Let's see if that works.

bad example

K&R uses too many super complicated examples. Too many shortcuts in the code, and too many little tricks to keep it shorter. Plus none of the examples are immediately functional - it's just snippets.

I'm chugging along in the strings/pointers chapter and it has an obtuse example program of how to sort lines in text with an array of pointers that I barely can follow. Now I'm at the part about function pointers, and it decides to rewrite the obtuse example to use function pointers! Not helpful!

So for this particular thing I need to either find another source of information - OR - I need to just start a few subsections back and actually learn what the obtuse program is doing. That itself would kill a weekend. I dunno, I'll have to think on this. I have yet to be sorry that I went back and really dug into something in this book, but I don't have 12 hours of uninterrupted time in the near future to dig in.

Wednesday, September 22, 2010

jeez

I keep banging my head over stupid stuff.

I finally got the program to do what I wanted (read a bit of header info), but man did the journey to that point make me feel dumb.

First of all, I will reiterate again that pointers aren't taught very well, and very few tutorials or books make sense of them. I swear right now that when I feel confident enough I will write a tutorial that would have worked for me 10 years ago.

The issue is that in small programs pointers do nothing for you. All tutorial code or code snippets in books are not using pointers like they would be used in real life.

Anyways, what I was banging my head over was pointers to structures.

If I have

struct woof {int i;};

and then I say

struct woof *dog;

it's analogous to saying

int *i;

and I forgot that. So I was doing this:

struct woof *dog;

dog->i = 5;

which you can't do, because although I declared a pointer to a structure woof, I never properly initialized the pointer by giving it a memory address to a legit instance (is instance the right word?) of the structure.

If I had said:

struct woof puppy;
struct woof *dog = &puppy;
dog->i = 4;

then I'd be good to go.

In a small program going through all that rigmarole is useless. I did it in my little program as practice, but I'm learning now that it's bad practice (despite learning a lot THIS time) because it's not "real world".

I think I'll be able to flesh out the program soon (when I package certain parts into functions) such that using pointers will be more efficient because I won't be passing unwieldy structures by value.

open a file

I've been doing a lot of reading, so now I'll do a bit of doing.

int main()
{
FILE *plxfilepointer = fopen("test.plx", "rb");

if (plxfilepointer == NULL)
{
printf("No File Found\n\n");
return 0; // bail out of main() AKA end program
}

printf("Found File at %p\n\n", plxfilepointer);

fclose(plxfilepointer);

return 0;

}

Ok, so this does basically what it says, fair enough. My issue is this: I don't want to do it in the main function block. I'd rather pass the responsibility of opening the file to another function, and then have other functions for reading things from the file. I have an idea how to pull this off, but it really depends on how fopen() works under the hood. Seeing whether or not it returns null isn't good enough for testing how it all works, so I'll have to flesh out the program to at least read in some header info from the file.

Two projects (plus final exam)

I have two projects I want to tackle to get me over a few programming concept humps.

The first is something practical - read in and dump out values in a .plx (Plexon file format) file. I choose this because it's relatively straightforward and would be a big boost to my street cred at work (as well as, you know, help me be helpful to my customers probably). I have started this project already and the issues I've had with reading files will be the subject of my next few posts (spoiler alert: local variables - including pointers - are destroyed after exiting a function).

The second project is a bit more ambitious. I'd like to make a small simple little game. The traditional console-based game to write is blackjack, but I'd like to get out of console world sooner, so I'll be attempting to do some basic GUI programming. I'm trying to narrow down my options, but QT seems to be the obvious choice. I don't think there will be too many hindrances (says the newb) trying to do it in straight C (as opposed to C++). If there are, I'll look at TK or something. I'm still in the early research phase here.

I have actually decided on what project will be my litmus test for being "good enough" at C to move on to other things (C++ or whatever). It's another game since games integrate so many concepts of programming. So, I'd like to make a Lunar Lander clone. It's a simple 2d game, and it will force me to try and do a little physics programming and learn OpenGL along the way. It would be super awesome if I could integrate hand-drawn graphics and sound. I'd like to shoot for early 2011 to be at this stage of the learning process.

Tuesday, September 21, 2010

whoops

So I was making great progress in understanding pointers, arrays, memory, etc, and the Minecraft came along.

Uhm.....

So I need to buckle down and not be lazy. I'm being good about at least once a day looking at various online resources (www.stackoverflow.com is good to peruse).

Sunday, September 12, 2010

DDT

I think I might have figured out the problem I was having this morning.

Here's the Truth Nugget: Just because an array can behave like a pointer in some ways, doesn't mean it IS a pointer.

So the problem before was that if I have an array s[10], then just using s in an expression is using the address of the first element of the array - kind of like a pointer.

so:

char s[10];
char *ptr;

I can say:

ptr = s, without having to say explicitly ptr = &s[0] or something like that.

HOWEVER it doesn't go the other way.

I can't say s = ptr.

Why? Because.

DDT. Don't Do That.

Big thanks to http://www.eskimo.com/~scs/cclass/krnotes/sx8c.html

That site has saved me several times. I'd pay good money to have all those notes in a book.

Woof, pointers

My first attempt at learning C in high school ended when I couldn't understand pointers. I figured it was too important to just truck on without understanding them, so I stopped. This time around I have more discipline and focus (I hope), so I'm making sure that I keep throwing myself against the wall until I start making a dent, or at least a worn out area.

I'm writing little programs to poke around at the behavior of pointers. I might be hosing myself early on since I'm using printf() to print out the results of my little tests, and printf() might be smart enough to do things right even if I'm not. For example:

char sometext[] = "THIS IS SOMETEXT";
char *someothertext = "THIS IS SOMEOTHERTEXT"

sometext is a character array, and someothertext holds a memory address to a space in memory where "THIS IS SOMEOTHERTEXT" starts.

My book here says that (with my variable names substituted) "Since the name of an array is a synonym for the location of the initial element, the assignment someothertext=&sometext[0] can also be written as someothertext=sometext".

Ok, I can buy that, but where things get confusing for me is when you try to go the other way.

I can't say:

sometext = someothertext

...without my compiler barking at me with "error: incompatible types with assigning to type 'char[17]' from type 'char *'".

Ok... but why? You just said that sometext (just the name) holds the address of where a string starts. I want that address to now be the same address that someothertext holds. It very well might be that the compiler is trying to save me from myself, OR this might be one of those "core concepts behind programming" that I haven't internalized yet or have been exposed to in my self-taught journey.

In my fiddling around, I also tried to trick it and say:

&sometext = someothertext

...just to see if that would make it work, but no go.

Stuff like this irks me because I'm afraid I'll be forced to move on without really understanding it, and then it will bite me in the ass down the line.

Thursday, September 9, 2010

reading about reading

I've been using the C/C++ SDK that my company provides to our customers for reading our file format as inspiration of what to learn next. The SDK consists of a header file defining the file format (which is a whole mess of structures - is that all any format is?) and some sample programs to do simple things like read the headers and dump out the first 200 data points.

I understand about 95% of the header that defines the file format (it's really vanilla data structures - no linked lists or trees, etc), and about 80% of the sample file that reads in a file and gets information from it. Luckily the sample program is console based, so there isn't any GUI mess to sift through.

The 20% of the program that I don't understand has to do with reading in the file and passing the data to an array of data structures. Specifically, the 20% of confusion is fread(). I'll just have to play with it to see if I can tease out how it works. The internet isn't helping that much.

The read data function in the sample program first uses fread() to get some info, then it calls it several more times to pass data to other data structures using practically the same function call with the exception of which data structure to pass data to.... which didn't seem right at first. How does fread() know what data goes where? Well, it turns out (after HOURS of forum crawling) that fread() is smart enough to increment the file pointer and keep it there so that the next time to call the function to get the next blob of data, you start where you left off! There is actually a companion function of sorts called fseek() that I think can put the pointer at the beginning or end or wherever. I'm not sure yet.

I'm pissed that such a vital piece of info is never actually mentioned, or if it is, it's cryptic.

For example, type "fread" into Google and you get this as your first result:

http://www.cplusplus.com/reference/clibrary/cstdio/fread/

With this description:

size_t fread ( void * ptr, size_t size, size_t count, FILE * stream );

"Reads an array of count elements, each one with a size of size bytes, from the stream and stores them in the block of memory specified by ptr. The poistion indicator of the stream is advanced by the total amount of bytes read. The total amount of bytes read if successful is (size * count)."

I understand that there are four parts - variable to hold data read, size of data to be read, how many of those sizes to read in, and the pointer to the file. What is NOT clear is the sentence "The position indicator of the stream is advanced by the total amount of bytes read" unless you know that the pointer to the file IS the position indicator.

That could be stated MUCH clearer. I kept reading that as "you go through the file by how much you asked to go through the file". Maybe stating is as "The pointer to the file will start by being a pointer to the start of the file in memory, and will be incremented and left there by the amount of data read in by fread()". I finally found some resource that stated this explicitly, and now I think I understand.

Sunday, September 5, 2010

back at it

I'm back at it after a few weeks of not actually coding. I'm reading plenty, but that is no substitute for hitting a keyboard.

The plan is to prove my understanding of program structure and passing things to functions for manipulation.

Overall, the plan is this:

Be presented with some options (1,2,3,4, etc) and a big array of text (Desiderata, for now). Each option will perform a task and return the result. The first few obvious ones are a histogram of letters in the text (which I touched on in my prior post), sorting the words/line/etc by length, removing/inserting characters, and other common beginner things you're supposed to be able to do with text in an array.

The first hurdle is reading in the options. I remember that C++ has the CIN function, but C itself doesn't seem to have such a clear method of taking input from the keyboard. It does have getchar(), but it seems like overkill. Since I can't find any alternative (none anyways in my book yet) I'll just go with overkill.

Here is my first test to make sure that I understand what getchar() is doing:

main()
{
char character;
int integer;

integer = character = getchar();

printf("character is %c\n", character);
printf("integer is %i\n", integer);
}

The output is as I expect. If I run the program, it holds and waits for me to type in a character and hit enter. so...

chris@chris:~/learningc$ ./getchartests
f
character is f
integer is 102

No surprises... for a change.

The next move is to write a program that takes in this character (in a slightly better formatted way) and shuffles it through your standard switch/case statements. I guess I could do a big if/then block, but there will be plenty of those to come.