Memory issue in my Sub String function in C? - c

I have this C function which attempts to tell me if a sub string is contained in a string.
int sub_string(char parent [1000], char child [1000]){
int i;
i = 0;
int parent_size = (int) strlen(parent);
int child_size = (int) strlen(child);
char tempvar [child_size];
int res;
res = 1;
while(i<(parent_size - child_size + 1) && res != 0){
strncpy(tempvar, parent + i, child_size);
if(strcmp(tempvar, child)==0){
res = 0;
}
i++;
memset(tempvar, 0, child_size);
}
memset(tempvar, 0, sizeof(tempvar));
return res;
}
Now the strange thing is, when I pass a string "HOME_DIR=/tmp/" and "HOME_DIR" it returns a 0 the first time round, but after I call this function again, it returns a 1 to say it hasn't found it!!
I am guessing this is a memory issue, but I can't tell where, I would appreciate any help on this.

Is there any reason you can't use the strstr function? Otherwise there are some things you should clean up in your code. For starters since you are limiting the length of the arrays coming in to 1000 characters you should use strnlen instead of strlen with a limit of 1000. You should also create you should zero out the tempvar array before you start copying into it. If parent is not null terminated you could run off the end of the array in your while loop. I would also suggest using strncmp and giving a length limit (in general if you are using the C string library you should use the 'n' version of the functions i.e. strnlen instead of strlen so that you put a bounding length on the operation, this helps to protect buffer overflows and potential security holes in your code).

I have noticed some issues with this program:
Use pointers instead of fixed char arrays. This is more space optimal. So your function definition becomes int sub_string(char *parent, int parent_len, char *child, int child_len). Please note that since I pass pointers I also need to pass the length of the string so I know how much to traverse. So now you access your string like so *(parent+i) in a loop.
i<(parent_size - child_size + 1) This condition looks a bit dicey to me. Let's say parent is 100 in len & child is 75. so this expression becomes i<26. Now your loop will terminate when i>26. So tempvar would have the parent_string till index 25. So how does this work again?

One problem is:
char tempvar [child_size];
strcmp below will compare child_size+1 characters (incl. terminating '\0'), therefore its undefined behaviour.
Do you know the C-standard functions strstr and strncmp?

sizeof(tempvar) does not return child_size.

Related

malloc() into a recursive function that modifies a string

THE CODE:
The aim of this code is to take a string of 0 1 and * and print all the combinations of strings obtained replacing * with 0 or 1.
Ex.
input : 0*1 => output: 001 011
the idea is to build a recursive function (for practice purposes):
void rec_print (char *mod_str)
which counts the occurrences of *, the offset of the first * encountered while looping the string (I have used ternary just to practice them)
for(int i=0; mod_str[i]; i++) {
n_star = (mod_str[i] == '*') ? n_star+1 : n_star;
if (offset==-1) {
offset = (mod_str[i] == '*') ? i : -1;
}
}
The base case occurs when there is only one *, in which case replaces * with 0, prints the string, replace the 0 with a 1, and finally prints the string:
if (n_star==1) {
mod_str[offset] = "0";
printf("\n%s", mod_str);
mod_str[offset] = "1";
printf("\n%s", mod_str);
}
otherwise modifies the first * of the string to a 0 then call itself, then modify it to a 1 when it comes back, and finally call itself:
else {
// replace the first encountered * to 0 and recall itself
mod_str[offset] = "0";
rec_print(mod_str);
// replace the previous 0 to 1 and recall itself
mod_str[offset] = "1";
rec_print(mod_str);
}
THE ISSUE:
as you will notice here the problem is that I am trying to modify a string which memory is read-only (yes, I have a huge "Python bias" here), normally I would use a malloc() to resolve this but I can't figure out how to use it inside a function to modify a string.
I am well aware recursion is not the best solution to this exercise but I need to satisfy my curiosity about this.
I thank everyone for the time spent here and apologize for my eventual English mistakes in advance.
The base case occurs when there is only one *, in which case replaces * with 0, prints the string, replace the 0 with a 1, and finally prints the string:
This base case isn't really "base." For example, you could receive the string "001" as input, which contains zero stars. You should modify your base case to handle only zero stars, and rely on your recursive case to simplify the case with one star to zero stars.
as you will notice here the problem is that I am trying to modify a string which memory is read-only
If the memory is read-only, you should clarify that fact to the compiler! Then the compiler can check your code to make sure it never writes to a read-only variable.
Example:
void rec_print (const char *mod_str)
as you will notice here the problem is that I am trying to modify a string which memory is read-only (yes, I have a huge "Python bias" here), normally I would use a malloc() to resolve this but I can't figure out how to use it inside a function to modify a string.
You need to copy the string to a place where you can modify it. Here's an example:
void rec_print (const char *src_str) { // note name change
// Allocate memory
char *mod_str = malloc((strlen(src_str) + 1) * sizeof(char));
// This function copies src_str to mod_str
strcpy(mod_str, src_str);
// Rest of function
...
// Clean up memory used
free(mod_str);
}
Here we allocate enough memory to hold the input string. Then, we copy the input string to the space we allocated. We can do all modifications on this copy. At the end we free the allocation.

Using snprintf to print an array? Alternatives?

Is it at all possible to use snprintf to print an array? I know that it can take multiple arguments, and it expects at least as many as your formatting string suggests, but if I just give it 1 formatting string and an array of values, will it print the entire array to the buffer?
The reason I ask, is because I am modifying source code, and the current implementation only supported one value being placed in a string, but I am modifying it to support an array of values. I want to change the original implementation as little as possible.
If this doesn't work, is there another way someone would recommend to do this? Should I just suck it up and use a for loop (how well would that really work without stringbuffers)?
Essentially: What would be the best way to get all of the values from an array of doubles into the same string for a return?
No, there's no formatting specifier for that.
Sure, use a loop. You can use snprintf() to print each double after the one before it, so you never need to copy the strings around:
double a[] = { 1, 2, 3 };
char outbuf[128], *put = outbuf;
for(int = 0; i < sizeof a / sizeof *a; ++i)
{
put += snprintf(put, sizeof outbuf - (put - outbuf), "%f ", a[i]);
}
The above is untested, but you get the general idea. It separates each number with a single space, and also emits a trailing space which might be annoying.
It does not do a lot to protect itself against buffer overflow, generally for code like this you can know the range of the inputs and make sure the outbuf is big enough. For production code you would need to think about this of course, the point here is to show how to solve the core problem.
I decided to go with this:
int ptr = 0;
for( i = 0; i < size; i++)
{
ptr += snprintf(outbuf + ptr, sizeof(outbuf) - ptr, "%.15f ", values[i]);
}
slightly different, but to the same effect as in #unwind 's solution. I got this idea from the reference page for snprintf()

How to write into a char array in C at specific location using sprintf?

I am trying to port some code written in MATLAB to C, so that I can compile the function and execute it faster (the code is executed very often and it would bring a significant speed increase).
So basically what my MATLAB code does it that it takes a matrix and converts it to a string, adding brackets and commas, so I can write it to a text file. Here's an idea of how this would work for a vector MyVec:
MyVec = rand(1,5);
NbVal = length(MyVec)
VarValueAsText = blanks(2 + NbVal*30 + (NbVal-1));
VarValueAsText([1 end]) = '[]';
VarValueAsText(1 + 31*(1:NbVal-1)) = ',';
for i = 1:NbVal
VarValueAsText(1+(i-1)*31+(1:30)) = sprintf('%30.15f', MyVec(i));
end
Now, how can I achieve a similar result in C? It doesn't seem too difficult, since I can calculate in advance the size of my string (char array) and I know the position of each element that I need to write to my memory area. Also the sprintf function exists in C. However, I have trouble understanding how to set this up, also because I don't have an environment where I can learn easily by trial and error (for each attempt I have to recompile, which often leads to a segmentation fault and MATLAB crashing...).
I hope someone can help even though the problem will probably seem trivial, but I have have very little experience with C and I haven't been able to find an appropriate example to start from...
Given an offset (in bytes) into a string, retrieving a pointer to this offset is done simply with:
char *ptr = &string[offset];
If you are iterating through the lines of your matrix to print them, your loop might look as follow:
char *ptr = output_buffer;
for (i = 0; i < n_lines; i++) {
sprintf (ptr, "...", ...);
ptr = &ptr[line_length];
}
Be sure that you have allocated enough memory for your output buffer though.
Remember that sprintf will put a string-terminator at the end of the string it prints, so if the string you "print" into should be longer than the string you print, then that won't work.
So if you just want to overwrite part of the string, you should probably use sprintf to a temporary buffer, and then use memcpy to copy that buffer into the actual string. Something like this:
char temp[32];
sprintf(temp, "...", ...);
memcpy(&destination[position], temp, strlen(temp));

STM32 printf and RTC

* UPDATE *
Here is what I found. Whenever I had that function in there it wouldn't actually make the code lock up. It would actually make the read RTC I²C function very slow to execute, but the code would still run properly, but I had to wait a really long time to get past every time I read the RTC.
So there is an alarm interrupt for the RTC and this was triggering other I²C interactions inside the ISR, so it looks like it was trying to do two I²C communications at the same time, therefore slowing down the process. I removed the functions in the ISR and it's working now. I will keep investigating.
I am having this problem when programming an STM32F103 microcontroller using IAR 5.40. I have this function that if I try to printf a local variable it causes the code to freeze at another point way before it even gets to that function in question.
What could possibly be causing this?
This is the function:
u8 GSM_Telit_ReadSms(u8 bSmsIndex)
{
char bTmpSms[3] = {0};
itoa(bSmsIndex, bTmpSms, 10); // Converts the smsindex into a string
printf("index = %s\n", bTmpSms); // This printf caused the code to get stuck in the RTC // byte read function!
GSM_Telit_RequestModem("AT+CMGR=""1", 10, "CMGR", 5, 0);
return 1;
}
I tried this as well and this does not cause the lock I experienced:
u8 GSM_Telit_ReadSms(u8 bSmsIndex)
{
char bTmpSms[3] = {0};
itoa(bSmsIndex, bTmpSms, 10);
printf("index = 2\n");
GSM_Telit_RequestModem("AT+CMGR=""1", 10, "CMGR", 5, 0);
return 1;
}
There is no optimization enabled whatsoever and the code gets stuck when trying to read a byte out of my I²C RTC, but as soon as I remove this printf("index = %s\n", bTmpSms); or use this one instead printf("index = 2\n"); then everything is happy. Any ideas?
The bSmsIndex will never be more than 30 actually and even then the lock up happens wayyyy before this function gets called.
char bTmpSms[3] only has space for "99". If your bSmsIndex is 100 or greater, you will be trying to write to memory that doesn't belong to you.
Edit after the update
I don't have a reference to itoa on my local machine, but I found this one ( http://www.cplusplus.com/reference/clibrary/cstdlib/itoa/ ). According to that reference, the destination array MUST BE LONG ENOUGH FOR ANY POSSIBLE VALUE. Check your documentation: your specific itoa might be different.
Or use sprintf, snprintf, or some function described by the Standard.
Some ideas:
If itoa() is not properly NUL-terminating the string, then the call to printf may result in the machine looking for the NUL forever.
pmg has a very good point.
Also, consider what type the first argument to itoa() is. If it's signed and you're passing in an unsigned integer, then you may be getting an unexpected minus sign in bTmpSms. Try using sprintf() instead.
The change in code is moving the rest of your code around in memory. My guess is that some other part of the code, not listed here, is bashing some random location; in the first case that location contains something critical, in the second case it does not.
These are the worst kinds of problems to track down*. Good luck.
*Maybe not the worst - it could be worse if it were a race condition between multiple threads that only manifested itself once a week. Still not my favorite kind of bug.
It seems that if I don't initialize the variable bTmpSms to something the problem occurs.
I also realized that it is not the printf that is the problem. It is the itoa function. It got me to check that even though I didn't think that was the problem, when I commented the itoa function then the whole code worked.
So I ended up doing this:
u8 GSM_Telit_ReadSms(u8 bSmsIndex)
{
char bTmpSms[4] = "aaa"; // I still need to find out why this is !!!
itoa(bSmsIndex, bTmpSms, 10); // Converts the smsindex into a string
printf("index = %s\n", bTmpSms); // This printf caused the code to get stuck in the RTC // byte read function!
GSM_Telit_RequestModem("AT+CMGR=""1", 10, "CMGR", 5, 0);
return 1;
}
This is the itoa function I got:
char itoa(int value, char* result, int base)
{
// Check that the base if valid
if (base < 2 || base > 36) {
*result = '\0';
return 0;
}
char* ptr = result, *ptr1 = result, tmp_char;
int tmp_value;
do
{
tmp_value = value;
value /= base;
*ptr++ = "zyxwvutsr
qponmlkjihgfedcba9876543210123456789abcdefghijklmnopqrstuvwxyz" [35 + (tmp_value - value * base)];
} while (value);
// Apply negative sign
if (tmp_value < 0)
*ptr++ = '-';
*ptr-- = '\0';
while(ptr1 < ptr)
{
tmp_char = *ptr;
*ptr--= *ptr1;
*ptr1++ = tmp_char;
}
return 1;
}
What's the value of bSmsIndex you're trying to print?
If it's greater than 99 then you're overrunning the bTmpSms array.
If that doesn't help, then use IAR's pretty good debugger - I'd drop into the assembly window at the point where printf() is being called and single step until things went into the weeds. That'll probably make clear what the problem is.
Or as a quick-n-dirty troubleshoot, try sizing the array to something large (maybe 8) and see what happens.
What's the value of bSmsIndex?
If more than 99 it will be three digits when converted to a string. When zero terminated, it will be four characters, but you've allocated only three to bTmpSms so the null may get overwritten and the printf will try to print whatever is after bTmpSms until the next null. That could access anything, really.
Try to disassemble this area with index = 2 vs. index = %s.

How do we know that a string element in C is uninitialized?

Is there a way to know whether the element in a string in C has a value or not? I have tried using NULL, '', and ' ', but they don't seem to be working. I need to shift the characters down to index 0 without using stdlib functions.
#include <stdio.h>
int main()
{
char literal[100];
//literal[99] = '\0'
literal[98] = 'O';
literal[97] = 'L';
literal[96] = 'L';
literal[95] = 'E';
literal[94] = 'H';
int index = 0;
while(literal[index] != '\0')
{
if(literal[index] == NULL) // does not work
printf("Empty");
else
printf("%c", literal[index]);
++index;
}
getchar();
return 0;
}
No. Since literal has automatic storage, its elements will not be initialized, the values in the array is undefined.
You could initialize every element to something special and check for that value.
e.g. you could change
char literal[100];
char literal[100] = {0};
to initialize every element to 0.
You'd have to change your while loop termination check to
while(index < 100) {
if(literal[index] == 0)
printf("Empty");
...
}
}
That might not be optimal if you need to perform more string manipulation on the array though, as 0 now means empty element and also 'end of string'.
No, you can't do that. This is because it will have a value - there is just no way of knowing what that value is. This is why it is essential to initialise things to known values.
C does not default initialize anything. Therefore the contents in your string are whatever garbage was in that memory by whatever last used it on the stack. You need to explicitly set each literal value to a value that means "unset" to you.
No, there is no way of knowing what value the array has. You can, however, initialize it with a chosen "default" value of your choice and later check against that.
You need to set the end of the string to 0 (zero) or '\0' - C only does this for you automatically for string literals, not local variables on the stack
Try
memset(&literal, 0, 100);
Or just uncomment your line that sets literal at index 99 to '\0'
A c string is just a bunch of memory locations and a convention that '\0' marks the end. There is no compiler enforcement, and no attached meta data (unless you build a structure to provide it).
Every cell in memory, always has a value, so every string always has a value, you just can't guarantee that it is sensible or even that it ends in the allotted space.
Insuring that there is meaningful data in there is your responsibility, which suggests that you should initialize all strings either at declaration time or immediately after allocation. Exception to the rule are rare and are undertaken at your own risk.
No, that is undefined behaviour as the runtime, for all we care could shove in a few binary ASCII characters, you really do not want to get into that. The best way to deal with it is to use a for loop and iterate through it or use calloc which initializes a pointer but sets it to 0.
for (i = 0; i < 100; i++) literal[i] = '\0';
OR
char *literalPtr = (char*)calloc(100, sizeof(char)); // Array of 99 elements plus 1 for '\0'
There is absolutely no guarantee in doing that. Hence it would be classified as undefined behaviour as it is dependent on the compiler and runtime implementation.
Hope this helps,
Best regards,
Tom.

Resources