Pointers...What good are they?
Author |
Message |
atalat.. #1 / 20
|
 Pointers...What good are they?
Well fellow programmers, there is a new one among you. I have been studying C for about a month now, and pointers puzzle me. I can never get passed the use of pointers, no matter how much I read over them. I have even posted different pointer questions on other groups, but everyone seems to type something from a book. If possible, I'd like a "translation" of what books/online tutorials have to say. Here is an example (though it's not great): #include <stido.h> /* Die stuct, die! */ struct rec { int i; float f; char c; Quote: };
void main() { struct rec *p p=(struct rec*) malloc(sizeof(struct rec)); /* I know it somehow asigns values * but I am quit puzzled */ (*p).i=10; /* or p->i=10 */ (*p).f=3.14; /* or p->i=10 */ (*p).c='a'; /* or p->i=10 */ /* Prints the values it just assigned * but why so many pointers? */ printf("%d %f %c\n",(*p).i,(*p).f,(*p).c); /* Yeah, yeah...deallocate and stuff... free(p); Quote: }
That example is a bit advanced for me, so here is another one. #include <stdio.h> void main() { int *p; /* our good friend the pointer =) */ p=(int *) malloc(sizeof(int)); /* I know "p is generic" * but I need the reason for */ the (int *) in english. *p=10 /* And then all this */ printf("%d\n",*p); /* croc that means */ free(p) /* nothing to me */ /* knowing what the */ /* heck a pointer is */ Quote: }
Thank for your time (and patience) and I hope that you can help me out!
--
|
Tue, 05 Feb 2002 03:00:00 GMT |
|
 |
B. v Ingen Schen #2 / 20
|
 Pointers...What good are they?
Quote:
>Well fellow programmers, there is a new one among you. I have been >studying C for about a month now, and pointers puzzle me. I can never get >passed the use of pointers, no matter how much I read over them. I have >even posted different pointer questions on other groups, but everyone >seems to type something from a book. If possible, I'd like a >"translation" of what books/online tutorials have to say. Here is an >example (though it's not great):
To put it very simple: a pointer is a variable that literally points to some block of memory. Simpler than that I can't make it.
<snip - example with struct> Quote: >That example is a bit advanced for me, so here is another one. >#include <stdio.h> >void main() >{ > int *p; /* our good friend the pointer =) */ > p=(int *) malloc(sizeof(int)); /* I know "p is generic" > * but I need the reason for > */ the (int *) in english. > *p=10 /* And then all this */
The asteriks (*) before the pointer is an indication you want to work with the memory the pointer is pointing to, not the pointer itself. Think of '*p' as a new variable you introduced with the call to malloc. Quote: > printf("%d\n",*p); /* croc that means */ The same here. > free(p) /* nothing to me */
Here you don't have the *, bacause free wants to have a variable that points somewhere. Quote: > /* knowing what the */ > /* heck a pointer is */ >} >Thank for your time (and patience) and I hope that you can help me out!
I hope I have been of assistance Quote: Bart v Ingen Schenau --
|
Tue, 05 Feb 2002 03:00:00 GMT |
|
 |
Peter Seeba #3 / 20
|
 Pointers...What good are they?
Quote:
>Well fellow programmers, there is a new one among you. I have been >studying C for about a month now, and pointers puzzle me. I can never get >passed the use of pointers, no matter how much I read over them.
They're tricky. It really sounds to me like your problem isn't any specific technical question, but rather, that pointers Just Don't Make Sense To You. Quote: >struct rec >{ > int i; > float f; > char c; >}; >void main()
Hmph. main() should return int; your book is weak. Quote: > struct rec *p
Okay. Here's the idea. Imagine that you have a bunch of pieces of paper. You have, here, a piece of paper labeled "p". p is a piece of paper that is special, because all it holds is a description of another piece of paper. Quote: > p=(struct rec*) malloc(sizeof(struct rec));
You call your friend "malloc", and say "sizeof struct rec", and he says "here's a piece of paper big enough to write the contents of a struct rec". You put that piece of paper on your desk, in the upper left-hand corner. On "p", you write "the piece of paper in the upper left-hand corner of my desk". Quote: > /* I know it somehow asigns values > * but I am quit puzzled > */ > (*p).i=10; /* or p->i=10 */
Okay, here's what happens. You look at "p", and it says "the piece of paper in the upper left-hand corner of my desk". "*p" means "the paper described by p", so you go look at the piece of paper in the upper left-hand corner of your desk. On that piece of paper is a little form that looks like i ________ f ________ c ________ so, in the field "i", you write "10". Quote: > (*p).f=3.14; /* or p->i=10 */
Same thing, except this time, in the filed "f", you write "3.14". Quote: > (*p).c='a'; /* or p->i=10 */
And now, in "c", you write 'a'. Quote: > /* Prints the values it just assigned > * but why so many pointers? > */ > printf("%d %f %c\n",(*p).i,(*p).f,(*p).c);
Now, you do the same thing, but you're reading the fields from the piece of paper, and you hand them to printf. Quote: >#include <stdio.h> >void main() >{ > int *p; /* our good friend the pointer =) */
Yup. "p" is now a blank piece of paper. Quote: > p=(int *) malloc(sizeof(int)); /* I know "p is generic" > * but I need the reason for > */ the (int *) in english.
It's not really strictly necessary in C. We'll have to get a bit more advanced. Imagine that there are different kinds of paper, and "p" says, not just which piece of paper you're looking for, but what kind of paper it is. This is used to catch errors; if you try to store the location of a different kind of paper, you get a warning. The function "malloc" returns a description of "any old piece of paper", so you don't really need the cast, but you would in C++. Don't worry about it. :) So, what really happened is, malloc gave you a piece of paper labeled integer _________ and you took the description of where that paper is, and wrote it on "p". Quote: > *p=10 /* And then all this */
This says "find the piece of paper p describes, and write 10 on it". Quote: > printf("%d\n",*p); /* croc that means */
This means "find the piece of paper that p describes, read the number from it, and print it". Quote: > free(p) /* nothing to me */ > /* knowing what the */ > /* heck a pointer is */
This says "throw away the piece of paper that p describes". Quote: >Thank for your time (and patience) and I hope that you can help me out!
Well, we'll certainly try. I'm quite the master of awful analogies. -s --
C/Unix wizard, Pro-commerce radical, Spam fighter. Boycott Spamazon! Will work for interesting hardware. http://www.plethora.net/~seebs/ Visit my new ISP <URL:http://www.plethora.net/> --- More Net, Less Spam! --
|
Tue, 05 Feb 2002 03:00:00 GMT |
|
 |
Tommy Knowlto #4 / 20
|
 Pointers...What good are they?
Quote:
> Well fellow programmers, there is a new one among you. I have been > studying C for about a month now, and pointers puzzle me. I can never get > passed the use of pointers, no matter how much I read over them. I have > even posted different pointer questions on other groups, but everyone > seems to type something from a book. If possible, I'd like a > "translation" of what books/online tutorials have to say. Here is an > example (though it's not great): > #include <stido.h> > /* Die stuct, die! */ > struct rec > { > int i; > float f; > char c; > }; > void main() > { > struct rec *p
p is declared to hold a value, which is the memory address of the beginning of a region having the size and structure of a "rec" Quote: > p=(struct rec*) malloc(sizeof(struct rec));
p is assigned the value returned from malloc (which, because it is used to allocate storage for all kinds of things, the actual type of which isn't known when malloc is written, it is declared to return a value of type "void *" or in other words, a generic pointer. The cast to (struct rec*) is used primarily for self-documentation, so that the human reader knows that the type of the thing on the right of the assignment is "address of a rec structure" or "pointer to rec"). malloc() just takes a size (in bytes), and returns a generic pointer to a region in memory that is large enough to hold that many bytes. Quote: > /* I know it somehow asigns values > * but I am quit puzzled > */ > (*p).i=10; /* or p->i=10 */
first, the two forms are equivalent. x->y is just syntactic sugar for (*x).y since p is a pointer to a rec structure, you want some way to get at the members of the structure. If there were a statically-allocated instance of this structure, call it sr, declared as follows: struct rec sr; then, in order to get at the members, you use the member access operator, "." But p is a pointer to rec, not a rec. The way to get the "thing pointed to" by p, use the dereference operator on the reference (another word for pointer) variable. So, (*p) is just the thing pointed to by p, and (*p).i is just the "i member of the thing pointed to by p" I hope I'm not being too pedantic, I'm not trying to insult anyone, but just help. Quote: > (*p).f=3.14; /* or p->i=10 */ > (*p).c='a'; /* or p->i=10 */ > /* Prints the values it just assigned > * but why so many pointers? > */ > printf("%d %f %c\n",(*p).i,(*p).f,(*p).c);
the first %d field in the format specifier argument to printf wants an additional argument of integral type. Well, that's what "i member of thing pointed to by p" is. Likewise for "f member..." being a float, and "c member..." being a char. Quote: > /* Yeah, yeah...deallocate and stuff... > free(p); > } > That example is a bit advanced for me, so here is another one. > #include <stdio.h> > void main() > { > int *p; /* our good friend the pointer =) */
p is just a number, representing a memory location that holds an integer. Quote: > p=(int *) malloc(sizeof(int)); /* I know "p is generic" > * but I need the reason for > */ the (int *) in english.
again, it's not useful to the compiler, just to the human reading the code. It basically says, the type of the thing on the right hand side will be "address of an integer-sized chunk of memory". Since that agrees with the type of the thing on the left-hand side, everything is good. I believe ANSI actually requires the cast, but even so, it is only enforcing good style, it does nothing to help code-generation, since (on every computer I've ever worked on) pointers are all the same size, regardless of what they're pointing to. So, it's just a formality, but it is good programming practice, and is required for static type-checking. Again, the issue is, the malloc() function is declared as follows: void *malloc(size_t); Which means it takes an argument of type size_t (usually that translates to "unsigned" after preprocessing), and returns a pointer to (the address of) a chunk of memory reserved of that size. In order to store that value into a pointer declared for ints, you "cast" the return value, which just changes its effective type at compile-time. Quote: > *p=10 /* And then all this */
the integer value 10 is stored to the address in p, or alternative way of thinking about it is, thing pointed to by p has its value changed to 10. Quote: > printf("%d\n",*p); /* croc that means */
%d format specifier wants an integer type argument. "thing pointed to by p" is indeed an integer. (In fact, it's 10 at this point in the program). Quote: > free(p) /* nothing to me */
free() does the opposite of malloc(): basically, it gives the space back to the runtime system, to use for some new purpose. It "gives up" (or frees) the memory reserved by the previous call to malloc(). Quote: > /* knowing what the */ > /* heck a pointer is */ > } > Thank for your time (and patience) and I hope that you can help me out!
I hope that I have been able to help. Quote: --Tommy. --
|
Tue, 05 Feb 2002 03:00:00 GMT |
|
 |
Scott J. Tringal #5 / 20
|
 Pointers...What good are they?
Quote:
> Well fellow programmers, there is a new one among you. I have been > studying C for about a month now, and pointers puzzle me. I can never get > passed the use of pointers, no matter how much I read over them. I have > even posted different pointer questions on other groups, but everyone > seems to type something from a book. If possible, I'd like a > "translation" of what books/online tutorials have to say. Here is an > example (though it's not great):
You've got the technique, but the question seems to be "Why bother with pointers? Why not just use regular old variables? It's just more compilcated and looks uglier." The answer is, sometimes you need a "variable" variable. It lets you access *another* variable, by making a decision at run time. Otherwise, you would only be able to access variables specified at compile time. You need pointers in C frequently to do very important, common things: - simulate pass-by-reference - allocating storage whose size is determined at run time ...among a zillion other things. --
|
Tue, 05 Feb 2002 03:00:00 GMT |
|
 |
Dave Hans #6 / 20
|
 Pointers...What good are they?
Quote:
>Well fellow programmers, there is a new one among you. I have been >studying C for about a month now, and pointers puzzle me. I can never get >passed the use of pointers, no matter how much I read over them. I have
Pointers can be a difficult subject until the light clicks on (and sometimes even after that). They tend to be more important in C than most other languages, which is one reason I recommend beginning programmers learn some other language first. Quote: >even posted different pointer questions on other groups, but everyone >seems to type something from a book. If possible, I'd like a >"translation" of what books/online tutorials have to say. Here is an >example (though it's not great):
[...struct example...] Quote: >That example is a bit advanced for me, so here is another one.
Actually, it might just have been too simple. You did nothing with the pointer that could not have been done without a pointer (other than malloc and free the memory, that is). Lets work a little bit with this second example. A pointer is a variable that "points" to another. Kind of circular. *How* does it point to another? It is itself a variable. It contains the "address" of the variable it points to. You can operate on the pointer the same way you operate on other variables (within limits). To operate on the variable the pointer points to, you have to "dereference" the pointer using * or ->. It's not a particularly good analogy, but think of ptr = address; as writing an address in your little black book, and *ptr = value; as looking that address up, copying it on an envelope, putting "value" in the envelope and mailing it. If we have a (valid, non-NULL) pointer to type "X" we know there is an X out there somewhere that we can work with, and we know where to find it. There may or may not be other ways to get to that same X. Quote: >#include <stdio.h> >void main() >{ > int *p; /* our good friend the pointer =) */
int *p2; /* another pointer */ int q; /* a new friend to play with, not a pointer */ Quote: > p=(int *) malloc(sizeof(int)); /* I know "p is generic" > * but I need the reason for > */ the (int *) in english.
Actually, the cast is not required. I for one would prefer it was not there: it can conceal a bug (i.e. if the prototype for malloc is missing).
p2 = &q; /* p2 now points to q */ Quote: > *p=10 /* And then all this */
This statement sets the int pointed to by p (which you previously malloc'ed) to 10. Or at least it would if the semicolon were there... *p2 = 20; /* sets q to 20 */ Quote: > printf("%d\n",*p); /* croc that means */
The above should print "10" printf("%d, %d\n", q, *p2); should print "20, 20" Now let's have some real fun: p2 = p; printf("%d, %d\n", q, *p2); Although the print statement is the same as it was the last time, it should now print "20, 10" *p2 = 30; printf("%d, %d, %d", q, *p2, *p); should print "20, 30, 30". Quote: > free(p) /* nothing to me */ > /* knowing what the */ > /* heck a pointer is */ >} >Thank for your time (and patience) and I hope that you can help me out!
Hope this helps. -=Dave Just my (10-010) cents I can barely speak for myself, so I certainly can't speak for B-Tree. Change is inevitable. Progress is not. --
|
Tue, 05 Feb 2002 03:00:00 GMT |
|
 |
A. Bolmarci #7 / 20
|
 Pointers...What good are they?
Quote:
>Well fellow programmers, there is a new one among you. I have been >studying C for about a month now, and pointers puzzle me. I can never get >passed the use of pointers, no matter how much I read over them. I have >even posted different pointer questions on other groups, but everyone >seems to type something from a book. If possible, I'd like a >"translation" of what books/online tutorials have to say. Here is an >example (though it's not great):
[snip] First, let me type something from a book: "A pointer is a variable that contains the address of a variable." You use a pointer when you don't know the actual variable that part of the program will use. This typically happens when part of a program needs to operate on different variables at different times when the program runs. Here is a simple example. #include <stdio.h> int main() { int a = 4, b = 9, *p; printf("before a=%d b=%d\n", a, b); p = &a; *p = 0; p = &b; *p = 0; printf("after a=%d, b=%d\n", a, b); } At different times during the program the pointer contained the address of differnet variables. In such a simple program there is no need to use a pointer, you know what variables you want to set to zero. However, a program does not always know the variables that it will use. This is especially true with functions in C. Here is another way to write the above program. #include <stdio.h> static void setToZero(int *p) {*p = 0;} int main() { int a = 4, b = 9; printf("before a=%d b=%d\n", a, b); setToZero(&a); setToZero(&b); printf("after a=%d, b=%d\n", a, b); } The function setToZero works with any variable of type int. The function will be called to operate on different variables at different times when the program runs. A pointer is used because in C function arguments are passed by value. When a function is called, each argument is evaluated and the body of the function uses a copy of that value when it uses the corresponding parameter declared in the function definition. Some other programming languages allow function parameters to be declared in a way such that when the parameter is used in the body of the function, the program uses the variable that was the corresponding argument of the function (rather than a copy of the value of the argument). C does not. Pointers allow parts of a C program to operate on different variables at different times by setting the pointer to the address of the variable to be operated on. --
|
Wed, 06 Feb 2002 03:00:00 GMT |
|
 |
Jerry Coff #8 / 20
|
 Pointers...What good are they?
says... Quote: > Well fellow programmers, there is a new one among you. I have been > studying C for about a month now, and pointers puzzle me. I can never get > passed the use of pointers, no matter how much I read over them.
Okay, let's leave your question alone for the moment, and start with yet another attempt at explaining what pointers are. Since your question dealt with pointers to structures, I'll use something similar as an analogy. Assume for the moment that you want to know the definition of a word, and for some crazy reason you can't just look it up in the dictionary on your own. For the moment, let's also assume that we're using something like the Oxford English Dictionary, where a complete definition can be pretty long. If I wanted to tell you the definition of a word, I could do a couple of different things. One would be for me to copy the whole definition for the word out of the dictionary onto a piece of paper, and give you the piece of paper. Unfortunately, if the definition is big, this is going to take me a while, and will probably also require more paper than I want to use. Therefore, to make my life a bit simpler, I might just copy down something like "the 10th word on page 1027". This way, I don't have to make a copy of the definition. Instead, I've simply given you some directions to be able to find the original definition yourself. A pointer is almost exactly like that piece of paper I'd hand you -- it doesn't contain the value (definition) itself; it just tells you where you can find the original value. When you've been given a pointer, and go to look up the value it points to, you "dereference" the pointer, using the "*" operator. The basic dereferencing operator, however, assumes something similar to you receiving ONLY a page number in the dictionary, with no number of a word on that page. If you happen to use a dictionary that has only one definition per page, that's perfectly fine. That's pretty similar to having, say, an array of int's -- each int is (more or less) a thing by itself, and you can use the dereferencing operator to get to the correct int. Our dictionary is more like a struct in C though: when you get to a particular page, it's got a number of definitions on it. Once you get to the right page, you also have to find the right word. A struct is pretty much the same way -- if you have a pointer to a struct, you don't just want the beginning of the struct, but you also want to pick out a particular part of the struct. You can do that by using the normal dereferencing operator to "pick the right page", then separately look for the right word on the page. Since this happens quite a bit, C provides us with a way of combining the two operations: we can tell it both the struct we want, AND the member of the struct we want, and it'll look figure out both at once. This is where the "- Quote: >" operator comes in -- we put the pointer to the struct on its left,
and the member of the struct on its right, and it allows us to do whatever we want with that member of that struct. There are two main reasons for using pointers in C: one (analogous with the example of the dictionary definition above) is that a pointer is typically smaller and quicker to pass around than whatever it points at. Much like with definitions, you might occasionally see one that's not much larger than the page number, and some kinds of variables aren't much slower to copy/pass than pointers. OTOH, pointers are pretty dependably at least reasonably small and fast, while the things they point at can vary quite widely. The other reason shouldn't (usually) be very applicable to dictionaries, but it's still easy to describe in that context. When you want to change a value of a variable, you often need a pointer to be able to do so. If I wanted to say that (for example) there was an error in the definition of a word, I could pass you a copy of the definition, and you could change the definition on that piece of paper. You'd then have to do something like return the piece of paper to me, and I could write the new definition into the dictionary. If, however, I don't tell you what dictionary we're modifying, you probably can't go in an make the change yourself. OTOH, if I wanted you to make the change yourself, I could give you the pointer to the right place, and by looking there (again, using the dereferencing operator) you could write the new definition yourself. C is VERY much the same way: if I want you to modify a variable, I can pass you a copy of the variable, in which case you usually have to do something like return a new value, which I can then use to overwrite the old one. If I want you to change a variable directly, I can pass you a pointer, and by overwriting what the pointer points at, you can modify the original variable directly. Hopefully, that gives a more understandable idea of how pointers work, and when and why you use them. Once you figure out the basic idea of pointers, understanding how C uses them (for example) is mostly a matter of getting used to the particular symbols it uses to represent the operations involved. --
|
Wed, 06 Feb 2002 03:00:00 GMT |
|
 |
Tom Tor #9 / 20
|
 Pointers...What good are they?
Quote:
>{ > int *p; /* our good friend the pointer =) */
PS> Yup. "p" is now a blank piece of paper. Mmh, I think p is now an indeterminate piece of paper. Use static or an explicit initializer to make it blank :-) greetings, Tom
--
|
Wed, 06 Feb 2002 03:00:00 GMT |
|
 |
Peter Seeba #10 / 20
|
 Pointers...What good are they?
Quote:
>>{ >> int *p; /* our good friend the pointer =) */ > PS> Yup. "p" is now a blank piece of paper. >Mmh, I think p is now an indeterminate piece of paper. Use static or an >explicit initializer to make it blank :-)
Ahh, not so! p is a blank piece of paper. It is unclear what should happen if you say "find the paper p refers to". By contrast, if you initialize it, you might end up with a piece of paper saying "mu", which would make more sense. -s --
C/Unix wizard, Pro-commerce radical, Spam fighter. Boycott Spamazon! Will work for interesting hardware. http://www.plethora.net/~seebs/ Visit my new ISP <URL:http://www.plethora.net/> --- More Net, Less Spam! --
|
Wed, 06 Feb 2002 03:00:00 GMT |
|
 |
Mathew Hend #11 / 20
|
 Pointers...What good are they?
Quote:
>>{ >> int *p; /* our good friend the pointer =) */ > PS> Yup. "p" is now a blank piece of paper. >Mmh, I think p is now an indeterminate piece of paper.
It's not indeterminate, but you may have nasal problems if you look at it before writing anything on it. -- Mat. --
|
Thu, 07 Feb 2002 03:00:00 GMT |
|
 |
Tom Tor #12 / 20
|
 Pointers...What good are they?
Quote:
>>{ >> int *p; /* our good friend the pointer =) */ > PS> Yup. "p" is now a blank piece of paper. >Mmh, I think p is now an indeterminate piece of paper. Use static or an >explicit initializer to make it blank :-)
PS> Ahh, not so! PS> p is a blank piece of paper. It is unclear what should happen if PS> you say "find the paper p refers to". No, that would be the case if it were implicitly (by making it static) or explicitly initialized to NULL. In this case, however, the value of p itself is indeterminate, so it is undefined behaviour to read from p, let alone what it refers to. (I suspect the analogy is now thinking "I didn't mean to be taken so seriously") greetings, Tom
--
|
Thu, 07 Feb 2002 03:00:00 GMT |
|
 |
Tom Tor #13 / 20
|
 Pointers...What good are they?
Quote:
>>{ >> int *p; /* our good friend the pointer =) */ > PS> Yup. "p" is now a blank piece of paper. >Mmh, I think p is now an indeterminate piece of paper.
MH> It's not indeterminate, but you may have nasal problems if you look MH> at it before writing anything on it. It's not ? In what way do I mis-read the below paragraph then ? 3.5.7 Initialization <snip> If an object that has automatic storage duration is not initialized explicitly, its value is indeterminate. greetings, Tom
--
|
Thu, 07 Feb 2002 03:00:00 GMT |
|
 |
Peter Seeba #14 / 20
|
 Pointers...What good are they?
Quote:
>>>{ >>> int *p; /* our good friend the pointer =) */ >> PS> Yup. "p" is now a blank piece of paper. >>Mmh, I think p is now an indeterminate piece of paper. Use static or an >>explicit initializer to make it blank :-) > PS> Ahh, not so! > PS> p is a blank piece of paper. It is unclear what should happen if > PS> you say "find the paper p refers to". >No, that would be the case if it were implicitly (by making it static) or >explicitly initialized to NULL. In this case, however, the value of p >itself is indeterminate, so it is undefined behaviour to read from p, let >alone what it refers to.
It's an implementation-defined thing. I agree, I said that wrong. If a piece of paper is blank, it is undefined behavior to even ask the question "what is written on this piece of paper". That's not indeterminate, but it is the way I chose to implement "indeterminately valued". When you initialize p to a null pointer, the paper stops being blank, and starts saying "I refer to no paper". Quote: >(I suspect the analogy is now thinking "I didn't mean to be taken so >seriously")
Poor defenseless little analogy. -s --
C/Unix wizard, Pro-commerce radical, Spam fighter. Boycott Spamazon! Will work for interesting hardware. http://www.plethora.net/~seebs/ Visit my new ISP <URL:http://www.plethora.net/> --- More Net, Less Spam! --
|
Fri, 08 Feb 2002 03:00:00 GMT |
|
 |
Chris Tore #15 / 20
|
 Pointers...What good are they?
The thread with the above "subject" line got placed adjacent to the ongoing one about pronouns, which made me realize that, in a way, pointers are somewhat like pronouns. "Pronouns ... what good are they?" Suppose we did not have pronouns. Instead of saying "me", "you", "him", "her", and the like, suppose we had to use nouns all the time. One might say to Jack: "Jane took Jane's car to Bob's Auto Service. Bob needs to keep Jane's car overnight. Jack should go pick Jane up at 4 PM." (Think of old Tarzan movies or something. :-) ) This would *work*, but I think people would find it awkward (cf. the "more natural" phrasing, "Jane took her car to Bob's Auto Service. He needs to keep her car overnight. You should go pick her up at 4 PM."). Instead of naming something explicitly over and over again, we have "short forms" by which we can name something conveniently. In addition, this allows us to use pronouns "generically", such as "you", addressed to the reader. "You" are reading this right now, no matter whether your name is Jack, Jane, Bob, or something else entirely. The pronoun "you" magically refers to the correct person, regardless of your name. Similarly, consider a procedure like strtol(): long strtol(const char *nptr, char **endptr, int base); The sequence-of-characters we want to convert might be in buf[0] through buf[3]: char buf[BUFSIZ]; long l; char *ep; ... if (fgets(buf, sizeof buf, stdin) == NULL) errexit("end of file, quitting"); l = strtol(&buf[0], &ep, 0); Inside strtol(), the pointer "nptr" refers to &buf[0]. We could try to write a different strtol() without using "nptr", but then we would have to name "buf[0]" explicitly inside our replacement: long alt_strtol(void) { extern char buf[BUFSIZ]; int first_digit, second_digit, third_digit, fourth_digit; ... first_digit = buf[0] - '0'; second_digit = buf[1] - '0'; third_digit = buf[2] - '0'; fourth_digit = buf[3] - '0'; ... } If a second number we want to convert happens to be in buf[9] through buf[12], this alt_strtol() is useless. (We could write an "alt2_strtol", but this way lies madness, or at least Microsoft-sized code.) Similarly, "endptr" inside strtol winds up referring to the variable "ep". Here "ep" itself is a pointer, so "endptr = &ep" -- this assignment effectively happens at the time of the call to strtol() -- sets up a pointer to a pointer. Just as a pronoun is also a word, a pointer is also an ordinary object; and just as a pronoun can stand in for some other word, a pointer can stand in for some other object; so a pointer can stand in for another pointer. To follow a pointer, you simply use the unary "*" operator: this_digit = *nptr - '0'; is more or less equivalent to: this_digit = buf[0] - '0'; because nptr refers to (points to) buf[0]. Ultimately, each pointer had better stand in for *some* object, before you try to use that particular object. Any uninitalized automatic variable (more or less, "one local to a set of {}s") contains garbage, and this is true of pointers as well. So if you declare a pointer of your own (such as "ep" above), you will have to set it before you try to follow it to where it points. The language reserves one particular value -- the "null pointer" -- to be used as a valid value that explicitly points to *no* object. This is very much *un*like the normal use of pronouns; "you" refers to a real person, but the pointer "endptr" can be set to NULL. The strtol() function checks "endptr != NULL" before trying to use the object for which "endptr" might stand: long strtol(const char *nptr, char **endptr, int base) { ... if (endptr != NULL) *endptr = some_valid_value; return (value); } That means that after the call to strtol(), "ep" -- the thing to which "endptr" pointed while strtol() was doing its work -- will have been written with some valid value. The actual definition of strtol() says that it will locate a digit sequence, convert it, and set *endptr to the first "invalid" (non-digit) character in the buffer. Thus, we can write a function like this: void simple_arithmetic(void) { char buf[BUFSIZ]; long n1, n2; char *ep1, *ep2; if (fgets(buf, sizeof buf, stdin) == NULL) errexit("end of file, quitting"); /* group 1 (see note below) */ n1 = strtol(&buf[0], &ep1, 0); if (ep1 == buf) errexit( "missing <number1> -- expected <number1> + <number2> or <number1> - <number2>"); while (isspace(*ep1)) ep1++; operator = *ep1++; if (operator != '+' && operator != '-') errexit("missing/invalid operator -- expected + or -"); /* group 2 (see note below) */ n2 = strtol(ep1, &ep2, 0); if (ep1 == ep2) errexit( "missing <number2> -- expected <number1> + <number2> or <number1> - <number2>"); while (isspace(*ep2)) ep2++; if (*ep2 != '\0') warn("junk after expression"); if (operator == '+') printf("%d + %d = %d\n", n1, n2, n1 + n2); else printf("%d - %d = %d\n", n1, n2, n1 - n2); Quote: }
(proper include files, support functions -- including main -- and testing of this code left as an exercise to the reader :-) ). Note: As a more interesting exercise, once you have written the support functions and gotten this working, try writing a routine that handles the sequence "do a strtol, and errexit() if no number was supplied; then skip over trailing whitespace", which appears twice in simple_arithmetic() above. This will simplify the two marked groups of code. What parameters will you need inside this "get_number" routine? -- In-Real-Life: Chris Torek, Berkeley Software Design Inc
--
|
Fri, 08 Feb 2002 03:00:00 GMT |
|
|
Page 1 of 2
|
[ 20 post ] |
|
Go to page:
[1]
[2] |
|