Using realloc to concat strings - c

I'm trying to concat two strings, supposing the "dest" string hasn't enough space to add another one, so I'm using dynamic arrays to solve it.
The problem is a mremap_chunk error when trying to compile the code.
I don't know what I'm missing since the realloc call has all the right params place in.
Error:
malloc.c:2869: mremap_chunk: Assertion `((size + offset) & (GLRO (dl_pagesize) - 1)) == 0' failed.
Aborted (core dumped)
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *strcatt(char *s1, char *s2)
{
int a = strlen(s1);
int b = strlen(s2);
int i, size_ab = a+b;
s1 = (char *) realloc (s1, size_ab*sizeof(char));
for(i=0; i<b; i++) {
s1[i+a]=s2[i];
}
s1[size_ab]='\0';
return s1;
}
int main()
{
char s1[]="12345";
char s2[]="qwerty";
strcatt(s1,s2);
printf("%s\n", s1);
return 0;
}

First, you are treating non-heap memory as heap memory, don't do that.
Second you're not including space for the terminator in the calculation.
Here are some more points:
Don't name functions starting with str, that's a reserved name space.
Buffer sizes should be size_t, not int.
Don't cast the return value of malloc() in C.
Use memcpy() to copy blocks of memory when you know the size.
The "right hand side" strings should be const.
Deal with the possibility of allocation error.
I consider it bad practice to scale by sizeof (char), that's always 1.
Here's how I would write it, assuming the same logic:
char * my_strcatt(char *s1, const char *s2)
{
const size_t a = strlen(s1);
const size_t b = strlen(s2);
const size_t size_ab = a + b + 1;
s1 = realloc(s1, size_ab);
memcpy(s1 + a, s2, b + 1);
return s1;
}

You can not realloc or free a memory that is not allocated with a call to malloc or is not NULL.
From section 7.22.3.5. The realloc function in C11 draft
The realloc function deallocates the old object pointed to by ptr and
returns a pointer to a new object that has the size specified by size.
The contents of the new object shall be the same as that of the old
object prior to deallocation, up to the lesser of the new and old
sizes. Any bytes in the new object beyond the size of the old object
have indeterminate values.
So, s1 = (char *) realloc (s1, size_ab*sizeof(char)); is plainly wrong for your inputs (automatic arrays), never do that.
And then there are many more problems which can be fixed with some help from a debugger.

The clang debugger gives a very clear error description:
malloc: error for object 0x7fff6fbb16d6: pointer being realloc'd was not allocated
set a breakpoint in malloc_error_break to debug
Both of your arrays are initialized as string literals. Further on, your function tries to modify a string literal by reallocing it, which is wrong by C standard because you can't reallocate what you haven't allocated, and then copying the members of the second string literal to the "object" you intended to modify by misusing realloc() on a string literal.
The code would work if you had dynamically defined a third string in which you would have summed the contents of both:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *mystrcatt(char *s1, char *s2)
{
int a = strlen(s1);
int b = strlen(s2);
int i, size_ab = a+b;
char *s3 = malloc (size_ab*sizeof(char)); //sizeof(char) is always 1
for(i=0; i<a; i++) { //inefficient
(s3[i])=s1[i];
}
for(i=0; i<b; i++) { //inefficient
(s3[i+a])=s2[i];
}
s3[size_ab]='\0';
return s3;
}
int main()
{
char s1[]="12345";
char s2[]="qwerty";
char *s3 = mystrcatt(s1,s2);
printf("%s\n", s3);
free(s3);
return 0;
}
Please, also note that you don't cast the return of malloc() in C.

Related

Returning array of chars in C function

I have tried so many ways of doing this and I cannot get it to work. My setup says to use char[] but everything I've researched has no information on using that. Here is my code below
#include <stdio.h>
#include <string.h>
char[] makeString(char character,int count)
{
char finalString[count];
strcpy(finalString,character);
for(int i=1;i<=count;i++)
{
strcat(finalString,character);
}
return finalString;
}
int main() {
printf("%s\n",makeString("*",5)); }
I'm trying to create a function that returns a string of the given character count amount of times. Any help is greatly appreciated.
My apologies if this is a very simple error, I mostly code in python so C is very new to me.
There are a couple of issues, mainly on char finalString[count];
finalString is a variable created within the function, it is called a local variable. It would be destroyed after the function returns.
count as the value of the count variable is dynamically changed. Its value could not be determined during the compile stage, thus the compiler could not allocate memory space for this array. The compiling would fail.
To fix this issue.
either create this variable outside and pass it into the function. Or create the variable on the HEAP space. As the Heap space are shared across the entire program and it would not be affected by function ending.
either using a constant number or dynamically allocating a chunk of memory with malloc, calloc and etc.
Here is one demo with the full code:
// main.c
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char* makeString(char character,int count) {
char* finalString = malloc(count+1); //dynamic allocate a chunk of space. +1 for mimic string end with an extra termination sign 0.
for(int i=0; i<count; i++) {
finalString[i] = character;
}
finalString[count] = 0; // string end signal 0
return finalString; // the memory finalString pointed to is in the HEAP space.
}
int main() {
char * p = makeString('*',5);
printf("%s\n",p);
free(p); // free up the HEAP space
return 0;
}
To compile and run the code.
gcc -Wall main.c
./a.out
The output
*****
Arrays are not a first-class type in C -- there are a lot of things you can do with other types that you can't do with arrays. In particular you cannot pass an array as a parameter to a function or return one as the return value.
Because of this restriction, if you ever declare a function with an array type for a parameter or return type, the compiler will (silently) change it into a pointer, and you'll actually be passing or returning a pointer. That is what is happening here -- the return type gets changed to char *, and you return a pointer to your local array that is going out of scope, so the pointer you end up with is dangling.
Your code doesn't compile. If you want to return an array you do char * not char []. Local variables like finalString are out of scope after the function returns.
Here are 3 ways of doing it:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *initString(char *a, char c, int n) {
memset(a, c, n);
a[n] = '\0';
return a;
}
char *makeString(char c, int n) {
char *a = malloc(n + 1);
memset(a, c, n);
a[n] = '\0';
return a;
}
int main(void) {
printf("%s\n", memset((char [6]) { 0 }, '*', 5));
char s[6];
initString(s, '*', (sizeof s / sizeof *s) - 1);
printf("%s\n", s);
char *s2 = makeString('*', 5);
printf("%s\n", s2);
free(s2);
}

I wanna make strncpy function directly, can you review my code? There is bus Error

I wanna Make strncpy function by code, not by using Library or Header
but There is zsh bus error..... What's wrong with my code? What's the zsh bus error??
#include <stdio.h>
#include <string.h>
char *ft_strncpy(char *dest, char *src, unsigned int n)
{
unsigned int i;
i = 0;
while (i < n && src[i])
{
dest[i] = src[i];
i++;
}
while (i < n)
{
dest[i] = '\0';
i++;
}
return (dest);
}
int main()
{
char *A = "This is a destination sentence";
char *B = "abcd";
unsigned int n = 3;
printf("%s", ft_strncpy(A, B, n));
}
Your implementation of strncpy is fine, the uncanny semantics of the error prone function are correctly implemented (except for the type of n, which should be size_t).
Your test function is incorrect: you pass the address of a string constant as the destination array, causing undefined behavior when ft_strncpy() attempts to write to it. String constant must not be written to. The compiler may place them in read-only memory if available. On your system, writing to read-only memory causes a bus error, as reported by the shell.
Here is a modified version with a local array as destination:
int main()
{
char A[] = "This is a destination sentence";
const char *B = "abcd";
unsigned int n = 3;
printf("%s\n", ft_strncpy(A, B, n));
return 0;
}
Your code exposes one of the very subtle differences in C between an array and a pointer. The line:
char *A = "This is a destination sentence";
declares A as a pointer to a character (string) and then initialises that pointer to the address of a string literal. This string literal is a constant value, and the compiler is allowed to place this in an area of memory that is read-only. Then, when you pass that memory to the ft_strncpy function (via its address), you are attempting to modify that read-only memory.
If you, instead, use the following:
char A[] = "This is a destination sentence";
then you are declaring A as an array of characters and initializing that array with the data from the string literal. Thus, the compiler is now aware that the array is modifiable (you haven't included a const qualifier) and will place that array in memory that can be read from and written to.

Writing a string-concat: How to convert character array to pointer

I am learning C and I have written the following strcat function:
char * stringcat(const char* s1, const char* s2) {
int length_of_strings = strlen(s1) + strlen(s2);
char s3[length_of_strings + 1]; // add one for \0 at the end
int idx = 0;
for(int i=0; (s3[idx]=s1[i]) != 0; idx++, i++);
for(int i=0; (s3[idx]=s2[i]) != 0; idx++, i++);
s3[idx+1] = '\0';
// s3 is a character array;
// how to get a pointer to a character array?
char * s = s3;
return s;
}
That part that looks odd to me is where I have to "re-assign" the character array to a pointer, otherwise C complains that my return is a memory address. I also tried "casting" the return value to (char *) s3, but that didn't work either.
What is the most common way to do this "conversion"? Is this a common pattern in C programs?
There are many ways to handle this situation, but returning a pointer to stack-allocated memory inside the function isn't one of them (the behavior is undefined; consider this memory untouchable once the function returns).
One approach is to allocate heap memory using malloc inside the function, build the result string, then return the pointer to the newly allocated memory with the understanding that the caller is responsible for freeing the memory.
Here's an example of this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *stringcat(const char* s1, const char* s2) {
int i = 0;
int s1_len = strlen(s1);
int s2_len = strlen(s2);
char *result = malloc(s1_len + s2_len + 1);
result[s1_len+s2_len] = '\0';
for (int j = 0; j < s1_len; j++) {
result[i++] = s1[j];
}
for (int j = 0; j < s2_len; j++) {
result[i++] = s2[j];
}
return result;
}
int main(void) {
char *cat = stringcat("hello ", "world");
printf("%s\n", cat); // => hello world
free(cat);
return 0;
}
Another approach is for the caller to handle all of the memory management, which is similar to how strcat behaves:
/* Append SRC on the end of DEST. */
char *
STRCAT (char *dest, const char *src)
{
strcpy (dest + strlen (dest), src);
return dest;
}
man says:
The strcat() function appends the src string to the dest string, overwriting the terminating null byte ('\0') at the end of dest, and then adds a terminating null byte. The strings may not overlap, and the dest string must have enough space for the result. If dest is not large enough, program behavior is unpredictable; buffer overruns are a favorite avenue for attacking secure programs.
The problem isn't converting from array to pointer; that happens all the time implicitly, and it's no big deal. Your problem is you've just returned a pointer to invalid memory. The array you allocated in the function disappears when the function returns, and dereferencing a pointer to that array is undefined behavior (returning the pointer isn't technically illegal, but any good compiler warns you, because a pointer that is never dereferenced is usually pretty useless).
If you want to return a new array with the concatenated string, you must use dynamically allocated memory, e.g. from malloc/calloc; making the array static would also work (it would now be persistent global memory), but it would make your function both non-reentrant and non-threadsafe, so it's usually frowned on.
Your little trick of assigning to a pointer and returning the pointer may have fooled the compiler into thinking you weren't doing anything illegal, but it did nothing to make your code safer.
You might be used to languages with more dynamic memory handling, but your function here won't work because C strings are just a block of local memory which disappears when you return. That means that whatever you write to char s3[] will disappear after the return (the details vary and the memory can sometimes stick around long enough for you to think it worked even when it didn't).
Normally you'd want to allocate the memory before calling the function, and pass it in as a parameter, as in:
void stringcat(const char * first, const char * second, char * dest, const size_t dest_len)
Called like this:
char title[] = "Mr. ";
char last[] = "Jones";
char addressname[sizeof(title) + sizeof(last)];
stringcat(title, last, addressname, sizeof(addressname));
The other way to do it is to allocate the memory in the function using malloc(), and return that, but you have to remember to free it in the code when you're done with it.

Simple question on dynamically allocating memory to a char pointer

I am studying for a Data Structures and Algorithms exam. One of the sample questions related to dynamic memory allocation requires you to create a function that passes a string, which takes it at copies it to a user defined char pointer. The question provides the struct body to start off.
I did something like this:
typedef struct smart_string {
char *word;
int length;
} smart_string;
smart_string* create_smart_string(char *str)
{
smart_string *s = (smart_string*)malloc(sizeof(smart_string));
s->length = strlen(str);
s->word = malloc(s->length);
strcpy(s->word, str);
return s;
}
But the answer was this
typedef struct smart_string {
char *word;
int length;
} smart_string;
smart_string *create_smart_string(char *str)
{
smart_string *s = malloc(sizeof(smart_string));
s->length = strlen(str);
s->word = malloc(sizeof(char) * (s->length + 1));
strcpy(s->word, str);
return s;
}
I went on code:blocks and tested them both to see any major differences. As far as I'm aware, their outputs were the same.
I did my code the way it is because I figured if we were to allocate a specific block of memory to s->word, then it should be the same number of bytes as s ->length, because that's the string we want to copy.
However the correct answer below multiplies sizeof(char) (which is just 1 byte), with s->length + 1. Why the need to add 1 to s->length? What's the importance of multiplying s->length by sizeof(char)? What mistakes did I make in my answer that I should look out for?
sizeof(char) == 1 by definition, so that doesn't matter.
You should not cast the result of malloc: Do I cast the result of malloc?
And your only real difference is that strlen returns the length of the string, not including the terminating NUL ('\0') character, so you need to add + 1 to the size of the buffer as in the solution.
If you copy there the string, the terminating character won't be copied (or worse, it will be copied on some other memory), and therefore, any function that deals with strings (unless you use special safety functions such as strscpy) will run through the buffer and past it since they won't find the end. At that point it is undefined behaviour and everything can happen, even working as expected, but can't rely on that.
The reason it is working as expected is because probably the memory just next to the buffer will be 0 and therefore it is being interpreted as the terminating character.
Your answer is incorrect because it doesn't account for the terminating '\0'-character. In C strings are terminated by 0. That's how their length can be determined. A typical implementation of strlen() would look like
size_t strlen(char const *str)
{
for (char const *p = str; *p; ++p); // as long as p doesn't point to 0 increment p
return p - str; // the length of the string is determined by the distance of
} // the '\0'-character to the beginning of the string.
But both "solutions" are fubar, though. Why would one allocate a structure consisting of an int and a pointer on the free-store ("heap")!? smart_string::length being an int is the other wtf.
#include <stddef.h> // size_t
typedef struct smart_string_tag { // *)
char *word;
size_t length;
} smart_string_t;
#include <assert.h> // assert()
#include <string.h> // strlen(), strcpy()
#include <stdlib.h> // malloc()
smart_string_t create_smart_string(char const *str)
{
assert(str); // make sure str isn't NULL
smart_string_t new_smart_string;
new_smart_string.length = strlen(str);
new_smart_string.word = calloc(new_smart_string.length + 1, sizeof *new_smart_string.word);
if(!new_smart_string.word) {
new_smart_string.length = 0;
return new_smart_string;
}
strcpy(new_smart_string.word, str);
return new_smart_string;
}
*) Understanding C Namespaces

malloc() to concatenate 2 strings into third string - crash after compilation

So I'm working through "Sams Teach Yourself C Programming in One Hour a Day, Seventh Edition" Lesson 10 Exercise 7 which asks to "Write a function that accepts two strings. Use the malloc() function to allocate enough memory to hold the two strings after they have been concatenated (linked). Return a pointer to this new string."
I am sure there are much more elegant ways to go about this than what I have attempted below. I am mostly interested in why my solution doesn't work. I have only been learning C for a few months and have no significant programming background. Please let me know why this crashes on compilation. I am using Code Blocks on Win 7 with GNU GCC Compiler if that makes a difference. Thank you :)
#include <stdio.h>
#include <stdlib.h>
char * concatenated(char array1[], char array2[]);
int ctrtotal;
int main(void)
{
char *comboString;
char *array1 = "You\'re the man ";
char *array2 = "Now Dog!";
comboString = (char *)malloc(ctrtotal * sizeof(char));
concatenated(array1, array2);
if (comboString == NULL)
{
puts("Memory error");
exit(1);
}
puts(comboString);
free(comboString);
return 0;
}
char * concatenated(char array1[], char array2[])
{
char *array3;
int ctr;
int ctr2;
for (ctr = 0; array1[ctr] != '\0'; ctr++)
array3[ctr] = array1[ctr];
ctr2 = ctr;
for (ctr = 0; array2[ctr] != '\0'; ctr++)
{
array3[ctr2 + ctr] = array2[ctr];
}
array3[ctr2 + ctr + 1] = '\0';
ctrtotal = (ctr2 + ctr + 2);
return array3;
}
Thank you for the help. After reviewing everyone's feedback on my errors I revised the code to the following:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * concatenated(char array1[], char array2[]);
int main(void)
{
char *array1 = "Testing Testing One Two ";
char *array2 = "Three. Finally, not crashing the mem o ry.";
char *comboString = malloc( (strlen(array1)+strlen(array2) + 1)*sizeof(char));
comboString = concatenated(array1, array2);
if (comboString == NULL)
{
puts("Memory error");
exit(1);
}
puts(comboString);
free(comboString);
return 0;
}
char * concatenated(char array1[], char array2[])
{
char *array3;
array3 = malloc( (strlen(array1)+strlen(array2) + 1)*sizeof(char) );
strcat(array3, array1);
strcat(array3, array2);
return array3;
}
If anyone sees any redundancies/unnecessary remaining code the could/should be deleted, please let me know. I recognize the benefit of being as concise as possible.
Your code has a bunch of issues:
int ctrtotal is never initialized, so you are mallocing 0 bytes
concatenated() is copying characters to an uninitialized array3. This pointer should point to a mallocd buffer.
If concatenated is allocating the memory, then main doesn't need to. Instead it should use the result of concatenated.
I don't want to give you the full code, and let you to miss out on this learning opportunity. So concatenated should look like this, in psuedo-code:
count = length_of(string1) + length_of(string2) + 1
buffer = malloc(count)
copy string1 to buffer
copy string2 to buffer, after string1
set the last byte of buffer to '\0' (NUL)
return buffer
In C, strings are represented as a NUL-terminated array of characters. That's why we allocate one additional byte, and terminate it with \0.
As a side-note, when dealing with strings, it is far easier to work with pointers, instead of treating them as arrays and accessing them via indices.
There's a lot of code here that just doesn't make any sense. I suggest that you first write this program on paper. Then, "execute" the program in your head, stepping through every line. If you get to something you don't understand, then you need to either fix your understanding, or your incorrect code. Don't try to write code that looks like some other bit of code.
There's also a library function called strcat which will make this task even easier. See if you can figure out how to use it here.
Spoiler --> #include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *concatenate2(const char* s1, const char* s2);
int main(void)
{
char *comboString;
char *array1 = "You're the man ";
char *array2 = "Now Dog!";
comboString = concatenate2(array1, array2);
if (comboString == NULL)
{
puts("Memory error");
exit(1);
}
puts(comboString);
free(comboString);
return 0;
}
char *concatenate2(const char* s1, const char* s2)
{
char *result;
result = malloc(strlen(s1) + strlen(s2) + 1);
*result = '\0';
strcat(result, s1);
strcat(result, s2);
return result;
}
You forgot to allocate memory for third, concatenated, array of chars (in function)
You should do something like this:
char *array3;
array3 = (char *)malloc( (strlen(array1)+strlen(array2) + 1)*sizeof(char) ); // +1 for '\0' character.
and then write chars from first and second array into third.
Perhaps a stroll through the question code is best.
#include <stdio.h>
#include <stdlib.h>
char * concatenated(char array1[], char array2[]);
int ctrtotal;
Notice that the above line declares ctrtotal to be an integer, but does not specify the value of the integer.
int main(void)
{
char *comboString;
char *array1 = "You\'re the man ";
char *array2 = "Now Dog!";
comboString = (char *)malloc(ctrtotal * sizeof(char));
Notice that the above line allocates memory and sets 'comboString' to point at that memory. However, how much memory is being allocated?
(ctrtotal[???] * sizeof(char)[1])
What is the value of (??? * 1) ? This is a problem.
concatenated(array1, array2);
The intent of the line above is that array1["You\'re the man "] and array2["Now Dog!"] will be joined to form a new string["You\'re the man Now Dog!"], which will be placed in allocated memory and returned to the caller.
Unfortunately, the returned memory containing the string is not captured here. For example, perhaps the above line should be:
comboString = concatenated(array1, array2);
While this make sense, for this line, it begs a question of the purpose of the lines:
comboString = (char *)malloc(ctrtotal * sizeof(char));
as well as the global variable:
int ctrtotal;
and the later reference:
ctrtotal = (ctr2 + ctr + 2);
Perhaps all of these 3 lines should be deleted?
if (comboString == NULL)
{
puts("Memory error");
exit(1);
}
puts(comboString);
free(comboString);
return 0;
}
char * concatenated(char array1[], char array2[])
{
char *array3;
Notice that '*array3' is now a defined pointer, but it is not pointing anywhere specific.
int ctr;
int ctr2;
The purpose of 'concatenated()' is to join array1 and array1 into allocated array3. Unfortunately, no memory is allocated to array3.
Below, the memory where array3 is pointing will be modified. Since array3 is not pointing anywhere specific, this is not safe.
Prior to modifying memory where array 3 is pointing, it is important to point array3 at memory where it is safe to modify bytes. I suggest that the following code be inserted here:
array3 = malloc(strlen(array1) + strlen(array2) + 1);
Now, array3 points to allocated memory, large enough to hold both strings plus the string termination character '\0'.
for (ctr = 0; array1[ctr] != '\0'; ctr++)
array3[ctr] = array1[ctr];
ctr2 = ctr;
for (ctr = 0; array2[ctr] != '\0'; ctr++)
{
array3[ctr2 + ctr] = array2[ctr];
}
array3[ctr2 + ctr + 1] = '\0';
ctrtotal = (ctr2 + ctr + 2);
return array3;
}
I am responding to your revised code. There are a few bugs in it.
...
char *array2 = "Three. Finally, not crashing the mem o ry.";
char *comboString = malloc( (strlen(array1)+strlen(array2) + 1)*sizeof(char));
comboString = concatenated(array1, array2);
...
The malloc is unnecessary here and actually a bug in your code. You are allocating a block of memory, but you then replace the value of the pointer comboString with the pointer from the call to concatenated. You lose the pointer to the block of memory allocated in main and thus never are able to free it. Although this will not be a problem in the code you have right now since main returns soon after, it could cause a memory leak in an application that ran for a longer time.
strcat(array3, array1);
This is also a bug. strcat is going to walk through array3 to find '\0' and then once it is found copy in array1 from that index on, replacing the '\0'. This works fine here since the memory block that was allocated for array3 is going to be zeroed out** as no block has yet been freed by your program. However, in a longer running program you can end up with a block that does not start with a '\0'. You might end up corrupting your heap, getting a segfault, etc.
To fix this, you should use strcpy instead, array3[0] = '\0', or *array3 = '\0'
** When the operating system starts your program it will initialize the memory segment it reserves for it with zeroes (this actually isn't a necessity but will be true on almost any operating system). As your program allocates and frees memory, you will eventually wind up with values that are not zero. Note that the same bug can occur with uninitialized local variables such as:
int i;
for (; i < 10; i++);
This loop will run 10 times whenever the space on the runtime stack where i is stored is already 0.
Overall, the takeaway is to be very careful with arrays and dynamic memory allocation in C. C offers you none of the protections that modern languages do. You are responsible for making sure you stay within the bounds of your array, initialize your variables, and properly allocate and free your memory. Neglecting these things will lead to obscure bugs that will take you hours to find, and most of the times these bugs will not appear right away.

Resources