Variable empty after comparison - c

In the code, when I print var_value, it shows its content but when I need to assign it later on the if else statements, it's empty only IN THE LAST IF and I have no idea why it is. If I delete the last statement, the other three pass without problems.
while ((read = getline(&line, &len, f)) != -1){
printf("%s\n", line);
char *token;
token = strtok(line, "=");
var_name = token;
/* Separate every line by the '=' character */
while( token != NULL ) {
var_value = token;
token = strtok(NULL, "=");
}
printf("%s\n", var_name);
printf("%s\n", var_value);
// Obtain the parameters
if (strcmp(var_name, "puerto") == 0) {
puerto = atoi(var_value);
parameters_count += 1;
} else if (strcmp(var_name, "tamano_tabla") == 0) {
tamano_tabla = atoi(var_value);
parameters_count += 1;
} else if (strcmp(var_name, "periodo_archivo") == 0) {
periodo_archivo = atoi(var_value);
parameters_count += 1;
} else if (strcmp(var_name, "archivo_tabla") == 0) {
printf("%s var val\n", var_value);
strcpy(archivo_tabla, strtok(var_value, "\n")); //Remove \n and copy to destination variable
parameters_count += 1;
printf("%s filetabla\n", archivo_tabla);
}
}
Edit: Results in console and after the final one, segmentation fault
puerto=1212
puerto
1212
archivo_tabla=tabla.xml
archivo_tabla
tabla.xml
tabla.xml
var val

Your output does not support your contention that
In the code, when I print var_value, it shows its content but when I
need to assign it later on the if else statements, it's empty only IN
THE LAST IF [...].
In fact, your output shows the opposite: var_val is printed just fine. I have to assume that you are being confused by the fact that its value ends with a newline, which is printed, too. Thus, " var val" appears at the beginning of a line. Here's the expected value of var_val, including newline, followed by " var val":
tabla.xml
var val
The presence of a newline in the string provided by getline() is the whole point of the strtok(var_value, "\n") that happens next, after all. Or so I assume.
Note also that although the output you present appears to be truncated relative to the code you present, in my tests, the contents of var_val are successfully copied to variable archivo_tabla, too, less that pesky newline.

This line is suspect: strcpy(archivo_tabla, strtok(var_value, "\n")); //Remove \n and copy to destination variable
strtok mutates var_value. You seem to be copying archivo_tabla to the remaining part of var_value after the "\n" (which doesn't really make sense)
https://www.tutorialspoint.com/c_standard_library/c_function_strtok.htm

Related

Strsep, Parsing CSV Input further

Using strsep to split a CSV with a bunch of usless junk in it ("," Delim). One of the entries has quotes on either side (ie Florida,"Bob",1999) and I'd like to pull those out before I save them in my array.
How do I remove the quotes from the name? Thanks!
for (int i = 0; i < 19; i++)
{
token = strsep(&copy, ","); //Split token
if (i == 3) {one_spot->location = token;}
if (i == 17) {one_spot->name = token;}//the Name is in quotes in CSV
if (i == 18) {one_spot->year = atoi(token);}
}
all_spots[j] = one_spot; //Add to array.
You could do something like this:
look for the first " using strchr
If found, look for the next "
Use memcpy to copy the strings between the quotes.
if (i == 17)
{
char *firstq = strchr(token, '"');
if(firstq == NULL)
{
one_song->name = strdup(token);
continue;
}
char *lastq = strchr(firstq++, '"');
if(lastq == NULL)
{
// does not end in ", copy everything
one_song->name = strdup(token);
continue;
}
size_t len = lastq - firstq;
char *word = calloc(len + 1, 1);
if(word == NULL)
{
// error handling, do not continue
}
memcpy(word, firstq, len); // do not worry about \0 because of calloc
one_song->name = word;
}
Note that I use strdup to do the assignment one_song->name = strdup(token);
and calloc to allocate memory. strsep returns a pointer to copy + an
offset. Depending how you created/allocated copy, this memory might be
invalid once the function exits. That's why it's better to create a copy of the
original before you assign it to the struct.
This code is very simple, it does not handle spaces at the beginning and end of
the string. It can distinguish between abc and "abc" but it fails at
"abc"d or "abc"def". It also does not handle escaped quotes, etc. This code shows you only a way of extracting a string from the quotes. It's not my job to write your exercise for you, but I can show you how to start.

Why is my program printing out more times than expected?

I have a program that reads in a file, goes through line by line, and breaks up the line word by word. My problem is, I am about to store each word in a array but I need to use strcmp function to verify the word doesnt already exist. Anyways below is my code and my question is, why is my program printing out 1 so many times? I was expecting it to only print it out twice because this occurs twice in my text file.
while (fgets(line, sizeof(line), fi) != NULL) { // looping through each line
line_count += 1;
for (j = 0; j < sizeof(line); j++) { // convert all words to lowercase
line[j] = tolower(line[j]);
}
result = strtok(line, delimiters);
while (result != NULL) {
word_count += 1;
if (strcmp(result, "this")) {
printf("1\n");
}
result = strtok(NULL, delimiters); // get the next token
}
}
Below is my text file:
This is the first test.
This is the second test.
strcmp() returns 0 if the string matches. You're checking for a truthy value. You really want strcmp(result, "this") == 0.
You will also need to make the match case insensitive, which is usually called stricmp().
Do you try again after change "strcmp(result, "this")" to "strcmp(result, "This")" ?

Ignoring spaces in a string unless it's in quotes

char *args[32];
char **next = args;
char *temp = NULL;
char *quotes = NULL;
temp = strtok(line, " \n&");
while (temp != NULL) {
if (strncmp(temp, "\"", 1) == 0) {
//int i = strlen(temp);
printf("first if");
quotes = strtok(temp, "\"");
} else if (strncmp(temp, "\"", 1) != 0) {
*next++ = temp;
temp = strtok(NULL, " \n&");
}
}
I'm having trouble with trying to understand with how to still keep spaces if a part of the string is surrounded with quotes. For example, if I want execvp() to execute this: diff "space name.txt" sample.txt, it should save diff at args[0], space name.txt at args[1] and sample.txt at args[2].
I'm not really sure on how to implement this, I've tried a few different ways of logic with if statements, but I'm not quite there. At the moment I am trying to do something simple like: ls "folder", however, it gets stuck in the while loop of printing out my printf() statement.
I know this isn't worded as a question - it's more explaining what I'm trying to achieve and where I'm up to so far, but I'm having trouble and would really appreciate some hints of how the logic should be.
Instead of using strtok process the string char by char. If you see a ", set a flag. If flag is already set - unset it instead. If you see a space - check the flag and either switch to next arg, or add space to current. Any other char - add to current. Zero byte - done processing.
With some extra effort you'll be able to handle even stuff like diff "file \"one\"" file\ two (you should get diff, file "one" and file two as results)
I'm confused even to understand what you try to do. Are you trying to tokenize the input string into space separated tokens?
Just separate the input string on spaces and when you encounter a double quote char you need a second inner loop which handles quoted strings.
There is more to quoted strings than to search for the closing quote. You need to handle backslashes, for example backslashed escaped quotes and also backslash escaped backslashes.
Just consider the following:
diff "space name \" with quotes.txt\\" foo
Which refers to a (trashy) filename space name " with quotes.txt\. Use this as a test case, then you know when you are done with the basics. Note that shell command line splitting is a lot more crazy than that.
Here is my idea:
Make two pointers A and B, initially pointing at first char of the string.
Iterate through the string with pointer A, copying every char into an array as long as it's not a space.
Once you have reached a ", take the pointer B starting from the position A+1 and go forward until you reach the next ", copying everything including space.
Now repeat from number 2, starting from the char B+1.
Repeat as long as you haven't reached \0.
Note: You'll have to consider what to do if there are nested quotes though.
You can also use a flag (int 1 || 0) and a pointer to denote if you're in a quote or not, following 2 separate rules based on the flag.
Write three functions. All of these should return the number of bytes they process. Firstly, the one that handles quoted arguments.
size_t handle_quoted_argument(char *str, char **destination) {
assert(*str == '\"');
/* discard the opening quote */
*destination = str + 1;
/* find the closing quote (or a '\0' indicating the end of the string) */
size_t length = strcspn(str + 1, "\"") + 1;
assert(str[length] == '\"'); /* NOTE: You really should handle mismatching quotes properly, here */
/* discard the closing quote */
str[length] = '\0';
return length + 1;
}
... then a function to handle the unquoted arguments:
size_t handle_unquoted_argument(char *str, char **destination) {
size_t length = strcspn(str, " \n");
char c = str[length];
*destination = str;
str[length] = '\0';
return c == ' ' ? length + 1 : length;
}
... then a function to handle (possibly repetitive) whitespace:
size_t handle_whitespace(char *str) {
int whitespace_count;
/* This will count consecutive whitespace characters, eg. tabs, newlines, spaces... */
assert(sscanf(str, " %n", &whitespace_count) == 0);
return whitespace_count;
}
Combining these three should be simple:
size_t n = 0, argv = 0;
while (line[n] != '\0') {
n += handle_whitespace(line + n);
n += line[n] == '\"' ? handle_quoted_argument(line + n, args + argv++)
: handle_unquoted_argument(line + n, args + argv++);
}
By breaking this up into four separate algorithms, can you see how much simpler this task becomes?
So here is where I read in the line:
while((qtemp = fgets(line, size, stdin)) != NULL ) {
if (strcmp(line, "exit\n") == 0) {
exit(EXIT_SUCCESS);
}
spaceorquotes(qtemp);
}
Then I go to this: (I haven't added my initializers, you get the idea though)
length = strlen(qtemp);
for(i = 0; i < length; i++) {
position = strcspn(qtemp, " \"\n");
while (strncmp(qtemp, " ", 1) == 0) {
memmove(qtemp, qtemp+1, length-1);
position = strcspn(qtemp, " \"\n");
} /*this while loop is for handling multiple spaces*/
if (strncmp(qtemp, "\"", 1) == 0) { /*this is for handling quotes */
memmove(qtemp, qtemp+1, length-1);
position = strcspn(qtemp, "\"");
stemp = malloc(position*sizeof(char));
strncat(stemp, qtemp, position);
args[i] = stemp;
} else { /*otherwise handle it as a (single) space*/
stemp = malloc(position*sizeof(char));
strncat(stemp, qtemp, position);
args[i] = stemp;
}
//printf("args: %s\n", args[i]);
length = strlen(qtemp);
memmove(qtemp, qtemp+position+1, length-position);
}
args[i-1] = NULL; /*the last position seemed to be a space, so I overwrote it with a null to terminate */
if (execvp(args[0], args) == -1) {
perror("execvp");
exit(EXIT_FAILURE);
}
I found that using strcspn helped, as modifiable lvalue suggested.

Junk Characters Outputted After Parsing From STDIN in C

I am getting a junk character to be output at the very end of some text that I read in:
hum 1345342342 ~Users/Documents ecabd459 //line that was read in from stdin
event action: hum_?
event timestamp: 1345342342
event path: ~Users/Documents
event hash: ecabd459
At the end of the event action value there is a '_?' garbage character that is output as well. That can be rectified by setting the variable's last position to the null terminator (event.action[3] = '\0') which is all well and good, but I am perplexed by the fact that the other char array event.hash does not exhibit this type of behavior. I am creating/printing them in an identical manner, yet hash does not behave the same.
Note: I was considering maybe this was due to the hash value being followed strictly by a newline character(which I get rid of by the way), so I tested my program with re-ordered input to no avail (that is, added an additional space and word after the hash value's position on the line).
The relevant code is below:
struct Event{
char action[4];
long timestamp;
char* path;
char hash[9];
};
// parse line and return an Event struct
struct Event parseLineIntoEvent(char* line) {
struct Event event;
char* lineSegment;
int i = 0;
lineSegment = strtok(line, " ");
while (lineSegment != NULL) {
if (i > 3) {
printf("WARNING: input format error!\n");
break;
}
if (i == 0)
strncpy(event.action, lineSegment, sizeof(event.action)-1);
else if(i == 1)
event.timestamp = atoi(lineSegment);
else if(i == 2) {
event.path = malloc(sizeof(lineSegment));
strcpy(event.path, lineSegment);
} else if(i == 3)
strncpy(event.hash, lineSegment, sizeof(event.hash)-1);
lineSegment = strtok(NULL, " ");
i++;
} // while
return event;
} // parseLineIntoEvent()
int main (int argc, const char * argv[]) {
//...
printf("%s\n",line); //prints original line that was read in from stdin
struct Event event = parseLineIntoEvent(line);
printf("event action: %s\n", event.action);
printf("event timestamp: %lu\n", event.timestamp);
printf("event path: %s\n", event.path);
printf("event hash: %s\n", event.hash);
free(event.path);
free(line);
//...
return 0;
}
EDIT:
I read in a line with this function, which gets rid of the newline character:
// read in line from stdin, eliminating newline character if present
char* getLineFromStdin() {
char *text;
int textSize = 50*sizeof(char);
text = malloc(textSize);
if ( fgets(text, textSize, stdin) != NULL ) {
char *newline = strchr(text, '\n'); // search for newline character
if ( newline != NULL ) {
*newline = '\0'; // overwrite trailing newline
}
}
return text;
}
Thanks in advance!
This is a mistake:
event.path = malloc(sizeof(lineSegment));
will return the sizeof(char*), when you require the length plus one for terminating NULL character:
event.path = malloc(sizeof(char) * (strlen(lineSegment) + 1));
To avoid having to insert null string terminators into action and hash you could initialise event:
struct Event event = { 0 };
From the Linux manual page:
The strncpy() function is similar, except that at most n bytes of src are copied.
Warning: If there is no null byte among the first n bytes of src, the string
placed in dest will not be null-terminated.
When doing strncpy you have to make sure the destination string is properly terminated.
Change the setting of the event.action field:
if (i == 0)
{
strncpy(event.action, lineSegment, sizeof(event.action)-1);
event.action[sizeof(event.action)-1] = '\0';
}
but I am perplexed by the fact that the other char array event.hash does not exhibit this type of behavior
You got unlucky. hash[8] may have gotten a '\0' by sheer (bad-)luck.
Try setting it to something "random" before your strtok loop
int i = 0;
event.hash[8] = '_'; /* forcing good-luck */
lineSegment = strtok(line, " ");
while (lineSegment != NULL) {
This is because, the string "num" takes only three elements from the 4 element character array Event.action and the fourth element will stay unset. Because nothing has been set to the Event.action array element it will point to random memory location which has some random value stored. When you printf this character array it will print all of the elements instead of those pointing to valid data. This causes the garbage character to show up.

How would i Use strtok to compare word by word

I've been reading up on strtok and thought it would be the best way for me to compare two files word by word. So far i can't really figure out how i would do it though
Here is my function that perfoms it:
int wordcmp(FILE *fp1, FILE *fp2)
{
char *s1;
char *s2;
char *tok;
char *tok2;
char line[BUFSIZE];
char line2[BUFSIZE];
char comp1[BUFSIZE];
char comp2[BUFSIZE];
char temp[BUFSIZE];
int word = 1;
size_t i = 0;
while((s1 = fgets(line,BUFSIZE, fp1)) && (s2 = fgets(line2,BUFSIZE, fp2)))
{
;
}
tok = strtok(line, " ");
tok2 = strtok(line, " ");
while(tok != NULL)
{
tok = strtok (NULL, " ");
}
return 0;
}
Don't mind the unused variables, I've been at this for 3 hours and have tried all possible ways I can think of to compare the values of the first and second strtok. Also I would to know how i would check which file reaches EOF first.
when i tried
if(s1 == EOF && s2 != EOF)
{
return -1;
}
It returns -1 even when the files are the same! Is it because in order for it to reach the if statement outside of the loop both files have reached EOF which makes the program always go to this if statement?
Thanks in advance!
If you want to check if files are same try doing,
do {
s1 = fgetc(fp1);
s2 = fgetc(fp2);
if (s1 == s2) {
if (s1 == EOF) {
return 1; // RETURN TRUE
}
continue;
}
else {
return -1; // RETURN FALSE
}
} while (1);
Good Luck :)
When you use strtok() you typically use code like this:
tok = strtok(line, " ");
while (NULL != tok)
{
tok = strtok(NULL, " ");
}
The NULL in the call in the loop tells strtok to continue from after the previously found token until it finds the null terminating character in the value you originally passed (line) or until there are no more tokens. The current pointer is stored in the run time library, and once strtok() returns NULL to indicate no more tokens any more calls to strtok() using NULL as the first parameter (to continue) will result in NULL. You need to call it with another value (e.g. another call to strtok(line, " ")) to get it to start again.
What this means is that to use strtok on two different strings at the same time you need to manually update the string position and pass in a modified value on each call.
tok = strtok(line, " ");
tok2 = strtok(line2, " ");
while (NULL != tok && NULL != tok2)
{
/* Do stuff with tok and tok2 here */
if (strcmp(tok, tok2)... {}
/* Update strtok pointers */
tok += strlen(tok) + 1;
tok2 += strlen(tok2) + 1;
/* Get next token */
tok = strtok(tok, " ");
tok2 = strtok(tok2, " ");
}
You'll still need to add logic for determining whether lines are different - you've not said whether the files are equivalent if a line break occurs at different position but the words surrounding it are the same. I assume it should be, given your description, but it makes the logic more awkward as you only need to perform the initial fgets() and strtok() for a file if you don't already have a token. You also need to look at how files are read in. Currently your first while loop just reads lines until the end of the file without processing them.

Resources