kaires@hubcap.clemson.edu (Robert G Kaires) (02/25/90)
Dear C users: Thanks to all who answered my question entitled "A very elementary question concerning indirection". Your answers were most helpful (and plentiful). Sorry I could answer each response individually. This next question is maybe not so elementary (hence I left off the "very"). I am trying to write a code fragment which gets a floating point number from the user and checks to see if it contains any illegal characters. The atof() function can change the input string to a floating point number and stops converting at the first illegal character. Searching through my Turbo C manual (2.0), I find the function strtod() which seems to be better suited for my purpose. This function not only stops at the first illegal character but also returns a pointer (or is it a pointer to a pointer?). I don't really understand why this function has the syntax: double strtod(const char *s, char **endptr); Why is endptr a pointer to a pointer (and not just a pointer)? Unfortunately the description of double indirection is poorly explained in my manuals, and no description of how to use this function is given. However, I plunged ahead and tried to use it anyway. Here is my short program: #include <math.h> #include <stdio.h> #include <string.h> #include <stdlib.h> main() { char string[30]={""}; char **ptr; double ans; clrscr(); while(1) { gets(string); if (*string == 'q') break; ans=strtod(string,ptr); if ( ( string+strlen(string) ) != *ptr ) /* <--- warning here */ printf("format error\n"); else printf("You typed the number: %f\n",ans); } } This program seems to work OK (try it). However I do get warnings on the line indicated that "I am trying to use ptr before it is defined". Even worst, when I use this fragment in a much larger program, all hell breaks loose. It seems that I am writing over sections of memory that belong to other varaiables. Please tell me what is wrong (without too much scolding PLEASE, I am still a beginner). Thanks one and all. Bob Kaires
john@stat.tamu.edu (John S. Price) (02/25/90)
In article <8146@hubcap.clemson.edu> kaires@hubcap.clemson.edu (Robert G Kaires) writes: >Dear C users: > >[...stuff deleted...] >why this function has the syntax: > double strtod(const char *s, char **endptr); > >Why is endptr a pointer to a pointer (and not just a pointer)? The reason is this: you send this function the address of a character pointer, and it changes the pointer to point to the place in the string where the error occurs. For example: ... char *error, *string = "10.2#4"; /* or whatever you like */ double num; num = strtod(string, &error); ... Pass the address of the pointer that you want to point to the error. That's is why it's declared as a char **. You have a character pointer, and you are taking the address, thus a pointer to a character pointer, which is a char **. >Unfortunately the description of double indirection is poorly explained >in my manuals, and no description of how to use this function is given. There is nothing special about double indirection, although I have to admit that I was a little confused when I first started working with it. Just think of it this way. When you apply the indirection operator (*foo), you are looking at what "foo" points to. This can be any valid data type, that being an integer, float, structure, or pointer. If it's a pointer, well, you dereference it again to get what it's pointing to. It's actually quite simple once you catch on to it. I've had programs where I've had up to 5 levels of indirection, something like a pointer to an array of pointers to functions returning a pointer to a structure, or something like that. >However, I plunged ahead and tried to use it anyway. Here is my short >program: > >#include <math.h> >#include <stdio.h> >#include <string.h> >#include <stdlib.h> > >main() >{ >char string[30]={""}; >char **ptr; >double ans; >clrscr(); >while(1) > { > gets(string); > if (*string == 'q') break; > ans=strtod(string,ptr); > if ( ( string+strlen(string) ) != *ptr ) /* <--- warning here */ > printf("format error\n"); > else > printf("You typed the number: %f\n",ans); > } >} Just change the "char **ptr" to a "char *ptr", and change the call to strtod(string, ptr) to strtod(string,&ptr). That SHOULD work, although I haven't tested it. Hope that made sense, and helps any. >Bob Kaires -------------------------------------------------------------------------- John Price | It infuriates me to be wrong john@stat.tamu.edu | when I know I'm right.... --------------------------------------------------------------------------
raw@math.arizona.edu (Rich Walters) (02/27/90)
In article <8146@hubcap.clemson.edu> kaires@hubcap.clemson.edu (Robert G Kaires) writes: > this function has the syntax: > double strtod(const char *s, char **endptr); > >Why is endptr a pointer to a pointer (and not just a pointer)? >Unfortunately the description of double indirection is poorly explained >in my manuals, and no description of how to use this function is given. >However, I plunged ahead and tried to use it anyway. Here is my short >program: > >char string[30]={""}; >char **ptr; >double ans; > >while(1) > { > gets(string); > if (*string == 'q') break; > ans=strtod(string,ptr); > if ( ( string+strlen(string) ) != *ptr ) /* <--- warning here */ > printf("format error\n"); > else > printf("You typed the number: %f\n",ans); > } >} >This program seems to work OK (try it). However I do get warnings on the >line indicated that "I am trying to use ptr before it is defined". Even >worst, when I use this fragment in a much larger program, all hell >breaks loose. It seems that I am writing over sections of memory that >belong to other varaiables. Please tell me what is wrong. The reason you get the warning is obvious. ptr has not been (explicity) assigned a value. You will get this warning whenever a variable is initialized in a standard function. A better way might be #include <stdio.h> /* other appropriate includes */ main() { char string[30]; char *ptr; double ans; extern double strtod(); while(1) { gets(string); if (*string == 'q') break; ans=strtod(string,&ptr); if ( ( string+strlen(string) ) != ptr ) /* <--- warning here */ printf("format error\n"); else printf("You typed the number: %f\n",ans); } } This works. strtod wants to modify ptr to point to the correct place. thus you must send it the address of (a pointer to) the pointer that is to point to the terminating character. On my machine if I send it 12.34abcde, ptr points to the 'b'. I'm not sure why. Richard Walter ------------------------------------------------------------------------------- Keep on crunching those numbers -------------------------------------------------------------------------------
martin@mwtech.UUCP (Martin Weitzel) (02/28/90)
In article <8146@hubcap.clemson.edu> kaires@hubcap.clemson.edu (Robert G Kaires) writes: > this function has the syntax: > double strtod(const char *s, char **endptr); > >Why is endptr a pointer to a pointer (and not just a pointer)? >Unfortunately the description of double indirection is poorly explained >in my manuals, and no description of how to use this function is given. Yes, this is a constant source of trouble for novice C programmers. ******************************************************** NOTE: ** If you find a double pointer as formal argument ** ** in the description of some library function, this ** ** often means you have to supply the ADRESS of a ** ** (single) pointer variable! Furthermore pointers ** ** to C-struct-s as formal arguments often means you ** ** have to supply the adress of a struct-variable. ** ** Furthermore pointers to char (char *) often means, ** ** that an "array of char" (char foo[SIZE]) would be ** ** appropriate, when the function is called (%). ** ******************************************************** Please, do NOT take the above as general rule (eg there may well be situations where a double pointer formal argument needs a double pointer as actual parameter a.s.o.), but as a "warning light" which is switched on in your brains, if you read the manual! (%): If the library function *writes* to the location, the pointer points to, make sure "SIZE" is sufficient (and don't forget the terminating '\0'-Byte!). [the correct answer for the presented problem was allready given by another poster, I'll delete it] -- Martin Weitzel, email: martin@mwtech.UUCP, voice: 49-(0)6151-6 56 83