Let's take an example.
#include <stdio.h>
#include <string.h>
int main() {
char str1[7] = "hello ";
printf("Initial size of str1 is: %d\n", strlen(str1));
char str2[] = "buddy";
printf("%s\n", strcat(str1, str2));
printf("Final size: %d\n", strlen(str1));
}
The output of the above program will be
Initial size of str1 is: 6
hello buddy
Final size: 11
--------------------------------
Process exited after 0.835 seconds with return value 0
Press any key to continue . . .
See? how the size of str1 changed from 7 to 11 (including null variable), regarding that what I think would have happened is :
Some function I do not know may have reallocated contiguous memory for str1 starting from same address as before i.e str1 with size strlen(str1)+strlen(str2)+1 +1 for null value, and then redefined it to get hello buddy.
If I am wrong please tell, if not then, what function is it and how does it work?
One more question: how can I write a code to do the above task without the use of strcat function.
I tried doing it using realloc() but didn't quite succeed may be that's because realloc() can only reallocate dynamically allocated memory, is it so?
Buffer overflow
OP's code fails as strcat(str1,str2) attempts to write past the end of str1[] - result: undefined behavior (UB). #dimich
Instead use a larger destination buffer.
// char str1[7]="hello ";
char str1[7 + 5]="hello ";
char str2[]="buddy";
printf("%s\n",strcat(str1,str2));
Use correct print specifier
strlen() returns a size_t, not an int.
// printf("Initial size of str1 is: %d\n",strlen(str1));
printf("Initial size of str1 is: %zu\n",strlen(str1));
Tip: enable all warnings.
Alternative
One of many alternatives: copy str2 to the end of str1.
// printf("%s\n",strcat(str1,str2));
strcpy(str1 + strlen(str1), strt2);
printf("%s\n",str1);
realloc()
realloc() can only reallocate dynamically allocated memory, is it so?
realloc() should not be used on pointers to non-allocated, non-NULL pointers.
In addition to re-allocating dynamically allocated memory, realloc() can start with no prior allocation.
char *p = realloc(NULL, size);
// just like
char *p = malloc(size);
Moral of the story
Be mindful of memory usage with string functions.
Enable all warnings.
You can only reallocate the memory you have dynamically allocated (ie using malloc family functions).
ee? how the size of str1 changed from 7 to 11 (including null
variable), regarding that what I think would have happened is : A
function idk which one, but it may have reallocated contiguous memory
for str1 starting from same address as before i.e str1 with size
strlen(str1)+strlen(str2)+1 +1 for null value, and then redefined it
to get hello buddy. If i am wrong please tell, if not then , what
function is it and how does it work?
You are wrong. It is an example of an Undefined Behaviour. You have written some data outside array memory. Undefined Behavior means that your program behaviour from now is unpredictable. strcat does not reallocate any memory.
At last, how can i write a code to do the above task without the use
of strcat function.
For example:
char *mystrcat(char *dest, const char *src, const int isDynamicMemory)
{
size_t dlen = strlen(dest);
size_t slen = strlen(src);
if(isDynamicMemory)
{
dest = realloc(dest, slen + dlen + 1);
if(!dest) return NULL;
}
memcpy(dest + dlen, src, slen + 1);
return dest;
}
If dest was dynamically allocated you can reallocate it to the correct size by passing 1 as isDynamicMemory parameter
Try to do not program in the main function. Use functions for such task like writing strcat like function.
The program has undefined behavior because in the call of strcat
printf("%s\n", strcat(str1, str2));
the memory beyond the character array str1 declared like
char str1[7] = "hello ";
is being overwritten.
There is no space in the array to accommodate the string "buddy" after the stored string "hello ".
The sizes of the array str1 and str2 themselves was not changed. The function strlen does not return the size of a character array. It returns the length of a string: a sequence of characters terminated by the zero-terminating character '\0'. To get the size of a character array you should use the operator sizeof.
Pay attention to that the return type of the function strlen is size_t. To output a value of this type you have to use the conversion specifier zu instead of d.
printf("Initial size of str1 is: %zu\n", strlen(str1));
^^^
To make the program correct you have to enlarge the character array str1. Here is a demonstration program.
#include <stdio.h>
#include <string.h>
int main( void )
{
char str1[12] = "hello ";
printf( "The size of str1 is: %zu\n", sizeof( str1 ) );
printf( "The length of the stored string in str1 is: %zu\n", strlen( str1 ) );
char str2[] = "buddy";
printf("%s\n", strcat(str1, str2));
printf( "The size of str1 is: %zu\n", sizeof( str1 ) );
printf( "The length of the stored string in str1 is: %zu\n", strlen( str1 ) );
}
The program output is
The size of str1 is: 12
The length of the stored string in str1 is: 6
hello buddy
The size of str1 is: 12
The length of the stored string in str1 is: 11
As you can see from the output the size of the array str1 stays unchanged. What was changed is the length of the stored string in the array str1.
Pay attention to that the function strcat does not allocate or reallocate memory for arrays passed to the function as arguments. So if the destination array does not have enough memory to accommodate the appended string then the behavior is undefined because in this case the memory after the destination array will be overwritten.
As other answers (1, 2) mentioned, your code has a buffer overflow, a kind of undefined behaviour.
One more question: how can I write a code to do the above task without the use of strcat function.
Either:
Use snprintf()
Use strlcpy()
Implement your own version of strcat() (with some potential improvements)
Option 1
char str1[] = "hello ";
char str2[] = "buddy";
size_t total_size = sizeof(str1) + sizeof(str2) - 1; // sizeof counts \0 at the end
char res[total_size];
snprintf(res, total_size, "%s%s", str1, str2);
printf("sizeof(str1) = %zu\n", sizeof(str1));
printf("sizeof(str2) = %zu\n", sizeof(str2));
printf("total_size = %zu\n", total_size);
printf("res = %s\n", res);
sizeof(str1) = 7
sizeof(str2) = 6
total_size = 12
res = hello buddy
snprintf() lets you to control how many characters at most you want to print. This is comes handy in preventing a buffer overflow. For example, if you use sprintf(res, "%s%sxxx", str1, str2) in the above code, you'll get a BO. This is not the case with snprintf(res, total_size, "%s%sxxx", str1, str2).
Option 2
strlcpy() lets you to control how many characters at most you want to copy, and guarantees null-termination (unlike strncpy()). Possible implementations: 1, 2, 3.
Option 3 (credit: Back to Basics)
char *concatenate(char *dest, char *src)
{
while (*dest) dest++;
while ((*dest++ = *src++));
return --dest;
}
Or:
char *concatenate_n(char *dest, char *src, int n)
{
while (*dest) dest++;
for (int i = 0; i < n && (*dest++ = *src++); ++i) {}
return --dest;
}
Example:
char str1[12] = "hello ";
char str2[] = "buddy";
concatenate(str1, str2);
// concatenate_n(str1, str2, sizeof(str1) - 1 - strlen(str1)); // Remaining space in str1
printf("str1 = %s\n", str1);
printf("p = %s\n", p);
As i mentioned in the comment, overflow of str1 occures. strcat() doesn't know where and how strings are allocated. It searches end of destination string and appends source string overwriting null terminator.
If you want dynamic allocation, it could be:
char str1[]="hello ";
printf("Initial size of str1 is: %zu\n", strlen(str1));
char str2[]="buddy";
char *str3 = malloc(strlen(str1) + strlen(str2) + 1);
if (!str3)
return 1;
strcpy(str3, str1);
strcat(str3,str2);
printf("%s\n",str3);
printf("Final size: %zu\n", strlen(str3));
free(str3);
This may be optimized little bit. strlen() calculates length of string at runtime and you have strings known at compile time. So we can use it:
char str1[]="hello ";
printf("Initial size of str1 is: %zu\n", strlen(str1));
char str2[]="buddy";
char *str3 = malloc(sizeof(str1) + sizeof(str2) - 1);
if (!str3)
return 1;
strcpy(str3, str1);
strcpy(str3 + sizeof(str1) - 1, str2);
printf("%s\n",str3);
printf("Final size: %zu\n", strlen(str3));
free(str3);
Also pay attention to strlen() return type: it is size_t. We should either cast it to int for printing with %d format or print with %zu.
EDIT: fixed length calculation, fixed printf formatting modifier.
Related
I'm new with dynamic memory allocation and I tried to write a simple program to concatenate 2 strings (one initialized and one read from stdin) using realloc for the first string. But I receive this error:
cygwin_exception::open_stackdumpfile: Dumping stack trace to malloc.exe.stackdump
The code breaks at realloc and I do not know why, could you please help?
Input: man alive.
Expected output: The most beloved man alive.
I have tried replacing strlen with a number but with no avail.
Here's my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char *str = "The most beloved";
char str2[20];
scanf("%[^\n]%*c", str2);
//printf("%s %s\n", str, str2);
str = (char *)realloc(str, strlen(str) + strlen(str2));
strcat(str, str2);
printf("%s\n", str);
free(str);
}
You declared a pointer to a string literal
char *str = "The most beloved";
String literals have static storage duration. So they may not be reallocated dynamically.
Thus this statement
str = (char *)realloc(str, strlen(str) + strlen(str2));
invokes undefined behavior.
Pay attention to that you need to reserve memory for the terminating zero character '\0' of the result string.
What you need is the following
char *result = ( char * )malloc( strlen(str) + strlen(str2) + 1 );
strcpy( result, str );
strcat( result, str2 );
puts( result );
free( result );
Also it would be more safer to write
scanf("%19[^\n]", str2);
You are assigning a pointer to str which was not allocated using malloc. You may pass pointers to free or realloc only if they have been allocated using malloc.
Proper usage of realloc()
You could do
str = strdup("mystring");
Also here you need to account for the \0 at the end, so it should be:
str = (char *)realloc(str, strlen(str) + strlen(str2)+1);
I am learning C and want to learn how I can copy the remaining characters leftover in the string after using strncpy. I would like to have the string Hello World broken down into two separate lines.
For example:
int main() {
char someString[13] = "Hello World!\n";
char temp[13];
//copy only the first 4 chars into string temp
strncpy(temp, someString, 4);
printf("%s\n", temp); //output: Hell
}
How do I copy the remaining characters (o World!\n) in a new line to print out?
The one thing you should learn about strncpy is never use this function.
The semantics of strncpy are counter-intuitive and poorly understood by most programmers. It is confusing and error prone. In most cases, it does not do the job.
In your case, it copies the first 4 bytes and leaves the rest of temp uninitialized. You might have known this, but still invoked undefined behavior by passing temp to printf as a string argument.
If you want to manipulate memory, use memcpy and memmove and be careful about null terminators.
As a matter of fact, the string "Hello world!\n" has 13 characters and a null terminator, requiring 14 bytes in memory. Defining char someString[13] = "Hello World!\n"; is legal but it makes someString not a C string.
#include <stdio.h>
#include <string.h>
int main() {
char someString[14] = "Hello World!\n";
char temp[14];
memcpy(temp, someString, 4); //copy only the first 4 chars into string temp
temp[4] = '\0'; // set the null terminator
printf("%s\n", temp); //output: Hell\n
strcpy(temp + 4, someString + 4); // copy the rest of the string
printf("%s\n", temp); //output: Hello World!\n\n
memcpy(temp, someString, 14); //copy all 14 bytes into array temp
printf("%s\n", temp); //output: Hello World!\n\n
// Note that you can limit the number of characters to output for a `%s` argument:
printf("%.4s\n", temp); //output: Hell\n
return 0;
}
You can read more about strncpy here:
https://randomascii.wordpress.com/2013/04/03/stop-using-strncpy-already/
http://the-flat-trantor-society.blogspot.com/2012/03/no-strncpy-is-not-safer-strcpy.html
https://devblogs.microsoft.com/oldnewthing/?p=36773
What is the best alternative to strncpy()?
First of all, char someString[13] , you don't have enough space for the string Hello World\n, since you have 13 characters but you need at least size of 14, one extra byte for the NULL byte, '\0'. You better off let the compiler decide the size of the array, wouldn't be prone to UB that way.
To answer your question, you can just use printf() to display the remaining part of the string, you only need to specify a pointer to the element you want to start at.
In addition, strncpy() doesn't NULL terminate tmp, you are gonna have to do that manually if you want functions like printf() or puts() to function properly.
#include <stdio.h>
#include <string.h>
int main(void)
{
char someString[] = "Hello World!\n";
char temp[14];
strncpy(temp,someString,4);
temp[4] = '\0'; /* NULL terminate the array */
printf("%s\n",temp);
printf("%s",&someString[4]); /* starting at the 4th element*/
return 0;
}
In your case you could try something like:
char temp2[13];
strncpy(temp2, &someString[4], 9);
By the way you are missing a semicolon:
char someString[13] = "Hello World!\n";
The think you can do is to push your pointer of n character and copy the size - n caractere:
size_t n = 4; // nunmber caractere to copy first
size_t size = 13; // string length
char someString[size] = "Hello World!\n";
char temp[size];
char last[size - n]; // the string that contain the reste
strncpy(temp, someString, n); // your copy
strncpy(last, someString + n, 13 - n); // copy of reste of the string
The following program has no memory leaks. My question is, why does str1 and str2 not have to be passed into free(), even though I malloc'd both strings? Please see two commented locations in the code where I attempted to free str1 and str2, uncommenting that code resulted in an error saying I free'd a non-heap object. But from my understanding, str1 and str2 are objects created by malloc, hence are heap objects. I do not understand this contradiction.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* StrCat(char* s1, const char* s2) {
// Removing const from const char* s2
// made no difference on memory leak error message
char *s, *tmp;
s = tmp = malloc(strlen(s1) + strlen(s2) + 1);
strcpy(tmp, s1);
tmp += strlen(s1);
strcpy(tmp, s2);
//free(str1); free(str2); Why not?
printf("%d\n", s[strlen(s)] == '\0'); // Prints 1
return s;
}
int main(int argc, char** argv) {
char* str1 = malloc(4 * sizeof (char));
str1 = "abc\n";
char* str2 = malloc(6 * sizeof (char));
str2 = "party\n";
char* new = StrCat(str1, str2);
//free(str1); free(str2); Why not?
printf("%s\n", new);
free(new); // Required
return 0;
}
Of course you need to free heap objects, whether you pass them to a function or not. Whatever is returned by malloc() must eventually be free()d, regardless of how you will use it.
Your problem is as follows:
The following line:
char* str1 = malloc(4 * sizeof (char));
allocates memory for 4 characters and stores a reference to it in str1.
The following line:
str1 = "abc\n";
forgets whatever memory str1 was pointing to, (thus causing a memory leak,) and makes str1 point to a new location, in your program's static data segment. This is memory which was never allocated, and therefore may not be freed.
In order to solve your problem, instead of setting str1 to point to "abc\n" you need to use strcpy() to copy "abc\n" to the allocated memory block which is pointed by str1.
Before doing that, do not forget to increment your 4 and your 6 by 1 each, because strings in C also contain a null-terminating byte, so you need to allocate space for 5 and 7 characters respectively.
I'm writing my own strcpy due to the fact that the default one in string.h only accept a const char * as a source string to copy from.
I'm trying this very basic prototype (yes, the return isn't meaningful, I'm just trying things):
int copyStrings(char * dest, char * source){
int i=0;
while(source[i]!='\0'){
dest[i]=source[i];
i++;
}
dest[i]='\0';
return 0;
}
and it gives me SIGSEGV, Segmentation Fault error in gdb, at the line dest[i]=source[i], right at the first character. I'm pretty sure dest[i] isn't a string literal, so I should be able to modify it.
What am I doing wrong?
EDIT: here's the calling
int main(){
char * str = (char*)malloc((int)sizeof(double));
char * str2 = (char *)malloc((int)sizeof(int));
str = "hello";
str2 = "hey jude";
copyStrings(str2, str);
free(str);
free(str2);
return 0;
}
This is assigning a string literal to str2 - the very thing that you claim you aren't doing. This is actually the cause of your segfault.
str2 = "hey jude";
It also is causing a memory leak as prior to this, you malloc'd some memory and assigned it to str2 as well. But not enough memory to hold the string. Typically an int is 4 bytes and you need 9 bytes to store that string.
What you want to do is this, which allocates as many bytes as there are in the string, plus an extra one to store the \0 terminating character at the end.
str2 = malloc(strlen("hey jude")+1);
strcpy(str2,"hey jude");
or on some systems you can use POSIX function strdup() which effectively does the job of the above in one handy function call.
str2 = strdup("hey jude");
Let's go at it line by line and see where it goes wrong:
int main(){
char * str = (char*)malloc((int)sizeof(double));
char * str2 = (char *)malloc((int)sizeof(int));
str = "hello";
str2 = "hey jude";
copyStrings(str2, str);
free(str);
free(str2);
return 0;
}
int main(){ - this is an improper definition of main. Should be int main(int argc, char **argv)
char * str = (char*)malloc((int)sizeof(double)); - defines str, then allocates (probably) 8 bytes of memory and assigns its address to str. malloc takes a size_t argument, so the cast (int)sizeof(double) is incorrect. Also, in C the return value of malloc should never be cast. So this line should be char * str = malloc(sizeof(double));
char * str2 = (char *)malloc((int)sizeof(int)); - all the same problems as the preceding line. Should be char *str2 = malloc(sizeof(int));
str = "hello"; - causes a memory leak, because the memory you JUST ALLOCATED two lines earlier is now irretrievably lost. You've got two options here - either don't allocate the memory when defining str or free it first. Let's do the latter:
free(str);
str = "hello";
str2 = "hey jude"; - same problem, similar solution:
free(str2);
str2 = "hey jude";
copyStrings(str2, str); - here you're telling your routine to copy the constant string "hello" over the top of the constant string "hey jude". This will work fine on some systems, but will blow up on other systems. The question is in the treatment of the constant string "hey jude". If it's stored in modifiable memory the code will work just fine. If it's stored in memory which is marked as being unmodifiable, however, it will blow up. It seems that the latter is the case on your system. To fix this you probably want to go back to the previous line and change it to
str2 = malloc(20);
That's more memory than you'll need, but it will work just fine.
free(str); - you're attempting to free the constant string "hello", which is not dynamically allocated memory. This needed to be done prior to the assignment str = "hello";.
free(str2; - same problem as above. This needed to be done prior to the assignment str2 = "hey jude";.
} - correct
Best of luck.
I'm doing simple c excercise using visual studio.
Using strcat_s function I receive a violation exception thru this code:
char *str1;
str1 = (char *)malloc(20);
*str1 = "Ciao ";
char *str2 = "Marco";
strcat_s(str1, sizeof(str1), str2);
printf("%s", str1);
Now, if I use a predefined array whith a fixed size, strcat_s works perfectly.
How can I use pointers to char instead of array to make it work?
Any other solution or tip will be very appreciated.
Thank you in advance.
You have to copy the strings firstly into the allocated memory. If you like to know the length of a string use strlen(). sizeof() returns the size of the datatype in byte. In your case it is a pointer (4 byte on 32bit, 8 byte on 64bit machines).
The following code should work properly:
char *str1 = (char *)malloc(20);
strcpy(str1,"Ciao ");
char *str2 = (char *)malloc(20);
strcpy(str2,"Marco ");
strcat(str1, str2);
printf("%s", str1);
There are some issues with your code, and there are some general notes on strcat_s.
Your code str1 = (char *)malloc(20); *str1 = "Ciao " does not copy Ciao; *str is a single character at the first position of str, and your expression converts string literal "Ciao " (which is a pointer to a sequence of characters) to some single character (T in this case; surprising, isn't it?). One would need to use strcpy instead. An array, like char buffer[20] = "Ciao ", in contrast, works, because this (special) case is not an assignment but an initialiser of an array.
Your code sizeof(str1) gives you the size of a pointer value, which is probably 4 or 8, and has nothing to do with the actual size of the content or the memory block reserved. One should use strlen instead.
Concerning strcat_s, one should consider that it is not available on all platforms and that you have to be aware of it's special behaviour. For example, if you call strcat_s(somebuffer, 3, "somestrlongerthan3"), which exceeds the maximum length of 3 as provided, somebuffer will be an "empty" string (i.e. the first character will be set to \0.
I'd suggest to use strncat or snprintf instead. See the following variants:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
int main () {
char c = "Ciao "; // Gives a compiler warning and yields 'T'
#define maxlen 20
// Variant 1: start with initialized buffer, yet no "pointer" and dynamic allocation
char resultBuffer[maxlen] = "Ciao ";
size_t charactersRemaining = maxlen-strlen(resultBuffer)-1;
strncat(resultBuffer, "Marco", charactersRemaining);
// Variant 2: use dynamically allocated buffer and snprintf, with constant "Ciao".
char *resultBuffer2 = malloc(maxlen);
const char* second2 = "Marco";
snprintf(resultBuffer2, maxlen, "Ciao %s", second2);
// Variant 3: use dynamically allocated buffer and snprintf, with probably variable "Ciao" and "Marco"
char *resultBuffer3 = malloc(maxlen);
const char* first3 = "Ciao";
const char* second3 = "Marco";
snprintf(resultBuffer3, maxlen, "%s %s", first3, second3);
return 0;
}