Confusing strcpy() behaviour, concatenating to other strings [duplicate] - c

This question already has answers here:
How dangerous is it to access an array out of bounds?
(12 answers)
Closed 2 months ago.
So Im loading comma seperated text from a file.
9780136019701,An Introduction to Organic Chemistry,Timberlake Karen,10,3.54,12-2008
9781506304212,Mathematics for Social Scientists,Kropko Jonathan,7,4.73,12-2015
9781506304213,Discrete Mathematics,Jonathan,15,19.73,10-2013
9780136019702,Chemotherapy,Karen,1,2.54,1-2002
Each line will have six properties and I'm using strtok to split the line. However very confusing behvaiour is happening and that is I read in the ISBN as the first token, copy it into my book.isbn property and then read the next token and copy it into my book.title.
When I print out book.isbn before and after the title token, i notice that the title was added to both book.isbn and book.title . Why is that so? I never mentioned book.isbn anymore. Whats still pointing at it
while (fgets(line, STRING_LENGTH, file) != NULL)
{
Book book;
// Grabbing ISBN
char *bookToken = strtok(line, ",");
strcpy(book.isbn, bookToken);
printf("%s\n", book.isbn);
// Grabbing Title
bookToken = strtok(NULL, ",");
strcpy(book.title, bookToken);
printf("%s\n", book.isbn);
// Grabbing Author
bookToken = strtok(NULL, ",");
strcpy(book.author, bookToken);
The output
9780136019701
9780136019701An Introduction to Organic Chemistry
9781506304212
9781506304212Mathematics for Social Scientists
9781506304213
9781506304213Discrete Mathematics
9780136019702
9780136019702Chemotherapy
Why is it concatenating my title to my book.isbn ?? Also my book.isbn is char isbn[13] so how is it allocating this memory.
I should also say that all my other properties are stored correctly and non of this happens with anything else

Literally after posting i realized my mistake. I was not giving it enough space by only using isbn[13], i now realize it should be isbn[14]

Related

strcmp fails when comparing two words that are supposed to be the same

So I have a list of words, let's call them
words = {"red", "blue", "yellow", "green", "orange"}
and then I have a string that I read from stdin, I parse this string using the following code
char *token;
token = strtok(string," ");
then I compare the new token to the list of words in a for loop using
strcmp(token,words[i]);
Now this only works if my input is followed by at least a space, for example,
"blue hello" or "blue ", will evaluate to the words matching since token will equal "blue" but if my input is just "blue" the token is "" and I cannot compare the two.
Now my workaround included running isblank() on the string and only using stroke if there was a empty space in the string and if there wasn't an empty space then I just compare the string itself since I know its only one word using the following
strcmp(string, words[I])
but this also results in strcmp failing and not being able to compare the two string together. I don't really know where else to go with this but if someone could maybe see my mistake in my explanation then I would greatly appreciate being corrected and shown my mistakes. I would love to post more code but this has to do with school so I cannot post more within possibly getting into trouble. If you would like more of an explanation I would be happy to explain more.
If you are reading from stdin with fgets, then most probably a new line is
in stored in your string variable.
You can clear the newline with
string[strcspn(string, "\n")] = 0;
after the fgets or you can add \n to the list of delimiters when using
strtok:
char *token;
token = strtok(string, " \n");
strtok would in this case use an empty space and the new line as
delimiters, thus the newline does not appear in token.

array indexing with signed number in C [duplicate]

This question already has answers here:
Are negative array indexes allowed in C?
(9 answers)
Closed 5 years ago.
I just want to know is it a good way of programming style.
I know what is happening in this piece of code. look for the first occurrence of href save it next_next and then look for the first occurrence of "}" and save it end_marker.
Here my question is end_marker[-1] = '\0'; is needed? Because strstr, upon successful completion, strstr() shall return a pointer to the located string or a null pointer if the string is not found.
I know the endmarker '\0' is for string but don't know is it good to index the array in the negative number?
Code:
char *end_marker;
char *next_next = strstr(links_ptr, "href");
if (next_next != NULL) {
next_next += 7;
end_marker= strstr(next_next, "}");
end_marker[-1] = '\0'; // :)
}
EDIT: links_ptr contains this data
"links": [
{
"rel": "next",
"href": "https://www.randomstuff.com/blabla"
}
]
This usage of strstr assumes much about the input. Given input it doesn't expect, it can scan memory out of the string bounds, write to bad addresses, or try to dereference a null pointer.
If links_ptr is different - if it's part of user input or data downloaded on the internet - then it's a definite bug and security issue.
next_next += 7 assumes that strlen(next_next) >= 7. If the string is shorter you'll be scanning memory that doesn't belong to the string until the first '\0' or '}' is found.
if the previous scan finds '}' it will write '\0' to an unrelated address
if '}' isn't found, end_marker will be NULL and end_marker[-1] should crash
In C/C++, there's nothing evil in using a negative array index. In this way you are addressing the slot BEFORE the pointer represented by end_marker. However, you need to ensure that there's valid memory at this address.
In this case it would be undefined behaviour, you should do
if (end_marker != NULL)
{
end_marker[strlen(end_marker) - 1] = '\0';
}
Using negative number isnt good practice and you should do it.
To do it you have to be sure there is still this array.

Mystery about strtok() function [duplicate]

This question already has answers here:
How does strtok() split the string into tokens in C?
(16 answers)
Closed 6 years ago.
Sorry for probably a stupid question but, after reading a considerably amount of examples I still don't understand how strtok() works.
Here is example:
char s[] = " 1 2 3"; // 3 spaces before 1
int count = 0;
char* token = strtok(s, " ");
while (token != NULL) {
count++;
token = strtok(NULL, " ");
}
After executing count equals 3. Why?
Please explain I've given detailed steps of what happens inside the call to that function.
Because:
http://man7.org/linux/man-pages/man3/strtok.3.html
From the above description, it follows that a sequence of two or more
contiguous delimiter bytes in the parsed string is considered to be a
single delimiter, and that delimiter bytes at the start or end of the
string are ignored.
You could also have print the consecutive tokens.
Output for me:
1
2
3
It is C, but C++ reference has a nice example: http://www.cplusplus.com/reference/cstring/strtok/
char s[] once initialized, points to a memory location with data: 1 2 3.
First call to strtok, with delimiter a single space, advances the pointer to point to further memory loaction, now with just: 1 2 3. Further calls increase the pointer, to point to locations of consecutive tokens.
Note: think of strtok() as a tokenizer function, iterating forward by the valid tokens. Also, printing out the current value of pch may help to understand it better (or use a debugger).

Parsing file to struct in C [duplicate]

This question already has an answer here:
fscanf with colon (:) delimited data
(1 answer)
Closed 7 years ago.
I have a file with questions and answers formatted like this:
1;Which US state is famous for Disneyland and the film industry?;California;Washington;Florida;
The number(which is 1 in this case) tells us how many questions the file contains.
I have a struct:
typedef struct{
char answer1[30];
char answer2[30];
char answer3[30];
char question[30];
}Questions;
I'll use a loop to scan in the text to the struct, something like this:
Questions q;
for(int i = 0; i < number;i++){
fscanf(file, ";%s; %s; %s; %s;", q.question, q.anwswer1, q.answer2, q.answer3);
}
The problem is that the question and answers in the file is separated with ";", how can I scan in the values in the file to the struct?
Take the following steps for each line of input:
use fgets with a large enough buffer to read a line from the input file. Check for a NULL return value to detect end of file.
parse the line with strchr, strtok or by testing for ';' explicitly with a for loop.
for each element, change the ';' separator to a '\0' and use strdup() to make a copy of the field value and store the pointer to the corresponding member of your structure.
use the Question structure for what it is needed, and free the pointers when it is no longer needed,
repeat for the next line.

Separating a single string into two different strings in C [duplicate]

This question already has answers here:
Split string with delimiters in C
(25 answers)
Closed 9 years ago.
I take user input in char name[20] using fgets like this:
fgets(name,20,stdin);
The user enters two strings separated by white space like John Smith. What if I wanted to use John and Smith in two strings like char name[20] , char surname[20] or just compare John and Smith using strcmp?
I tried a lot, but I did not find any way to do this.
What are some ways to fix this kind of problem?
You need to learn char * strtok (char *restrict newstring, const char *restrict delimiters) function in C uses to splitting a string up into token separated by set of delimiters.
You input string John Smith is separated by space (' ') char. You need to write a code something like below:
char *token;
token = strtok(name, " "); // first name
strcpy(fname, token);
token = strtok(NULL, " "); // second name
strcpy(lname, token);
You will need to search for the blank within the string yourself - look up the strchr function for that. Then, use strncpy to copy the two parts in 2 different strings.
Use the strtok function to split strings.

Resources