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.
Related
as far as I'm concerned, strncat enlarges the size of the array you want to cat.
for example:
char str1[] = "This is str1";
char str2[] = "This is str2";
and here the length of str1 is 12 and str2 is also 12, but when I strncat them, str1 changes from 12 to 24.
I was asked to write strncat by my own, but I can't figure out how to enlarge the size of an array, taking in account that we didn't learn pointers yet.
I tried just putting every char in the end of the array while moving the distance by 1 each iteration, but as you would have thought, it doesn't put the data in the array because there is no such position like this in the array (str[20] when str's length is 10 for example).
Thanks in advance,
every help would be appreciated.
strlen returns the length of the string, that is, counts until the first null character. It does NOT return the size of the memory allocated for str1!
When you concatenatestr2 to str1, you write beyond the memory allocated for str1. That will cause undefined behavior. In your particular case, it seems nothing happens and it even seems that str1 has become larger. That is not so. However (in your paticular case), if str2 follows str1 in memory, you just overwrote str2. Try printing str2. It will probaby print his is str2.
Since strcat() et al. does not enlarge a buffer, your implementation does not have to do it. (And it is simply not possible with the parameter list of strcat().) It is the caller's responsibility to pass a destination buffer big enough.
On the caller's side you can simply create an array big enough and pass its address. However, you can still use variable length arrays (VLA):
char str1[] = "This is str1";
char str2[] = "This is str2";
char str1str2[strlen(str1)+strlen(str2)+1];
strcpy( str1str2, str1 );
yourstrcat( str1str2, str2 );
str1str2 is big enough to store both contents plus 1 for the string terminator \0.
Thanks for everyone, I solved the problem. As some of you said, I don't need to enlarge the string, I just need to make sure it's big enough to contain all the data.
what I did eventually is this:
void strnCat(char dest[], char src[], int length)
{
int i = 0;
int len = strlen(dest);
for(i=0; i < length; i++)
{
dest[len+i] = src[i];
dest[len+i+1] = 0;
}
}
so my main problem was that I forget to add the null at the end of the array to make it a string and that I used strlen(str) instead of saving the length in a variable. I did that because I forgot that there is no end of the string after the null disappears.
It is a really strange task to let students implement strncat, since this is one of the C functions that is very difficult to use correctly.
So to implement it yourself, you should read its specification in the C standard or in the POSIX standard. There you will find that strncat doesn't enlarge any array. By the way, arrays cannot be enlarged in C at all, it's impossible by definition. Note the careful distinction between the words array (can contain arbitrary bytes) and string (must contain one null byte) in the standard wording.
A saner alternative to implement is strlcat, which is not in the C standard but also widely known.
I have 2 questions..
is it necessary to add a termination character when executing the following commands against a char *string ?
strcpy();
strncpy();
Is it necessary to allocate memory before before doing any operation with the above to function against the char *string ?
for example..
char *str;
str = malloc(strlen(texttocopy));
strcpy(texttocopy, str); // see the below edit
Please explain.
EDIT :
in the above code I inverted the argument. it is just typo i made while asking the question here. The correct way should be
strcpy(str, texttocopy); // :)
The strcpy function always adds the terminator, but strncpy may not do it in some cases.
And for the second question, yes you need to make sure there is enough memory allocated for the destination. In your example you have not allocated enough memory, and will have a buffer overflow. Remember that strlen returns the length of the string without counting the terminator. You also have inverted the arguments to strcpy, the destination is the first argument.
'strcpy' function copies data from source to destination address including with '\0' termination character . 'strncpy' function copies data as the same way but if there is no termination character '\0' exists in the first n bytes to be copied, termination character will not be copied then and you will need to add it by yourself to terminate the string.
You will always have to statically or dynamically allocate a memory space to play with. Therefore, you should declare a character array or dynamically allocate a chunk of memory first then you can play nice with your strings
I'm fairly new to the concept of pointers in C. Let's say I have two variables:
char *arch_file_name;
char *tmp_arch_file_name;
Now, I want to copy the value of arch_file_name to tmp_arch_file_name and add the word "tmp" to the end of it. I'm looking at them as strings, so I have:
strcpy(&tmp_arch_file_name, &arch_file_name);
strcat(tmp_arch_file_name, "tmp");
However, when strcat() is called, both of the variables change and are the same. I want one of them to change and the other to stay intact. I have to use pointers because I use the names later for the fopen(), rename() and delete() functions. How can I achieve this?
What you want is:
strcpy(tmp_arch_file_name, arch_file_name);
strcat(tmp_arch_file_name, "tmp");
You are just copying the pointers (and other random bits until you hit a 0 byte) in the original code, that's why they end up the same.
As shinkou correctly notes, make sure tmp_arch_file_name points to a buffer of sufficient size (it's not clear if you're doing this in your code). Simplest way is to do something like:
char buffer[256];
char* tmp_arch_file_name = buffer;
Before you use pointers, you need to allocate memory. Assuming that arch_file_name is assigned a value already, you should calculate the length of the result string, allocate memory, do strcpy, and then strcat, like this:
char *arch_file_name = "/temp/my.arch";
// Add lengths of the two strings together; add one for the \0 terminator:
char * tmp_arch_file_name = malloc((strlen(arch_file_name)+strlen("tmp")+1)*sizeof(char));
strcpy(tmp_arch_file_name, arch_file_name);
// ^ this and this ^ are pointers already; no ampersands!
strcat(tmp_arch_file_name, "tmp");
// use tmp_arch_file_name, and then...
free(tmp_arch_file_name);
First, you need to make sure those pointers actually point to valid memory. As they are, they're either NULL pointers or arbitrary values, neither of which will work very well:
char *arch_file_name = "somestring";
char tmp_arch_file_name[100]; // or malloc
Then you cpy and cat, but with the pointers, not pointers-to-the-pointers that you currently have:
strcpy (tmp_arch_file_name, arch_file_name); // i.e., no "&" chars
strcat (tmp_arch_file_name, "tmp");
Note that there is no bounds checking going on in this code - the sample doesn't need it since it's clear that all the strings will fit in the allocated buffers.
However, unless you totally control the data, a more robust solution would check sizes before blindly copying or appending. Since it's not directly related to the question, I won't add it in here, but it's something to be aware of.
The & operator is the address-of operator, that is it returns the address of a variable. However using it on a pointer returns the address of where the pointer is stored, not what it points to.
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).
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.