Reduce string length in c, where is the fault? - c

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).

Related

The use of strcat in C overwrites irrelevant strings

The code is as follows:
char seg1[] = "abcdefgh";
char seg2[] = "ijklmnop";
char seg3[] = "qrstuvwx";
strcat(seg2, seg3);
Then the value stored in seg1 will become:
"rstuvwx\0\0"
I have learned to declare that strings with close positions are also adjacent in the stack area, but I forgot the details.
I guess the memory address of seg1 was overwritten when strcat() was executed, but I'm not sure about the specific process. Can someone tell me the specific process of this event?Thanks
C does not have a string class, it has character arrays which may be used as strings by appending a null terminator. And since there is no string class, all memory management of strings/arrays must be done manually.
char seg1[] = "abcdefgh"; Allocates space for exactly 8 characters and 1 null terminator. There is no room to append anything else at the end. If you try anyway, that's the realm of undefined behavior, where anything can happen. Crashes, overwriting other variables, program ceasing to function as expected and so on.
Solve this by allocating enough space to append something in the end, for example
char seg1[50] = "abcdefgh";. Alternatively allocate a new, third array and copy the strings into that one.

best method to assign new string value to char array

I know that I have to use strcpy / strncpy to assign a new string value to an existing char array. Recently I saw a lot of code like this
char arr[128] = "\0";
sprintf(arr, "Hello World"); // only string constants no variable input
// or
sprintf(arr, "%s", "Hello World");
Both variants give the same result. What is the advantage of the latter variant?
It depends on whether the string to be copied is a literal, as shown, or can vary.
The best technique for the array shown would be:
char arr[128] = "Hello World";
If you're in charge of the string and it contains no % symbols, then there's not much difference between the two sprintf() calls. Strictly, the first uses the string as the format and copies the characters directly, while the second notes it has %s as the format and copies the characters from the extra argument directly — it's immeasurably slower. There's a case for:
snprintf(arr, sizeof(arr), "%s", "Hello World");
which ensures no buffer overflow even if "Hello World" becomes a much longer diatribe.
If you're not in charge of the string, then using snprintf() as shown becomes important as even if the string contains % symbols, it is simply copied and there's no overflow. You have to check the return value to establish whether any data was truncated.
Using strcpy() is reasonable if you know how long the string is and that there's space to hold it. Using strncpy() is fraught — it null pads to full length if the source is shorter than the target, and doesn't null terminate if the source is too long for the target.
If you've established the length of the string is short enough, using memmove() or memcpy() is reasonable too. If the string is too long, you have to choose an error handling strategy — truncation or error.
If the trailing (unused) space in the target array must be null bytes (for security reasons, to ensure there's no leftover password hidden in it), then using strncpy() may be sensible — but beware of ensuring null termination if the source is too long. In most cases, the initializer for the array is not really needed.
The compiler may be able to optimize the simple cases.
The first version won't work if the string contains any % characters, because sprintf() will treat them as formatting operators that need to be filled in using additional arguments.. This isn't a problem with a fixed string like Hello World, but if you're getting the string dynamically it could cause undefined behavior because there won't be any arguments to match the formatting operators. This can potentially cause security exploits.
If you're not actually doing any formatting, a better way is to just use strcpy():
strcpy(arr, "Hello World");
Also, when initiallizing the string it's not necessary to put an explicit \0 in the string. A string literal always ends with a null byte. So you can initialize it as:
char arr[128] = "";
And if you're immediately overwriting the variable with sprintf() or strcpy(), you don't need to initialize it in the first place.

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.

Wrong strlen output

I have the following piece of code in C:
char a[55] = "hello";
size_t length = strlen(a);
char b[length];
strncpy(b,a,length);
size_t length2 = strlen(b);
printf("%d\n", length); // output = 5
printf("%d\n", length2); // output = 8
Why is this the case?
it has to be 'b [length +1]'
strlen does not include the null character in the end of c strings.
You never initialized b to anything. Therefore it's contents are undefined. The call to strlen(b) could read beyond the size of b and cause undefined behavior (such as a crash).
b is not initialized: it contains whatever is in your RAM when the program is run.
For the first string a, the length is 5 as it should be "hello" has 5 characters.
For the second string, b you declare it as a string of 5 characters, but you don't initialise it, so it counts the characters until it finds a byte containing the 0 terminator.
UPDATE: the following line was added after I wrote the original answer.
strncpy(b,a,length);
after this addition, the problem is that you declared b of size length, while it should be length + 1 to provision space for the string terminator.
Others have already pointed out that you need to allocate strlen(a)+1 characters for b to be able to hold the whole string.
They've given you a set of parameters to use for strncpy that will (attempt to) cover up the fact that it's not really suitable for the job at hand (or almost any other, truth be told). What you really want is to just use strcpy instead. Also note, however, that as you've allocated it, b is also a local (auto storage class) variable. It's rarely useful to copy a string into a local variable.
Most of the time, if you're copying a string, you need to copy it to dynamically allocated storage -- otherwise, you might as well use the original and skip doing a copy at all. Copying a string into dynamically allocated storage is sufficiently common that many libraries already include a function (typically named strdup) for the purpose. If you're library doesn't have that, it's fairly easy to write one of your own:
char *dupstr(char const *input) {
char *ret = malloc(strlen(input)+1);
if (ret)
strcpy(ret, input);
return ret;
}
[Edit: I've named this dupstr because strdup (along with anything else starting with str is reserved for the implementation.]
Actually char array is not terminated by '\0' so strlen has no way to know where it sh'd stop calculating lenght of string as as
its syntax is int strlen(char *s)-> it returns no. of chars in string till '\0'(NULL char)
so to avoid this this we have to append NULL char (b[length]='\0')
otherwise strlen count char in string passed till NULL counter is encountered

string manipulation without alloc mem in c

I'm wondering if there is another way of getting a sub string without allocating memory. To be more specific, I have a string as:
const char *str = "9|0\" 940 Hello";
Currently I'm getting the 940, which is the sub-string I want as,
char *a = strstr(str,"9|0\" ");
char *b = substr(a+5, 0, 3); // gives me the 940
Where substr is my sub string procedure. The thing is that I don't want to allocate memory for this by calling the sub string procedure.
Is there a much easier way?, perhaps by doing some string manipulation and not alloc mem.
I'll appreciate any feedback.
No, it can't be done. At least, not without modifying the original string and not without departing from the usual C concept of what a string is.
In C, a string is a sequence of characters terminated by a NUL (a \0 character). In order to obtain from "9|0\" 940 Hello" the substring "940", there would have to be a sequence of characters 9, 4, 0, \0 somewhere in memory. Since that sequence of characters does not exist anywhere in your original string, you would have to modify the original string.
The other option would just be to use a pointer into the original string at the place where your desired substring starts, and then also remember how long your substring is supposed to be in lieu of having the terminating \0 character. However, all C standard library functions that work on strings (and pretty much all third party C libraries that work with strings) expect strings to be NUL-terminated, and so won't accept this pointer-and-count format.
Try this:
char *mysubstr(char *dst, const char *src, const char *substr, size_t maxdst) {
... do substr logic, but stick result in dst respecting maxdst ...
}
Basically, punt and let the caller allocate space on the stack via:
char s[100];
Or something.
A C string is simply an array of chars in memory. If you want to access the substring without allocating a copy of the characters, you can simply access it directly:
char *b = a[5];
The problem with this approach is that b will not be null-terminated to the appropriate length. It would essentially be a pointer to the string: "940 hello".
If that doesn't matter to the code that uses b, then you are good to go. Keep in mind, however, that this would probably surprise other programmers later on in the product lifetime (including yourself)!
As xyld, suggested, you could let the caller allocate the memory and pass your substr function a buffer to fill; though, strictly speaking, that still involves "allocating memory".
Without allocating any memory at all, the only way you'd be able to do this would be by modifying the original string by changing the character after the substring to a '\0', but of course then your function couldn't take a const char * anymore, and you're modifying the original string, which may not be desirable.
If you don't require a \0 terminated string you can make a substring finding function that just tells you where in the full string (haystack) your partial string (needle) is. This would be considered a hot-copy or alias as the data could be changed by changes to the full string (haystack).
I was writing up a long thing on how to allocate memory using alloca and implement a macro (because it wouldn't work as a function) that would do what you want, but just happened to run across strndupa which is like strndup except allocates the memory on the stack rather than from the heap. It's a GNU extension, so it might not be available for you.
Writing your own macro that would look like a function because it needs to return a value but also work on the memory, but it is possible.

Resources