I am using strtok to extract 2 words from a string names[result]. I want to get the first value from the strtok and stored it into a char array named lastName and the second value into a char array named firstName. However I got an invalid initializer error for 2 lines which are indicated by the arrow when I compiled my code. How do I resolve my problem?
char *p = NULL;
p = strtok(names[result]," ");
char lastName[50] = p; <---
p = strtok(NULL, " ");
char firstName[50] = p; <---
printf("%s %s\n",firstName,lastName);
strtok gives the pointer to the tokenized string.
char lastName[50] = p; Isn't really a good thing that you are doing there. Should use strncpy() to copy the string, or if only want the pointer, then should store in another pointer.
Array initialization in C can only use a literal, not a variable. So your code is a syntax error.
You need to use the typical strcpy() function to copy the string, or some of the more safe (and modern) varities, like strlcpy() or snprintf().
You could also do the parsing and copying in one call, using sscanf(), with proper size specifiers in the formatting string to avoid the risk of buffer overflow.
You can initialize a string to the character array like char lastName[50] = "Sample";
In this case you are trying to initialize a pointer to the character array 'char lastName[50] = p;' which is not valid.
Better you can use strcpy, memcpy function to copy the string to the character array or you can assign it in another pointer.
The other answers are all correct in that copying the string data out will make this program work, but the reason strtok is so dastardly (and generally using it is considered ill-advised) is that it changes your input by inserting NULLs into the original string. If you're going to be using it anyway, you might as well advantage of this and just use the pointers that strtok is returning directly.
Of note, though, is that since the input is changed and maybe whoever passed that input into you is not expecting that, it might be better to copy the input to a separate string first before ever calling strtok on it.
Observe the output of this code to see what I mean:
int main(int argc, char *argv[]) {
char name[] = "Firstname Lastname";
printf("Name before strtok: %s\n", name);
char *first = strtok(name, " ");
char *last = strtok(NULL, " ");
printf("Token strings: first=%s last=%s\n", first, last);
printf("Name after strtok: %s\n", name);
}
Produces:
Firstname Name before strtok: Firstname Lastname
Token strings: first=Firstname last=Firstname
Name after strtok: Firstname
Related
I typed up this block of code for an assignment:
char *tokens[10];
void parse(char* input);
void main(void)
{
char input[] = "Parse this please.";
parse(input);
for(int i = 2; i >= 0; i--) {
printf("%s ", tokens[i]);
}
}
void parse(char* input)
{
int i = 0;
tokens[i] = strtok(input, " ");
while(tokens[i] != NULL) {
i++;
tokens[i] = strtok(NULL, " ");
}
}
But, looking at it, I'm not sure how the memory allocation works. I didn't define the length of the individual strings as far as I know, just how many strings are in the string array tokens (10). Do I have this backwards? If not, then is the compiler allocating the length of each string dynamically? In need of some clarification.
strtok is a bad citizen.
For one thing, it retains state, as you've implicitly used when you call strtok(NULL,...) -- this state is stored in the private memory of the Standard C Library, which means only single threaded programs can use strtok. Note that there is a reentrant version called strtok_r in some libraries.
For another, and to answer your question, strtok modifies its input. It doesn't allocate space for the strings; it writes NUL characters in place of your delimiter in the input string, and returns a pointer into the input string.
You are correct that strtok can return more than 10 results. You should check for that in your code so you don't write beyond the end of tokens. A reliable program would either set an upper limit, like your 10, and check for it, reporting an error if it's exceeded, or dynamically allocate the tokens array with malloc, and realloc it if it gets too big. Then the error occurs when you fun out of memory.
Note that you can also work around the problem of strtok modifying your input string by strduping before passing it to strtok. Then you'll have to free the new string after both it and tokens, which points to it, are going out of scope.
tokens is an array of pointers.
The distinction between strings and pointers if often fuzzy. In some situations strings are better thought out as arrays, in other situations as pointers.
Anyway... in your example input is an array and tokens is an array of pointers to a place within input.
The data inside input is changed with each call to strtok()
So, step by step
// input[] = "foo bar baz";
tokens[0] = strtok(input, " ");
// input[] = "foo\0bar baz";
// ^-- tokens[0] points here
tokens[1] = strtok(NULL, " ");
// input[] = "foo\0bar\0baz";
// ^-- tokens[1] points here
tokens[2] = strtok(NULL, " ");
// input[] = "foo\0bar\0baz";
// ^-- tokens[2] points here
// next strtok returns NULL
I'm working on the following homework problem:
Given the first name and last name as parameters, write the code of
the function createFBlink(). The functions returns a facebook link
which serves as an alternate email of the facebook user. The variable
holding the facebook link should contain the minimum number of bytes
required to store the string representing the facebook link. If there
is no first name or last name, the function returns NULL.
For example, if firstname = tzuyu and lastname = chou, the
facebook link is chou.tzuyu#facebook.com.
(See the original problem statement here.)
I've been trying to return a string from createFBlink into main. I've tried multiple methods such as turning char into static but I keep getting errors that I don't understand because I don't have a lot of experience with C.
I've had the best luck with using malloc, but I've come across a problem wherein if ever there are parameters to the function I'm sending from main, I end up with a crash after the input. Here's my code so far:
#include <string.h>
#include <conio.h.>
#include <stdio.h>
#include <stdlib.h>
char *createFBlink(char *firstname , char *lastname) ;
int main(void)
{
char firstname[24] , lastname[24], fblink[24] ;
printf("Enter first name: ");
scanf("%s", firstname);
firstname[strlen(firstname)] = '\0';
printf("\n Enter last name: ");
scanf("%s", lastname);
lastname[strlen(lastname)] = '\0';
*fblink = createFBlink(firstname, lastname);
if(*firstname == '\0'){
printf("no facebook link generated");
}else{
printf("%s", *fblink);
}
getch();
return 0;
}
char * createFBlink(char *firstname , char *lastname)
{
int check1 = strlen(firstname) , check2 = strlen(lastname), num = check1+check2;
char link = (char*) malloc(sizeof(char) * num);
if(check1 == 0 || check2 == 0){
*firstname = '\0' ;
}else{
strcat(*lastname, ".");
strcat(*lastname, firstname);
strcat(*lastname, "#facebook.com");
strcpy(link , *lastname);
return link;
}
}
*link = (char *) malloc(24);
This is incorrect, it should be
link = (char *) malloc(24);
*link (the same as link[0]) is the first character of the string pointed by link, that assignment is just overwriting the character, not changing the pointer.
The following is also incorrect:
*fblink = createFBlink(firstname, lastname);
This:
strcat(*lastname, ...);
is incorrect in the same way. You are getting the first character of the string pointed by lastname, converting it to a pointer and passing this (obviously invalid) pointer to strcat. This is the most likely reason of the crash.
Also, 24 characters may not be enough to hold the concatenated string.
Try to read a book about working with pointers in C, trying to understand them via trial-and-error is probably not the most effective way.
When working with strings, you need to understand the types you are using.
This is a fixed area in memory, of fixed size.
char buffer [24];
This is a dynamically allocated buffer that must be freed
char* szBuffer = malloc(24);
free(szBuffer)
Instead of doing that correctly, your createFBlink does malloc twice, and free zero times.
If you return a malloc'ed buffer from a function, you still must free it.
char * result = createFBlink(stuff);
free(result);
Since the types are different, you would need to use another function to move the string data from one to the other.
char * result = createFBlink(stuff);
strcpy(fblink, result, sizeof(fblink));
free(result);
And then you have additional risk from writing outside the allocated space. Let's try a made-up name with some common names.
firstname "Richard"
lastname "Hernandez"
returned string "Hernandez.Richard#facebook.com"
Oh look, 31 characters in a 24 character string. We just overwrite something, somewhere on your computer. Literally anything could happen, now.
So you have all kinds of risk. You have to match malloc with free. You have to keep track of the size. All of this is considered to be VERY BAD c++ style. The std::string class is highly recommended for this. You want your string class to take care of all the resource management, so you can't mess it up while you are using it.
std::string CreateFacebookLink (const std::string &firstname, const std::string &lastname){
return firstname + "." + lastname + "#facebook.com";
}
std::string strFacebookLink (CreateFacebookLink("Richard", "Hernandez"));
I am starting to studying C and I already run into few problems.
I want to parse a file and store the results of each line in a structure.
My structure looks like:
struct record {
char x[100];
}
Then, whenever I use strtok to parse a line in some file.txt,
struct record R;
...
char *token;
token = strtok(line, "\t");
token returns a pointer to the string and whenever I print it, it is correct string. I want to assign token to x, such as R.x = token, but I get an error, "char x[100] is not assignable". Is it possible to convert this pointer token to actual char array or what would be the best way to store the results into the structure?
The error says it all. Arrays are not assignable. You need to copy each character one by one and then append a NUL-terminator at the end.
Fortunately there is a function that does this for you. The name of the function is strcpy and it is found in the string.h header.
To fix your issue, use
strcpy(R.x,token);
instead of
R.x = token;
Use strcpy after making sure that the string fits in the array:
#define LEN(array) (sizeof (array) / sizeof (array)[0])
if (strlen(token) < LEN(R.x)) {
strcpy(R.x, token);
} else {
fprintf(stderr, "error: input string \"%s\" is longer than maximum %d\n", token, LEN(R.x) - 1);
}
strcpy stops when it encounters a NULL, memcpy does not.
So if you array have 0x00 eg. \0 in middle,you should use memcpy rather than strcpy.
So I'm new to C and the whole string manipulation thing, but I can't seem to get strtok() to work. It seems everywhere everyone has the same template for strtok being:
char* tok = strtok(source,delim);
do
{
{code}
tok=strtok(NULL,delim);
}while(tok!=NULL);
So I try to do this with the delimiter being the space key, and it seems that strtok() no only reads NULL after the first run (the first entry into the while/do-while) no matter how big the string, but it also seems to wreck the source, turning the source string into the same thing as tok.
Here is a snippet of my code:
char* str;
scanf("%ms",&str);
char* copy = malloc(sizeof(str));
strcpy(copy,str);
char* tok = strtok(copy," ");
if(strcasecmp(tok,"insert"))
{
printf(str);
printf(copy);
printf(tok);
}
Then, here is some output for the input "insert a b c d e f g"
aaabbbcccdddeeefffggg
"Insert" seems to disappear completely, which I think is the fault of strcasecmp(). Also, I would like to note that I realize strcasecmp() seems to all-lower-case my source string, and I do not mind. Anyhoo, input "insert insert insert" yields absolutely nothing in output. It's as if those functions just eat up the word "insert" no matter how many times it is present. I may* end up just using some of the C functions that read the string char by char but I would like to avoid this if possible. Thanks a million guys, i appreciate the help.
With the second snippet of code you have five problems: The first is that your format for the scanf function is non-standard, what's the 'm' supposed to do? (See e.g. here for a good reference of the standard function.)
The second problem is that you use the address-of operator on a pointer, which means that you pass a pointer to a pointer to a char (e.g. char**) to the scanf function. As you know, the scanf function want its arguments as pointers, but since strings (either in pointer to character form, or array form) already are pointer you don't have to use the address-of operator for string arguments.
The third problem, once you fix the previous problem, is that the pointer str is uninitialized. You have to remember that uninitialized local variables are truly uninitialized, and their values are indeterminate. In reality, it means that their values will be seemingly random. So str will point to some "random" memory.
The fourth problem is with the malloc call, where you use the sizeof operator on a pointer. This will return the size of the pointer and not what it points to.
The fifth problem, is that when you do strtok on the pointer copy the contents of the memory pointed to by copy is uninitialized. You allocate memory for it (typically 4 or 8 bytes depending on you're on a 32 or 64 bit platform, see the fourth problem) but you never initialize it.
So, five problems in only four lines of code. That's pretty good! ;)
It looks like you're trying to print space delimited tokens following the word "insert" 3 times. Does this do what you want?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main(int argc, char **argv)
{
char str[BUFSIZ] = {0};
char *copy;
char *tok;
int i;
// safely read a string and chop off any trailing newline
if(fgets(str, sizeof(str), stdin)) {
int n = strlen(str);
if(n && str[n-1] == '\n')
str[n-1] = '\0';
}
// copy the string so we can trash it with strtok
copy = strdup(str);
// look for the first space-delimited token
tok = strtok(copy, " ");
// check that we found a token and that it is equal to "insert"
if(tok && strcasecmp(tok, "insert") == 0) {
// iterate over all remaining space-delimited tokens
while((tok = strtok(NULL, " "))) {
// print the token 3 times
for(i = 0; i < 3; i++) {
fputs(tok, stdout);
}
}
putchar('\n');
}
free(copy);
return 0;
}
Just for the fun of it I am writing a program that will take a user inputted string (or maybe even a text document) and scramble the words within the string.
I am attempting to use the strtok function to separate each word in the string. At the moment I feel like my current implementation of strtok is sloppy:
int main(int argc, char *argv[])
{
char *string, *word;
if(!(string = getstr())) //function I wrote to retrieve a string
{
fputs("Error.\n", stderr);
exit(1);
}
char array[strlen(string) + 1]; //declare an array sized to the length of the string
strcpy(array, string); //copy the string into the array
free(string);
if(word = strtok(array, " "))
{
//later I'll just write each word into a matrix, not important right now.
while(word = strtok(NULL, " "))
{
//later I'll just write each word into a matrix, not important right now.
}
}
return 0;
}
I feel like there must be a cleaner way of implementing strtok without declaring an array midway through the program. It just doesn't feel correct to me. Is using strtok the correct way to go about this? I would rather not use a fixed size array, as I like everything to be dynamic, which is why I'm starting to doubt using strtok is the correct way to go.
If your string is malloced as suggested by your free. Then you don't need to copy it in a new buffer (which is btw 1 character too short). Use the buffer you were provided.
You only need to duplicate it if it was given to you by a const char * i.e. you're not allowed to modify the content of the buffer.
It's also better to use strtok_r as the regular strtokis not reentrant.
You can use scanf() instead of getstr() and strtok()
char word[100];
while(scanf(" %s",word)!=EOF) {
// use the word string here
}
the user should stop input chracters with
EOF = CTRL + D (for Linux)
EOF = CTRL + Z (for Windows)