If I have this(please bear with me - this is a case of a former java
guy going back to C ;-)
int main () {
char *tokconvert(char*);
It will confuse people less if you put function prototypes at file scope
instead of inside functions. (In this particular case, you can avoid
needing the prototype altogether by putting tokconvert before main(),
but that's not always possible or reasonable.)
char str[] = "dot.delimited.str";
This allocates an array of char and populates it with the characters
in the string "dot.delimited.str" (including the terminating '\0').
The array is in the automatic-allocation space (we can call this "the
stack", but we prefer not to, because the function-invocation stack that
it exists in is not the same stack as the "processor's stack segment"
stack (which need not even exist) that people typically assume we're
talking about), and therefore that we can do pretty much whatever we
want with it (the relevant bit of that here is that we can write to it)
until the function returns.
char *result;
result = tokconvert(str);
When you pass str (an array) to a function (or do most other things with
it, notable exceptions being applying & or sizeof to it), the array name
decays to a pointer to the array's first element. In this case, this
is exactly what you want - a pointer to the first character of the string.
return 0;
}
char *tokconvert(char *strToConvert) {
char *token;
char *tokDelim =",.";
token=strtok(strToConvert, tokDelim);
while(token != NULL) {
printf("Token -> %s \n", token);
token=strtok(NULL, tokDelim);
}
You're not returning anything here. Your compiler should have warned
you about that.
(I'm not sure what you'd've wanted to return; possibly this is a leftover
from doing something with the tokens other than just printing them?)
}
the thing compiles and runs fine, however if I declare char *str =
"dot.delimited.str" (instead of char str[] = "dot.delimited.str") the
whole thing falls on its ass real bad (bus error) - strtok is defined
as char *strtok(char *, const char *) - what's going on?
When you say `char *str="a string literal"', the string literal (like
any other string literal in the program[1]) refers to an anonymous
not-const-but-not-writeable array of characters containing the string.
In English, that means you're allowed to point a pointer that you're
allowed to write through at it (remember, arrays decay to pointers),
but you're not actually allowed to write to it.
So, you have a pointer pointing at a string literal that you're not
allowed to write to... and then you try to write to it (indirectly,
by passing it to strtok, which writes to its first argument). That's
what's causing your problem. The solution is to Don't Do That, Then:
Allocate writeable space for the string you give strtok as its first
argument, either as an automatic variable (like in your code above)
or as dynamically allocated memory (f'rexample, memory from strdup as
below), and put the string into that.
more craziness: if I declare/initialise
char *str;
str = strdup("dot.delimited.str)
inside tokconvert (instead of main) and pass that to strtok - it runs
fine!!
Note that strdup is a unixism and not part of the C language.[2]
What strdup does is allocate (with malloc) enough memory to hold the
string you give it, and copy the string into that memory, and return a
pointer to the copy of the string. This memory is writeable, so giving
strdup a pointer to it isn't a problem, for the same reason that giving
it a pointer to the automatically allocated array isn't a problem.
P.S.
btw this is on FreeBSD 5.1.2 (using gcc 3.3.3)
If I'd needed to know that, then your question would have been
inappropriate for comp.lang.c and would have been better off asked in
a FreeBSD or GCC newsgroup.
But given that you're using GCC: If you'd compiled with:
gcc -W -Wall -ansi -pedantic -O myprog.c
then GCC would have warned you about failing to return a value from
tokconvert, along with a bunch of other warnings about things that you
typically don't want to do. This makes debugging some problems a lot
easier - they go away when the compiler stops warning you about them.
dave
[1] In language-lawyer-ese, the string in the array initialization
`char buf[]="a string"' is an initializer, not a string literal;
this is, as far as I know, the only place you can have a string in
the source code that doesn't represent an anonymous array of char.
[2] It's in the implementation's namespace, though, which means you're
not allowed to define it yourself. The solution in comp.lang.c is
to use my_strdup, which can portably be defined and have the same
behavior as the unix strdup; the usual solution outside comp.lang.c
is to use the library's strdup if it exists, and otherwise to apply
knowledge beyond that found in the language definition to establish
that the programmer is allowed to define a function by that name on
that implementation and do so.