Help explain char * and char [] differences
Author |
Message |
Aaron See #1 / 15
|
 Help explain char * and char [] differences
I came across an interesting function strtok() which i find will be very useful in parsing config files in my mini-game (yes, I'm that inexperienced). using the given example I wrote a simple test prog to check out the function : int main() { const char delimiters[] = "[]"; char *teststr = "[1]"; /***** notice this declaration *****/ char *token; printf("%s\n", delimiters); printf("%s\n", teststr); token = strtok(teststr, delimiters); printf("%s\n", token); token = strtok(NULL, delimiters); printf("%s\n", token); return 1; Quote: }
It gave a core dump. When I looked back at the sample, I found the string to be "stripped" is declared as char [] instead of char *. sure enough changing my declaration to char teststr[] worked. I thought char * is the same as char[]? It's not that I needed preallocated space by putting teststr[512] or something. I looked up the text bk & sure enough char * is more flexible than char [], & strtok() takes in a char * anyway. any comments why only a char [] works here? I also have another query : how do I reset a char * back to the 1st char in the string when I've done ++ operations to the pointer? there's no way, and I'll need a 2nd ptr to point to the head, much like a linked list, right? thanx for the enlightenment, Aaron
|
Fri, 01 Mar 2002 03:00:00 GMT |
|
 |
Alex_K.. #2 / 15
|
 Help explain char * and char [] differences
Quote: > I came across an interesting function strtok() which i find will be very > useful in parsing config files in my mini-game (yes, I'm that > inexperienced). using the given example I wrote a simple test prog to > check out the function : > int main() > { > const char delimiters[] = "[]"; > char *teststr = "[1]"; /***** notice this declaration *****/ > char *token; > printf("%s\n", delimiters); > printf("%s\n", teststr); > token = strtok(teststr, delimiters); > printf("%s\n", token); > token = strtok(NULL, delimiters); > printf("%s\n", token); > return 1; > } > It gave a core dump. When I looked back at the sample, I found the > string to be "stripped" is declared as char [] instead of char *. sure > enough changing my declaration to char teststr[] worked. > I thought char * is the same as char[]?
No, it is not. If your book doesn't explain this, dump the book. In any case, read the FAQ at http://www.eskimo.com/~scs/C-faq/top.html - it is explained there in details. Quote: > It's not that I needed > preallocated space by putting teststr[512] or something.
No, pointer is valid, but it points to a string literal. Quote: > I looked up the > text bk & sure enough char * is more flexible than char [], & strtok() > takes in a char * anyway. any comments why only a char [] works here?
Because: a) strtok() modifies the string being passed to it; b) you are passing to it a pointer to a string literal; and c) trying to modify string literal invokes undefined behaviour - in your specific case, segmentation fault. -- Regards, Alex Krol Disclaimer: I'm not speaking for Scitex Corporation Ltd Sent via Deja.com http://www.deja.com/ Share what you know. Learn what you don't.
|
Fri, 01 Mar 2002 03:00:00 GMT |
|
 |
Manfred Knemeye #3 / 15
|
 Help explain char * and char [] differences
- snip - Yes, char *teststr; and char teststr[]; are different animals. Question: What does the (very simple) expression teststr mean, say when used as an argument value in a function call? That was the source of confusion - but not of the core dump. The name of an array, when appearing alone, is interpreted as the value of a pointer to its first element, just as if you had written &teststr[0]. Note that your first declaration also makes some sense. But the problem here is that the char array it points to is a constant (unmodifiable). And it will be modified by strtok(). That caused the core dump. Luckily, since this is OS dependent.
|
Fri, 01 Mar 2002 03:00:00 GMT |
|
 |
John Bod #4 / 15
|
 Help explain char * and char [] differences
Quote: > I thought char * is the same as char[]? It's not that I needed > preallocated space by putting teststr[512] or something. I looked up the > text bk & sure enough char * is more flexible than char [], & strtok() > takes in a char * anyway. any comments why only a char [] works here?
No, they're not the same. One form declares a modifiable buffer, the other simply sets a pointer to an unmodifiable location. char *p = "hello"; /* p points to a location in unwritable memory */ char q[] = "world"; /* q is a static buffer, 6 chars long, and */ /* "world" is copied into it */ The problem is that strtok() modifies the buffer you are scanning, replacing the delimiters with a '\0' character. Passing a string constant or a pointer to a string constant will cause it to choke. t = strtok ("hello", "l"); /* bad */ t = strtok (p, "l"); /* bad */ t = strtok (q, "l"); /* ok */ Quote: > I also have another query : how do I reset a char * back to the 1st char > in the string when I've done ++ operations to the pointer? there's no > way, and I'll need a 2nd ptr to point to the head, much like a linked > list, right?
Yes. You'll need to preserve the original address somehow. There's one other thing you'll need to watch out for when using strtok(). You can't nest calls -- that is, you can't read one token, then parse it, then try to read from the original string again. Here's an example (error checking omitted for brevity): void get_date_tokens(char *buf, char *delim, char *m, char *d, char *y) { m = strtok (buf, delim); d = strtok (NULL, delim); y = strtok (NULL, delim); Quote: }
void get_time_tokens(char *buf, char *delim, char *h, char *m) { h = strtok (buf, delim); m = strtok (NULL, delim); Quote: }
int main (void) { char date[] = "09/13/1999 09:43"; char *bufd, *buft; char *m, *d, *y, *H, *M; /* ** The following code won't work properly. Calls to ** strtok() cannot be nested. ** After calling get_date_tokens, we will have lost our original ** place in the date buffer. */ bufd = strtok (date, " "); get_date_tokens (bufd, "/", m, d, y); buft = strtok (NULL, " "); get_time_tokens (buft, ":", H, M); /* ** This is the proper way to handle the problem. You fully parse ** the original string first, *then* work on each part of it. */ bufd = strtok (date, " "); buft = strtok (NULL, " "); get_date_tokens (bufd, "/", m, d, y); get_time_tokens (buft, ":", H, M); Quote: } > thanx for the enlightenment, > Aaron
-- Phrases often heard just before a major disaster: "How hard can it be?" "Hey, watch this!" "Don't worry, this time I *know* what I'm doing..." Sent via Deja.com http://www.deja.com/ Share what you know. Learn what you don't.
|
Fri, 01 Mar 2002 03:00:00 GMT |
|
 |
Stephan Wilm #5 / 15
|
 Help explain char * and char [] differences
Aaron Seet schrieb: Quote: > I came across an interesting function strtok() which i find will be very > useful in parsing config files in my mini-game (yes, I'm that > inexperienced). using the given example I wrote a simple test prog to > check out the function : > int main() > { > const char delimiters[] = "[]"; > char *teststr = "[1]"; /***** notice this declaration *****/ > char *token; > printf("%s\n", delimiters); > printf("%s\n", teststr); > token = strtok(teststr, delimiters);
Hi Aaron Seet, As you have noticed yourself (below) the "char *teststr" causes Undefined Behaviour (in the form of a "core dump") in the call to "strtok()". That's because "strtok()" is defined to modify the given source string. But a string literal is read-only, which means that you are not allowed to modify it. Changing the declaration like this: char teststr[] = "[1]"; places (copies) the string literal into a local variable. Quote: > printf("%s\n", token); > token = strtok(NULL, delimiters); > printf("%s\n", token);
The above line is another bug that you have overlooked. The return value of "strtok()" is NULL if no more token were found. Since your test string does not have a valid second token your are passing NULL to "printf()" and that causes Undefined Behaviour. Your specific "printf()" implementation might detect this and handle it in a non destructive way, but you must not depend on this. Quote: > return 1;
And one final portability tip: according to the ANSI-C standard there are only three valid return values for main: 0, EXIT_SUCCESS and EXIT_FAILURE. The later two are defined in <stdlib.h>. Quote: > I thought char * is the same as char[]?
No, it is not. Not by a long run. The first one is a pointer without any space allocated to it and the later is an array of a specific size. Even this line is not identical to a real array: char *test = "some text"; For one thing it sets the pointer to a string literal, which is defined as being read-only. For another "test" is still just a pointer, which has subtle differences to an array. I urge you to read the section 6 of the comp.lang.c FAQ, which explains the differences between "Arrays and Pointers" in a very good and understandable way, including several examples. Quote: > It's not that I needed > preallocated space by putting teststr[512] or something.
Something like: char test[] = "some text"; will give and occupy just the space needed for storing the text and an additional terminating zero byte. For using "strtok()" you must supply modifiable memory. Either by declaring a real array or by dynamically allocating the memory using "malloc()". Quote: > I looked up the > text bk & sure enough char * is more flexible than char [], & strtok() > takes in a char * anyway.
Well, you can have a pointer point to an array, if you want to use pointer arithmetic: char test[] = "some text"; char *p; p = test; The reason why "strtok()" (and any other string processing function) takes a "char*" is explained in the FAQ. Please read that first, it should make things clear. If it does not, feel free to ask here again. Quote: > I also have another query : how do I reset a char * back to the 1st char > in the string when I've done ++ operations to the pointer?
By storing the original pointer separately. If the original is an array you simply reassign the array: p = test; (re)sets "p" to the first element of the array "test". Quote: > there's no > way, and I'll need a 2nd ptr to point to the head, much like a linked > list, right?
Sounds correct. You can get the FAQ at http://www.eskimo.com/~scs/C-faq/top.html or at ftp://rtfm.mit.edu/pub/usenet/comp.lang.c/C-FAQ-list and it gets posted to this newsgroup and to news.answers regularly (at the beginning of each month). Stephan (initiator of the campaign against grumpiness in c.l.c)
|
Fri, 01 Mar 2002 03:00:00 GMT |
|
 |
Paul Lutu #6 / 15
|
 Help explain char * and char [] differences
Quote: > I thought char * is the same as char[]?
No, one is modifiable ([]), the other is not (*). Quote: > I also have another query : how do I reset a char * back to the 1st char > in the string when I've done ++ operations to the pointer?
Simpler to save a copy of the original. -- Paul Lutus www.arachnoid.com
Quote: > I came across an interesting function strtok() which i find will be very > useful in parsing config files in my mini-game (yes, I'm that > inexperienced). using the given example I wrote a simple test prog to > check out the function : > int main() > { > const char delimiters[] = "[]"; > char *teststr = "[1]"; /***** notice this declaration *****/ > char *token; > printf("%s\n", delimiters); > printf("%s\n", teststr); > token = strtok(teststr, delimiters); > printf("%s\n", token); > token = strtok(NULL, delimiters); > printf("%s\n", token); > return 1; > } > It gave a core dump. When I looked back at the sample, I found the > string to be "stripped" is declared as char [] instead of char *. sure > enough changing my declaration to char teststr[] worked. > I thought char * is the same as char[]? It's not that I needed > preallocated space by putting teststr[512] or something. I looked up the > text bk & sure enough char * is more flexible than char [], & strtok() > takes in a char * anyway. any comments why only a char [] works here? > I also have another query : how do I reset a char * back to the 1st char > in the string when I've done ++ operations to the pointer? there's no > way, and I'll need a 2nd ptr to point to the head, much like a linked > list, right? > thanx for the enlightenment, > Aaron
|
Fri, 01 Mar 2002 03:00:00 GMT |
|
 |
Jordan Kat #7 / 15
|
 Help explain char * and char [] differences
Quote:
> I also have another query : how do I reset a char * back to the 1st char > in the string when I've done ++ operations to the pointer?
Just as you can point to the next element using the increment operator(s), you can go an element back using the decement operators. Here's an example: char *myPtr; char myArray[] = "Hello!"; myPtr = myArray; /* myPtr points to myArray[0], which is 'H' */ myPtr++; /* myPtr points to myArray[1], which is 'e' */ myPtr--; /* myPtr points back to myArray[0] */ -- _________________________________ Jordan Katz
|
Fri, 01 Mar 2002 03:00:00 GMT |
|
 |
Aaron See #8 / 15
|
 Help explain char * and char [] differences
I had this misconception a char * string would be modifiable since I did not explicity declare using const. So its const by default. I'll stick to arrays then. Thanks for the clarifications! Aaron PS - yea, I'm having real weird probs with my news server? I posted the 1st msg but didn't see any update for a day or so & thought it got lost. It only appeared after I posted the 2nd, which also took a few hrs to appear, even when other posts were coming thru. And it appeared both appeared at my face at the same time! Is it my side or my news server or the newsgrp host????
|
Sat, 02 Mar 2002 03:00:00 GMT |
|
 |
Bish #9 / 15
|
 Help explain char * and char [] differences
Quote:
>> I also have another query : how do I reset a char * back to the 1st >char >> in the string when I've done ++ operations to the pointer? there's no >> way, and I'll need a 2nd ptr to point to the head, much like a linked >> list, right? >Yes. You'll need to preserve the original address somehow.
Really? I didn't know this. I thought that a -- operations on the pointer would eventually reset the char * to it's original position. I even tried this out and it seemed to work. I guess this is just another one of those strange ``undefined behaviour'' issues with C, or perhaps my compiler was doing a bit of magic and I just got lucky? For what it's worth here's the code I tried this with. Constructive criticism is VERY, VERY, VERY welcome. :-) #include <stdio.h> #include <stdlib.h> void foo(char *s1, char *s2) { while ((*s2++ = *s1++) != '\0') ; --s1; if (*--s1 == 't') printf("This is only a test.\n"); Quote: }
This code isn't meant to do anything spectacular nor is it supposed to look good. :-) Anyway, I guess the above code is both dangerous and wrong? Thanks folks. -- Bishop
|
Sat, 02 Mar 2002 03:00:00 GMT |
|
 |
Paul Lutu #10 / 15
|
 Help explain char * and char [] differences
Quote: > >Yes. You'll need to preserve the original address somehow. > Really? I didn't know this. I thought that a -- operations on the pointer > would eventually reset the char * to it's original position.
But don't you see -- your method doesn't contradict John's statement. You did preserve the original address by storing the number of decrements required to restore the original address. -- Paul Lutus www.arachnoid.com
<snip>
|
Sat, 02 Mar 2002 03:00:00 GMT |
|
 |
Bish #11 / 15
|
 Help explain char * and char [] differences
Quote:
>> >Yes. You'll need to preserve the original address somehow. >> Really? I didn't know this. I thought that a -- operations on the pointer >> would eventually reset the char * to it's original position. >But don't you see -- your method doesn't contradict John's statement. You >did preserve the original address by storing the number of decrements >required to restore the original address. >-- >Paul Lutus >www.arachnoid.com
I suppose you are right. Stupid me. How about my next example? It seems to do what is asked of it. Can it also be considered correct? include <stdio.h> #include <stdlib.h> #include <string.h> int main() { char *p; p = malloc(6 * sizeof *p); if (p == NULL) { fprintf(stderr, "FATAL: out of memory.\n"); exit(EXIT_FAILURE); strcpy(p, "hello"); printf("%s\n", ++p); printf("%s\n", ++p); printf("%s\n", --p); printf("%s\n", --p); return EXIT_SUCCESS; Quote: }
-- Bishop
|
Sat, 02 Mar 2002 03:00:00 GMT |
|
 |
Paul Lutu #12 / 15
|
 Help explain char * and char [] differences
Quote: > I suppose you are right. Stupid me. How about my next example? It seems to > do what is asked of it. Can it also be considered correct?
All except the part where it doesn't call free(). If you say, "But the return from main() frees the allocation," this is generally true but it is bad practice to depend on it. Also your code is uncompilable -- a missing brace. Always copy your code directly from your program editor, never just type it in. Also your program uses exit() in one path, which will not deallocate the malloc'd memory. -- Paul Lutus www.arachnoid.com
Quote:
> >> >Yes. You'll need to preserve the original address somehow. > >> Really? I didn't know this. I thought that a -- operations on the pointer > >> would eventually reset the char * to it's original position. > >But don't you see -- your method doesn't contradict John's statement. You > >did preserve the original address by storing the number of decrements > >required to restore the original address. > >-- > >Paul Lutus > >www.arachnoid.com > I suppose you are right. Stupid me. How about my next example? It seems to > do what is asked of it. Can it also be considered correct? > include <stdio.h> > #include <stdlib.h> > #include <string.h> > int main() > { > char *p; > p = malloc(6 * sizeof *p); > if (p == NULL) { > fprintf(stderr, "FATAL: out of memory.\n"); > exit(EXIT_FAILURE); > strcpy(p, "hello"); > printf("%s\n", ++p); > printf("%s\n", ++p); > printf("%s\n", --p); > printf("%s\n", --p); > return EXIT_SUCCESS; > } > -- > Bishop
|
Sat, 02 Mar 2002 03:00:00 GMT |
|
 |
Paul Lutu #13 / 15
|
 Help explain char * and char [] differences
Thanks again. I wrongly accepted at face value another thread that asserted a different outcome for exit(). -- Paul Lutus www.arachnoid.com
Quote:
> > > I suppose you are right. Stupid me. How about my next example? It seems > to > > > do what is asked of it. Can it also be considered correct? > > All except the part where it doesn't call free(). If you say, "But the > > return from main() frees the allocation," this is generally true but it > is > > bad practice to depend on it. > > Also your code is uncompilable -- a missing brace. Always copy your code > > directly from your program editor, never just type it in. > > Also your program uses exit() in one path, which will not deallocate the > > malloc'd memory. > 5.1.2.2.3 Program termination > [#1] If the return type of the main function is a type > compatible with int, a return from the initial call to the > main function is equivalent to calling the exit function > with the value returned by the main function as its > argument;9) reaching the } that terminates the main function > returns a value of 0. If the return type is not compatible > with int, the termination status returned to the host > environment is unspecified. > That's from C9X, I'm afraid - no C89 here. > Anyway, the point is that if return from main() frees the memory, so does > exit(). > I do agree, though, that it's good programming practice to wash your own > dishes. > -- > Richard Heathfield > "Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
|
Sat, 02 Mar 2002 03:00:00 GMT |
|
 |
Martin Ambuh #14 / 15
|
 Help explain char * and char [] differences
Quote:
> >> >Yes. You'll need to preserve the original address somehow. > >> Really? I didn't know this. I thought that a -- operations on the pointer > >> would eventually reset the char * to it's original position. > >But don't you see -- your method doesn't contradict John's statement. You > >did preserve the original address by storing the number of decrements > >required to restore the original address. > I suppose you are right. Stupid me. How about my next example? It seems to > do what is asked of it. Can it also be considered correct?
Clearly not. #include is misspelled, a closing '}' is missing, and you never free the allocated memory. Try running this: #include <stdio.h> /* mha */ #include <stdlib.h> #include <string.h> int main() { char *p; p = malloc(6 * sizeof *p); if (p == NULL) { fprintf(stderr, "FATAL: out of memory.\n"); exit(EXIT_FAILURE); } /* mha */ printf("After %s, p is %p\n", "allocaton", (void *)p); /* mha */ strcpy(p, "hello"); printf("After %s, p is %p\n", "strcpy", (void *)p); /* mha */ printf("%s\n", ++p); printf("After %s, p is %p\n", "first ++p", (void *)p); /* mha */ printf("%s\n", ++p); printf("After %s, p is %p\n", "second ++p", (void *)p); /* mha */ printf("%s\n", --p); printf("After %s, p is %p\n", "first --p", (void *)p); /* mha */ printf("%s\n", --p); printf("After %s, p is %p\n", "second --p", (void *)p); /* mha */ free(p); /* mha */ return EXIT_SUCCESS; Quote: }
[Output with one impementation, yours will vary] After allocaton, p is 8f0d0 After strcpy, p is 8f0d0 ello After first ++p, p is 8f0d1 llo After second ++p, p is 8f0d2 ello After first --p, p is 8f0d1 hello After second --p, p is 8f0d0 Quote: > include <stdio.h> > #include <stdlib.h> > #include <string.h> > int main() > { > char *p; > p = malloc(6 * sizeof *p); > if (p == NULL) { > fprintf(stderr, "FATAL: out of memory.\n"); > exit(EXIT_FAILURE); > strcpy(p, "hello"); > printf("%s\n", ++p); > printf("%s\n", ++p); > printf("%s\n", --p); > printf("%s\n", --p); > return EXIT_SUCCESS; > } > -- > Bishop
--
__________________________________________________________ Fight spam now! Get your free anti-spam service: http://www.brightmail.com
|
Sat, 02 Mar 2002 03:00:00 GMT |
|
 |
Richard Heathfiel #15 / 15
|
 Help explain char * and char [] differences
Quote: > > I suppose you are right. Stupid me. How about my next example? It seems to > > do what is asked of it. Can it also be considered correct? > All except the part where it doesn't call free(). If you say, "But the > return from main() frees the allocation," this is generally true but it is > bad practice to depend on it. > Also your code is uncompilable -- a missing brace. Always copy your code > directly from your program editor, never just type it in. > Also your program uses exit() in one path, which will not deallocate the > malloc'd memory.
5.1.2.2.3 Program termination [#1] If the return type of the main function is a type compatible with int, a return from the initial call to the main function is equivalent to calling the exit function with the value returned by the main function as its argument;9) reaching the } that terminates the main function returns a value of 0. If the return type is not compatible with int, the termination status returned to the host environment is unspecified. That's from C9X, I'm afraid - no C89 here. Anyway, the point is that if return from main() frees the memory, so does exit(). I do agree, though, that it's good programming practice to wash your own dishes. -- Richard Heathfield "Usenet is a strange place." - Dennis M Ritchie, 29 July 1999.
|
Sun, 03 Mar 2002 03:00:00 GMT |
|
|
|