You are not logged in.
C is okay. It's just really hard to understand.
So this is my rant about it. It starts out by listing where I've been in terms of programming and then lists my difficulties with C itself.
I discovered C many years ago. I'm not too sure how. All I know is that for many years I've wanted to know what this C thing was all about, but had no way or knowledge of how to. I didn't really know anybody before I got the 'net last year, so asking someone else was out of the question. Plus, I wouldnt've known what question(s) to ask.
As I became more proficient with the whole technology thing, I began to go to the local libraries nearby and use their free internet access to look stuff up. But I didn't get the idea to do any research about C, most likely because I didn't have the mental capacity to plan well and my access was once or twice weekly at best. Plus, the only computer I had at home was 66MHz and ran DOS, and I only knew BASIC around that time which I was comfortable and content with, so wasn't looking for a new language. I think I knew about assembly language but didn't pursue it if I did.
A couple of computer upgrades later, I finally got the 'net at home and began to see the convenience of being able to spontaneously look something up when I wanted to as good, rather than weird. Ideas gradually began to pop into my head that I'd run off and look up, and one day C became one of them. So I did some research on C and finally began to learn what it was: an incomprehensible mess of manually managed memory and low-level trickery. Since I knew a fair bit about assembly language now I decided C was worse than asm (and I had no chance of learning asm back then), and left it at that.
Being the BASIC coder I was (pun intended), I found the syntax and concepts over my head by several miles. But the fascination never died, and kept poking at me again and again. And I just had to keep forgetting about it.
I moved on from QuickBASIC, which I'd been using for just about everything, to FreeBASIC, which was in such a beta state when I tried it, I disliked it enough to move on and discovered PHP.
PHP has been called the BASIC of the 21st century, and I can understand why. There are typically at least 10 ways to do something whether in principle or method, multiple functions do the same or an equivalent task, and overall it just doesn't look like a good language. But beyond all that, PHP made sense to me. As I went along many of the things I expected to perform in a given way performed in said way, which was a huge confidence boost. The model it followed might have been convoluted, but something inside my head "clicked" when I saw PHP, so I liked it, since I could understand it easily.
But recently, I found myself hitting too many walls. I wanted to get into graphical software development, and none of the graphical extensions PHP had available would work for me. PHP-GTK did work but prevented PHP from outputting anything as an Apache module, without throwing a single error anywhere. PHP-QT wouldn't compile on my system. PHP-TK did compile, but both segfaulted when any tk_* function was called and also exhibited the Apache module issue.
So I decided then and there that I needed to switch languages.
The problem was, my current machine happens to be so slow that a GIMP operation that executes in 6 seconds on the lowest generation AMD CPU from 4-5 years ago will execute in 38 seconds on mine. I have no idea why; the machine is, after all, 2.66GHz.
Although PHP is pretty snappy on my system, I don't know how other languages would fare and don't really want to risk the experiment; I want to switch to a language I know will be as fast as, or faster than, PHP. So I decided that a compiled language would have to be it, since I regarded PHP as the fastest language I knew. I was probably wrong, but whatever.
So I set my mind to understanding C. I'd asked around online before, and someone took pity on me and explained the basics of C and I did my best to understand them. This was great for a couple of days, but didn't last all that long unfortunately. So I asked around again, dreading their responses, and with good reason too: most of the tutorials I read often left me boggled and flew over my head at one point or another, which didn't help.
But I got some dreaded tutorial links, and did my best to read them. It took me a couple of weeks to finally convince my brain to understand the point of a language that utilizes variables that doesn't contain any data, but instead references to other variables. I eventually grasped the why, but am still having quite a hard time understanding the how.
So then, after that initial hurdle, I moved onto other topics. Or rather tried to. I quickly discovered that C interconnects some of its issues so deeply that it's hard to learn one thing at a time, move on and learn the next thing - how I best learn. I don't create paths very well by reading information; I create those paths by staying away from information and letting it slowly process in my mind. But to actually remember it in the first place, it needs to make sense, and C doesn't make sense because things are so interconnected and... we come full circle.
To be honest, after about a fortnight of trying to understand pointers, I still don't understand them. I've read what is probably the best the web has to offer about pointers. Has it helped? Not really.
Either the documentation:
- is too terse and I have to slow down, risking losing interest in what I'm reading
- skips over vital points or assumes I know Pascal or some other language
- is hard to understand or is poorly written
- puts segments in the wrong order, so I don't understand everything something might depend on before I reach that something
...and in general I either give up on reading the documentation, give up on C or just cry. I've done the 3rd a few times, the 2nd quite a few times and the 1st pretty much as many times as I've read documentation.
So what are my issues with C?
Let me address the two I can think of right now:
Pointers aren't addressed "simply"; if I declare a pointer to int named x I have to use *x to access what x points to, rather than use *x to get x's location, like one does with non-pointer variables where & is used to get an address. It'd be nice if we used &x to get x's value if x wasn't a pointer and *x to get x's value if x was a pointer, rather than use this convoluted scheme.
Also, I've heard that it's a common misconception that C handles arrays natively. Elsewhere, I've heard that strings are merely arrays of char. I can understand the 2nd, but what do I do with the 1st?
I do understand that if I say printf("%d\n", x[1]) I'm effectively saying x++; printf("%d\n", x), but I don't understand how this fully works. For example, let us consider the following code:
char *filename = "<insert file here>";
int i;
struct stat filebuffer;
int status;
FILE *handle;
handle = fopen(filename, "r");
status = stat(filename, &filebuffer);
char *buffer = malloc(filebuffer.st_size);
for (i = 0; i < filebuffer.st_size; i++) buffer[i] = fgetc(handle);
printf("%s\n", buffer);
You'll of course notice the array notation. Do I understand why if I replace said notation with something to the effect of...
buffer++
buffer = fgetc(handle);
...the program segfaults? No. Likewise, I don't understand why the...
buffer++
*buffer = fgetc(handle);
...in the loop does work, printf("%s"...); causes segfaults and printf("%d"...); does not.
Another thing I found is that declaring a char *, filling it with data, and then using memcpy on said char *, the program works fine, but if I declare for example char x[1] = "hi"; the compiler will shout at me for not allocating enough arrays. Only while writing this did I realize that the 2nd element is for the null byte.
Suffice to say that C confuses me. To bits. Although I have written a 500 line program in it (579 to be exact). All said program does is display a message on the screen via Xlib, but I managed to figure out how to make a word wrapping engine using strsep and how to use XDrawPoint XDrawLine to not only create a nice UI but also let me define various UI "styles" which can be loaded at startup.
Said program uses a very big helping of "if it doesn't work stab it until it does", so not only do I not understand how a lot of it works, it probably wouldn't compile under anything except gcc. Which is from a theory perspective quite a problem, IMHO. Almost every 2nd variable is typecast to this or that type.
So put simply, every tutorial or introduction to C hasn't made a lot of sense to me. Maybe I learn slowly; I'm hoping it's that, because I can't see anything besides assembly language which would be faster than C. I plan to learn asm after I've mastered the very basics of C, but I may end up having to learn the other way around if I expect to get anywhere.
Like I said in the title, I have one actual question in this post. So here it is:
Are there any fun, easy reading tutorials out there that don't visually look like they came out of 1992 and read like http://poignantguide.net/ or http://learnyouahaskell.com/?
-dav7
Windows was made for looking at success from a distance through a wall of oversimplicity. Linux removes the wall, so you can just walk up to success and make it your own.
--
Reinventing the wheel is fun. You get to redefine pi.
Offline
I have no answer to your question and I'm still procrastinating in learning a "serious" programming language. I just had to say that I quite enjoy your forum mannerisms.
I'm now going to take a look at that Haskell tutorial (something inside my head keeps saying "learn Haskell", to which I reply "why?", and then it goes "dunno, just do it"... so I keep my eyes open for anything that will convince me that it's worth doing (still haven't fully grasped its target area of application)).
(yeah, I realize that my mannerisms turn my posts into pseudo-lisp (another one of the "hey, you should learn that" languages))
EDIT
fixed typo: "not" to "now"
Last edited by Xyne (2008-11-03 14:24:42)
My Arch Linux Stuff • Forum Etiquette • Community Ethos - Arch is not for everyone
Offline
There are a few good ebooks out there. freecomputerbooks.com The older ones by the way are sometimes the best because they are the ones that actually explain what is going on. A few of the new ones skip things (as you mentioned). I learned C originally through the "C for Dummies" books around 5 years ago and that would have made me twelve or thirteen so they weren't hard to understand as i still retain most of what I read from them. I will say however if you read those books that some things are explained inadequately and say "this works you don't need to know why".
Offline
Xyne: thanks.
I think I have for C what you have for Haskell. A complete inability to fully understand it yet a niggling feeling to just GO AND LEARN IT ALREADY.
But lisp-style mannerisms are good. I can see you'd never get yourself tied up into the end-a-bracketized-statement-with-a-smiley-face thing.
reanimator: I see. Thanks for that link; I'll check that out.
I did in fact find (or it was pointed out to me) a document explaining C from 1970 or so; it was actually written before the first C book was released, and was fairly interesting.
It unfortunately explained pointers like this though, and was from where I declared "some tutorials to be terse":
<basic description>
int x = 1; int *hi = &x; *hi = 2; printf("%d\n", x); // 2
Which was just as good as saying
That over there is called water. It is very deep. If you are not careful you may drown.
#include <objects.h> #include <cannon.h> #include <speech.h> User dav7; Object water; load_cannon(dav7); aim_cannon(water); fire(); shout("NOW YOU USE YOUR INSTINCT TO FIGURE OUT HOW TO SWIM!!1\n", VOL_LOUD);
but at the same time
I do understand * and & though. Sorta.
-dav7
Last edited by dav7 (2008-11-03 13:59:00)
Windows was made for looking at success from a distance through a wall of oversimplicity. Linux removes the wall, so you can just walk up to success and make it your own.
--
Reinventing the wheel is fun. You get to redefine pi.
Offline
It unfortunately explained pointers like this though, and was from where I declared "some tutorials to be terse":
<basic description>
int x = 1; int *hi = &x; *hi = 2; printf("%d\n", x); // 2
That is basically everything there is to understand about pointers in four lines... combine that with memory assignment and you can pretty much handle of C.
Online
Hmm, I'm reading this right now, doesn't seem to be too bad.
http://home.netcom.com/~tjensen/ptr/pointers.htm
Has a few examples and whatnot and since it has been a while since I have actually programmed in C I would need to refresh myself on them otherwise I would happily do my best to explain what I can.
Offline
I think I have for C what you have for Haskell. A complete inability to fully understand it yet a niggling feeling to just GO AND LEARN IT ALREADY.
I'll let you know how the understanding goes later. For me it's just been one of those languages that I'm aware of but haven't looked into yet. I read the wikipedia page on it before (and ended up chaining right though overviews and comparisons of programming paradigms all the way to WWII cryptography) and a few summaries on the web, but because I haven't had a clear idea of when I would/could use it, I haven't gone through any tutorials.
That written, I've finally installed the relatively huge ghc package and just went through the first 2 chapters of the tutorial that you linked (quite a good one, fun without the usual double-portion of cheesy jokes... nice find... got something similar for Lisp?). I definitely see how some things will be very easy in it and so far I like the syntax.
My Arch Linux Stuff • Forum Etiquette • Community Ethos - Arch is not for everyone
Offline
Hello.
I can not recommend any tutorials. I can only recommend the following: if you are serious about C programming, you should buy a copy of "The C Programming Language" (2nd edition) by Kernighan & Ritchie and study it -- even though it may not be that - "easy read" - you seem to be looking for.
P.S.: Assembly language programming might turn out to be harder to master than you think.
Offline
I have been programming on and off for rather a long time now, so I do have a bit of experience (which might admittedly not be so relevant to another person). I am so old that I started with writing assembler code for 8-bit microprocessors (including stuff like Fourier transforms!). I think to someone like me, being able to write in C would (then) have been a real luxury, it would all have been so easy (but in the case of the Fourier transforms possibly too slow). Here we are many years later, and I would say if you want to have fun and a feeling of success at programming, please try python, or maybe lua or ruby, etc., first. They should all be at least as fast as PHP, if that concerns you. And python works very well with gtk, Qt and tk.
Concerning speed, what speed is it, anyway? Certainly not speed of development. Many programs that need speed might benefit from being written mainly in a more friendly language with just the time-critical bits in C. And if your 2.66GHz computer is too slow, investigate that (DMA not activated, insufficient memory, ...?)
If you are a masochist or really want to twist your brain around the innards of computers, first learn about computer hardware, then the basics of assembler language (what instructions the actual computer hardware can execute and why), maybe the basics of operating system design, and then you are in a good position to understand the idea behind C. Of course it's not necessary to go this way in order to learn C, I say only it's a way to get a feeling for how and why C arose.
Haskell, Lisp, Eiffel, D (and many others) are certainly also interesting intellectual exercises, especially as regards the question of why they haven't really caught on like C++, Java (, C#, VisualBasic?).
Good luck, and, especially, have fun!
larch: http://larch.berlios.de
Offline
Assembly, all the way. Once you've cracked that all else is just salad-dressing. No need to make it difficult for yourself, just
use assembly language to call C functions ( push function parameters; call function; get result). If you're interested PM me
and, once I get my backups re-installed, I'll send you an example.
Other languages worth looking at are Linoleum:
and Euphoria:
These are not trivial languages by any means, to quote the Euphoria page:
Euphoria is a simple, flexible, and easy-to-learn programming language. It lets you quickly and easily develop programs for Windows, DOS, Linux and FreeBSD. Euphoria was first released in 1993. Since then Rapid Deployment Software has been steadily improving it with the help of a growing number of enthusiastic users. Although Euphoria provides subscript checking, uninitialized variable checking and numerous other run-time checks, it is extremely fast. People use it to develop Windows GUI programs, high-speed DOS games, and Linux/FreeBSD X Windows programs. It is also very useful for CGI (Web-based) programming
One of the three options could be the answer you are looking for.
Good luck,
Deej
Offline
dav7 wrote:It unfortunately explained pointers like this though, and was from where I declared "some tutorials to be terse":
<basic description>
int x = 1; int *hi = &x; *hi = 2; printf("%d\n", x); // 2
That is basically everything there is to understand about pointers in four lines... combine that with memory assignment and you can pretty much handle of C.
You forget this part:
int y[10];
y[0] = 15;
y[1] = 20;
printf("%d = %d\n", y, y[0]);
printf("%d = %d\n", y[0], y+0);
printf("%d = %d\n", y[1], y+1);
Let me try to summarize in a way that makes sense if you come from a land of objects down to the world of C. See, I learned the opposite way, with assembly and all that jazz in there. There is no such thing as datatypes at that level, it's pretty much all just memory addresses.
Think of a pointer as an object. Not a "pointer to an int". Here is some C++:
struct int_pointer {
int value;
int_pointer(int val) : value(val) {}
int operator*() { return value; }
};
int_pointer x = 5;
I only covered what I need for this explanation. You know what objects are and all that jazz, so this part will make sense: x IS NOT 5. x is an object. Comparing x to 5 is always going to fail. It if the VALUE of that object that is 5. You need to compare THAT.
Likewise, a pointer is NOT its value. Pretend it is an object that CONTAINS 5. You need to get at the value it contains to do anything with it. The language has special semantics for this: the * prefix operator.
It's important to understand this:
int x = 5;
int *y = &x;
printf("y=%x *y=%d :: x=%d &x=%x\n", y, *y, x, &x);
*y = 10;
printf("y=%x *y=%d :: x=%d &x=%x\n", y, *y, x, &x);
x = 20;
printf("y=%x *y=%d :: x=%d &x=%x\n", y, *y, x, &x);
Run this code and look at the values.
Grasping C pointers isn't so much about language knowledge, it's about hardware knowledge.
Offline
by the way: why is everyone always only proposing script languages like python or ruby but never java? does the whole linux/open source community somehow dislike java because of it being owned by Sun? Or is java just as weird as c++?
Offline
I can't speak for others, but I don't like Java because everything HAS to be a class. No elegance of design like Python, where you can chose to use classes when you need them or not when you don't.
And sometimes the Sun thing doesn't help that much.
Those are MY opinions, FWIW.
Last edited by mrunion (2008-11-03 20:37:55)
Matt
"It is very difficult to educate the educated."
Offline
by the way: why is everyone always only proposing script languages like python or ruby but never java? does the whole linux/open source community somehow dislike java because of it being owned by Sun? Or is java just as weird as c++?
Nah, where C++ is weird, Java is just boring and verbose. But like C++, writing Java is way more tedium than anyone should have to put up with.
Offline
Are there any fun, easy reading tutorials out there that don't visually look like they came out of 1992 and read like http://poignantguide.net/ or http://learnyouahaskell.com/?
yes, here is a guide to c programming from howstuffworks.com. it's all very easy to read and has some pictures to help you visualize the variables and pointers as they appear in memory.
Offline
yes, here is a guide to c programming from howstuffworks.com. it's all very easy to read and has some pictures to help you visualize the variables and pointers as they appear in memory.
Offline
Pointers aren't addressed "simply"; if I declare a pointer to int named x I have to use *x to access what x points to, rather than use *x to get x's location, like one does with non-pointer variables where & is used to get an address. It'd be nice if we used &x to get x's value if x wasn't a pointer and *x to get x's value if x was a pointer, rather than use this convoluted scheme.
Pointer syntax is extremely unfortunate. The best part:
char *a; // It's a pointer.
*a; // It's a character. Good move, guys.
Also, I've heard that it's a common misconception that C handles arrays natively. Elsewhere, I've heard that strings are merely arrays of char. I can understand the 2nd, but what do I do with the 1st?
Insofar as C has arrays, C strings are character arrays. C arrays are just a promise that the system won't mess within a certain set of memory addresses. Array syntax is a concise way to calculate and dereference a specific location in memory, relative to an address that you hope is the beginning of some memory you reserved. array[n] = *(array + n), right? Personally, I would have left out the subscript notation entirely. Regardless, any time you choose to use brackets, you can mentally substitute in an explicit addition and dereference there. You're saying, "Give me the number stored at the memory address I have just calculated, which I know by my science holds something I put there intentionally, and not garbage at all."
One more clarification with regard to pointer arithmetic is necessary: when you add 2 to an int*, the resulting address is actually 2*sizeof(int) bytes after your base address. Same for a double*: 2*sizeof(double).
I do understand that if I say printf("%d\n", x[1]) I'm effectively saying x++; printf("%d\n", x), but I don't understand how this fully works.
It's not the same! First of all, in example #2, you're passing a pointer to an int. In example #1, you're passing an integer, since [] dereferences pointers for you. Any time you use those brackets, it's as if you had typed an asterisk yourself. Second, in example #1 you're not messing with x. In example #2 you're incrementing x by four bytes (the likely size of one integer). Doesn't make a difference in this short example, but if x ever gets used again it will be very significant.
Another thing I found is that declaring a char *, filling it with data, and then using memcpy on said char *, the program works fine, but if I declare for example char x[1] = "hi"; the compiler will shout at me for not allocating enough arrays. Only while writing this did I realize that the 2nd element is for the null byte.
Looks like a counting problem. Arrays are indexed from 0, but sizes are specified from 1 on up. Your "char x[1]" has only index [0]. To hold a two-character string, you'll need at least size three (char x[3]), so that x[0]='h', x[1]='i', x[2]='\0', the null terminator.
Suffice to say that C confuses me. To bits.
Any time you get confused by pointers or arrays (which are the same thing), take a step back and think about what's happening in terms of memory addresses. Draw it out on paper if you think you're making a mistake. In some languages you can ignore low-level details like that and write perfectly fine programs, even though you won't be able to optimize them without knowing how your code maps onto the machine. But in C, everything that looks like a high-level feature is just shorthand for setting a few bytes to different numbers, and the abstraction is so leaky that you can't get by without understanding it. Types are just a way for the compiler to catch dumb mistakes (some people believe this is helpful) and to automate some math, like the pointer arithmetic above. In a running program there are no types, so when you're trying to figure out what a program is actually doing, you need to consider what the types are shorthand for.
If you're having trouble "thinking like a programmer", by which I mean sanity-checking your use of syntax and stepping through a program so you know what it does, you might want to get up to speed in a different language, or by working through a book on algorithms.
Last edited by pauldonnelly (2008-11-03 22:54:12)
Offline
e_tank wrote:yes, here is a guide to c programming from howstuffworks.com. it's all very easy to read and has some pictures to help you visualize the variables and pointers as they appear in memory.
i don't care what that page says i still think it's a good resource as a _short_ _simple_ _introduction_ to c and its basic concepts. i haven't read every page of the thing myself as i found it for my brother to read when i taught him c a few years back, but i can tell you it helped him tremendously. he was struggling, i'm not a very good teacher, he read that and was able to understand many of the basic concepts of c almost immediately (including pointers). even if it isn't 100% correct (they don't point out what's wrong with it) or not technical enough doesn't mean it can't be useful.
Offline
there's no strings in C.
let me repeat that. there's no strings in C.
there is merely a convention that says that any region of memory happening to contain a sequence of chars ending with a \0 is treated a special way by some functions.
this makes "abc" an interesting thing, because it's not a string either. it's a constant. a freaking sequence of bytes hardcoded into the program, and if you do x="abc" then x[1]='d' then it goes boom.
the only thing to get C right is to get that you just manipulate bytes in memory in a more convenient and (somehow) hardware independent manner than with asm.
and so you get nice shorthands and notations like arrays and structs and strstr but this is all the same in the end. think bytes in memory.
To know recursion, you must first know recursion.
Offline
there's no strings in C.
let me repeat that. there's no strings in C.there is merely a convention that says that any region of memory happening to contain a sequence of chars ending with a \0 is treated a special way by some functions.
this makes "abc" an interesting thing, because it's not a string either. it's a constant. a freaking sequence of bytes hardcoded into the program, and if you do x="abc" then x[1]='d' then it goes boom.
the only thing to get C right is to get that you just manipulate bytes in memory in a more convenient and (somehow) hardware independent manner than with asm.
and so you get nice shorthands and notations like arrays and structs and strstr but this is all the same in the end. think bytes in memory.
You just posted almost exactly what I wanted to write, in response to pauldonnelly.
pauldonnelly: in as much as "int *foo" is a pointer to one int, so is "char *bar" a pointer to one char. As I said before, and I will bold it this time:
Understanding pointers is NOT about understanding the semantics of a given language. It is about understanding hardware and computer memory in general
There is a reason people go to school for these things.
Offline
Wow, thanks for the response guys. This will be interesting to read over again and again.
Just one thing:
pauldonnelly: in as much as "int *foo" is a pointer to one int, so is "char *bar" a pointer to one char. ...
So
char *abc = "hi";
allocates 3 consecutive pointers to chars, right after the other?
o.o
-dav7
Windows was made for looking at success from a distance through a wall of oversimplicity. Linux removes the wall, so you can just walk up to success and make it your own.
--
Reinventing the wheel is fun. You get to redefine pi.
Offline
Wow, thanks for the response guys. This will be interesting to read over again and again.
Just one thing:
phrakture wrote:pauldonnelly: in as much as "int *foo" is a pointer to one int, so is "char *bar" a pointer to one char. ...
So
char *abc = "hi";
allocates 3 consecutive pointers to chars, right after the other?
o.o
-dav7
Yep, since we now know the memory location of the first character of the string and it's also terminated by a '\0' null character so we know where it ends.
ARCH64 | XMonad | Configs | myAURpkgs | ArchWiki Contribs | Screenies
Offline
Not quite.
It allocates 1 pointer (named abc) and sets it to point to the first char of "hi". In memory it looks something like this:
['h']['i']['\0'] = region in memory containing 3 chars.
/\
|
abc
Keep in mind that strings like this are hardcoded and are unmodifiable. abc[1] = 'x' will segfault. If you want to modify it you have to copy it somewere else.
Last edited by Adams (2008-11-04 10:38:30)
"The bureaucracy is expanding to meet the needs of an expanding bureaucracy"
Offline
I see. Thanks for that.
So *hello = "hello world" is NOT 11 single pointers to single chars, it's one pointer to 11 chars?
-dav7
Windows was made for looking at success from a distance through a wall of oversimplicity. Linux removes the wall, so you can just walk up to success and make it your own.
--
Reinventing the wheel is fun. You get to redefine pi.
Offline
I see. Thanks for that.
So *hello = "hello world" is NOT 11 single pointers to single chars, it's one pointer to 11 chars?
-dav7
Yeah, the pointer you make just points to the first char and the C string is just a 1D array.
ARCH64 | XMonad | Configs | myAURpkgs | ArchWiki Contribs | Screenies
Offline