fscanf changes string variable? - c

I'm a beginner in programming and I'm currently learning C, but I've come across something that confuses me.
In my while loop i have:
char* bword = word
fscanf(fp, "%s", word);
Where word is a char[46], bword is a char* and fp is the file (a word dictionary in this case). I wanted to keep track of the word before it gets replaced when scanning fp. And it seemed logical to me to asign the word to a variable before it gets changed. But if I print bword after fscanf(fp, '%s", word) then it's changed to the new word! I don't really understand why and how.
If I do this:
bword = word;
printf("1.%s\n", word);
printf("2.%s\n", bword);
// scan the file for a for a word and store in word
fscanf(fp, "%s", word);
printf("3.%s\n", word);
printf("4.%s\n", bword);
I get these results in the command line:
1.
2.
3.a
4.a
(You don't see anything before 1 and 2 because the word was empty at the time).
I also tried assigning word to something "bar" before the loop but then I got:
1.bar
2.bar
3.a
4.a
So how do I solve this? I don't want bword to change.

You need to understand that this
char *bword = word;
declares a pointer to the first element of the array word, which means that modifiying bword modifies word too, because bword is just a reference1 to the real data location which is the array word
If you want bword and word to be independent of each other then make bword an array so it's stored in a different location, like this
char bword[SOME_REASONABLE_SIZE];
from here you can call fscanf() and pass the appropriate array and the result will be the one you expected before.
Notice, that when you pass the array to fscanf(), essentially you are passing a pointer to the first element of it, just what your bword was in the first place.
1A reference in a general sense, not in c++ sense.

First you must learn about pointers (you can see tutorialspoint).
Then you find out array is a pointer to a memory so when you assigning them you just assign addresses so if one of them change other one is also changed. if you want to copy strings you can not assign then you must copy them and you can use strcpy() function. as it man page says it have following syntax:
char *strcpy(char *dest, const char *src);
The strcpy() function copies the string pointed to by src, including the terminating null byte ('\0'), to the buffer pointed to by dest. The strings may not overlap, and the destination string dest must be large enough to receive the copy. Beware of buffer overruns!

Related

\n is not substituted using strtok

I am trying to use the C's strtok function in order to process a char* and print it in a display, and looks like that for some reason I don't know the character '\n' is not substituted by '\0' as I believe strtok does. The code is as follows:
-Declaration of char* and pass to the function where it will be processed:
char *string_to_write = "Some text\nSome other text\nNewtext";
malloc(sizeof string_to_write);
screen_write(string_to_write,ALIGN_LEFT_TOP,I2C0);
-Processing of char* in function:
void screen_write(char *string_to_write,short alignment,short I2C)
{
char *stw;
stw = string_to_write;
char* text_to_send;
text_to_send=strtok(stw,"\n");
while(text_to_send != NULL)
{
write_text(text_to_send,I2C);
text_to_send=strtok(NULL, "\n");
}
}
When applying the code, the result can be seen in imgur (Sorry, I am having problems with format adding the image here in the post), where it can be seen that the \n is not substituted as it is the strange character appearing in the image, and the debugger still showed the character as well. Any hints of where can the problem be?
Thanks for your help,
Javier
strtok expects to be able to mutate the string you pass it: instead of allocating new memory for each token, it puts \0 characters into the string at token boundaries, then returns a series of pointers into that string.
But in this case, your string is immutable: it's a constant stored in your program, and can't be changed. So strtok is doing its best: it's returning indices into the string for each token's starting point, but it can't insert the \0s to mark the ends. Your device can't handle \ns in the way you'd expect, so it displays them with that error character instead. (Which is presumably why you're using this code in the first place.)
The key is to pass in only mutable strings. To define a mutable string with a literal value, you need char my_string[] = "..."; rather than char* my_string = "...". In the latter case, it just gives you a pointer to some constant memory; in the former case, it actually makes an array for you to use. Alternately, you can use strlen to find out how long the string is, malloc some memory for it, then strcpy it over.
P.S. I'm concerned by your malloc: you're not saving the memory it gives you anywhere, and you're not doing anything with it. Be sure you know what you're doing before working with dynamic memory allocation! C is not friendly about that, and it's easy to start leaking without realizing it.
1.
malloc(sizeof string_to_write); - it allocates the sizeof(char *) bytes not as many bytes as your string needs. You also do not assign the allocated block to anything
2.
char *string_to_write = "Some text\nSome other text\nNewtext";
char *ptr;
ptr = malloc(strlen(string_to_write) + 1);
strcpy(ptr, string_to_write);
screen_write(ptr,ALIGN_LEFT_TOP,I2C0);

Segmentation fault of small code

I am trying to test something and I made a small test file to do so. The code is:
void main(){
int i = 0;
char array1 [3];
array1[0] = 'a';
array1[1] = 'b';
array1[2] = 'c';
printf("%s", array1[i+1]);
printf("%d", i);
}
I receive a segmentation error when I compile and try to run. Please let me know what my issue is.
Please let me know what my issue is. ? firstly char array1[3]; is not null terminated as there is no enough space to put '\0' at the end of array1. To avoid this undefined behavior increase the size of array1.
Secondly, array1[i+1] is a single char not string, so use %c instead of %s as
printf("%c", array1[i+1]);
I suggest you get yourself a good book/video series on C. It's not a language that's fun to pick up out of the blue.
Regardless, your problem here is that you haven't formed a correct string. In C, a string is a pointer to the start of a contiguous region of memory that happens to be filled with characters. There is no data whatsoever stored about it's size or any other characteristics. Only where it starts and what it is. Therefore you must provide information as to when the string ends explicitly. This is done by having the very last character in a string be set to the so called null character (in C represented by the escape sequence '\0'.
This implies that any string must be one character longer than the content you want it to hold. You should also never be setting up a string manually like this. Use a library function like strlcpy to do it. It will automatically add in a null character, even if your array is too small (by truncating the string). Alternatively you can statically create a literal string like this:
char array[] = "abc";
It will automatically be null terminated and be of size 4.
Strings need to have a NUL terminator, and you don't have one, nor is there room for one.
The solution is to add one more character:
char array1[4];
// ...
array1[3] = 0;
Also you're asking to print a string but supplying a character instead. You need to supply the whole buffer:
printf("%s", array1);
Then you're fine.
Spend the time to learn about how C strings work, in particular about the requirement for the terminator, as buffer overflow bugs are no joke.
When printf sees a "%s" specifier in the formatting string, it expects a char* as the corresponding argument, but you passed a char value of the array1[i+1] expression. That char got promoted to int but that is still incompatible with char *, And even if it was it has no chance to be a valid pointer to any meaningful character string...

C - Splitting C-String into words without reallocating memory

I'm trying to split a string (const char*) into words and saving the individual words in an array of char-pointer (char**).
My problem is not the splitting part but that I'm not allowed to allocate any memory. I need to use the input string as my memory, but since its a const char* I'm not able to modify it.
My thirst thought was to change all whitespaces into '\0' and save the position of the beginning of the words in the array, which of course is not possible since the input string is const.
The declaration of the function looks like this:
int breakIntoWords(const char *line, int maxWords, char** words);
The function returns the number of words in line and maxWords is the size of the word-array.
Everything I found either used arrays as input strings or allocated memory with malloc.
There is no solution to the problem as posed. You can obtain a pointer to the start of each word, but in order to use the source string as the storage for separate word strings you must modify it by replacing delimiters with string terminators, as you considered doing.
If the task indeed supposes that you will alter the input line to use it for storage of several separate strings, then it seems that it is inherently incorrect for the function's line parameter to be const-qualified. Such qualification is inconsistent with the job the function is supposed to perform. Moreover, if you are supposed to assign pointers into the string pointed to by line into words, then the fact that words is not const-qualified also presents a conflict.
The only plausible solution I see to the problem described is to remove the const qualifier from your line parameter.

How can i copy part of a string to another variable?

Hi i am trying to figure out how to copy only part of a line being read from a text file. I want to copy a line from a file called fileLine to a variable called line. The problem is, is that i only want to copy starting at index 10 in fileLine but memcpy dislikes that. How can i change this to make memcpy happy?
int stringLength = 0;
stringLength = strlen(fileLine);
memcpy(line, fileLine[10], stringLength); //this is where things go wrong.
You have passed in a char type to something that expected a const void*. This would have been okay if you had passed it a char*. You can do that as either &fileLine[10] or fileLine + 10.
Since you are offsetting by 10, you also want to ensure you copy 10 fewer characters:
memcpy(line, &fileLine[10], stringLength-10);
Although you probably want to copy the string terminator too...
memcpy(line, &fileLine[10], stringLength-9);
Yuck!
Instead, you could use strcpy:
strcpy(line, fileLine + 10);
In all cases, make sure that line is an array or a pointer to memory that is actually allocated to your process.
You can use getline function to get part of the string. But first, you have to move your read pointer to the position from which you want to read using seekg function.
seekg(ios flag, bytes);
cin.getline(source, number of characters, ending character);

Reduce string length in c, where is the fault?

i have two different filenames, which are defined in a header file:
1: "physio_sensor_readout.csv"
2: "statethresh_configuration.csv"
they are initialised by
char* filename;
and later
filename = FILENAMEINAMACRO; which is the corresponding filename above
Later, filename is passed to another function which alters the ending:
filename[strnlen(filename, FILENAME_LENGTH) - 4] = '\0';
This should remove the ending .csv and i strncat a new one afterwards.
FILENAME_LENGTH is 60, so enough space.
It works if i pass "statetresh_...."(even the strncat afterwards) but not with "physio_se.....". This throws a segment fault
strnlen(filename,FILENAME_LENGTH - 4)
returns 21 in case 1 and 25 in case 2. this is the correct position of the dot, where i want to put the terminating null.
Is this a problem with char* and should i initialise filename with char filename[60]?
Regards and thank you
edit:
your suggestions solved the problem. thanks!
I think you declare FILENAMEINAMACRO as string literal [Without more code I cannot be sure about it].
string literals might be saved on read only memory - so you might not be able to change them.
In any way, trying to change string literals results in undefined behavior.
You might want to make a copy of FILENAMEINAMACRO and work on it using strcpy()
It is not safe to modify the contents of a character literal. Something like this:
char *filename = "yes";
filename[2] = 'p'; // change to "yep"
is undefined behavior, and can cause disastrous results, because filename can be pointing to memory that can't be modified. Instead, try something like this:
char filename[] = "yes";
filename[2] = 'p'; // change to "yep"
which will allocate a new array filename and initialize its contents with "yes".
You are appear to be pointing your char* pointer filename at a character constant. I assume you have defined #define FILENAMEINAMACRO "physio_sensor_readout.csv". This makes your assignment filename = "physio_sensor_readout.csv";. You then use the filename pointer to modify the string constant. Here is a more suitable sequence:
char filename[256]; // choose a size that is suitably large
...
strcpy(filename, FILENAMEINAMACRO); // also look at strncpy for safer copying
...
... manipulate the content of filename as you wish ...
Because you have made a copy of the string literal, modifying it is safe (as long as you stay within the bounds of the declared size of filename -- which includes keeping any terminating null also within the bounds.
You should be careful using the char filename[] = "..." form. It allocates enough space for the string literal you give it, but if later you copying some other string literal into that space you must be certain that the second literal is no longer than the first. A safer practice is to dimension the space to be large enough that you're certain your code will never attempt to use any more than what you have dimensioned. If you accept input from outside the program (or from other person's code), you should check the length of what you are accepting before trying to copy it into the space you have dimensioned. Any use of space beyond the dimensioned size is likely to cause issues that can be hard to diagnose. In the example above, you must make all efforts to ensure you never use more space (including the terminating nul char) than 256 chars (because filename is dimensioned at 200).

Resources