char *ft_strjoin(int size, char **strs, char *sep)
{
int full_length;
int index;
char *read_head;
char *string;
if (size == 0)
return ((char *)malloc(sizeof(char)));
full_length = ft_compute_final_length(strs, size, ft_str_length(sep));
if (!(string = (char *)malloc((full_length + 1) * sizeof(char))))
return (0);
read_head = string;
index = 0;
while (index < size)
{
ft_strcpy(read_head, strs[index]);
read_head += ft_str_length(strs[index]);
if (index < size - 1)
{
ft_strcpy(read_head, sep);
read_head += ft_str_length(sep);
}
index++;
}
*read_head = '\0';
return (string);
}
When I saw others code I wonder the part of this.
read_head = string;
I change the code that use only allocated pointer.
In this case
string
So the error occures that "pointer being freed was not allocated"
I can't understand that Why do I have to use another pointer to point another pointer?
Is it happend because that to strcpy pointer and allocated pointer are different?
For starters this statement
if (size == 0)
return ((char *)malloc(sizeof(char)));
does not make a sense because the function returns a pointer to a non-initialized memory. Maybe you mean
if (size == 0)
return (char *)calloc( 1, sizeof(char));
That is the function will return a pointer to an empty string.
Within the function the pointer read_head is being changed as for example in this statement
read_head += ft_str_length(strs[index]);
That is after using it such a way it will not point to the initially allocated memory. As it is seen from this statement
*read_head = '\0';
after the while loop the pointer points to the terminating zero of the built string.
So using it in a call of free will issue the error you got.
So this statement
read_head = string;
allows to preserve the address of the allocated dynamically memory in the pointer string and to use the intermediate pointer read_head that will be changed..
Why I cannot use allocated pointer in this case?
The reason that you can't use string directly but have to use the extra read_head variable is because you change read_head in the loop (i.e. read_head += ...). If you did that directly on string you would be in problems because you need to know the malloced value of string so that you can call free later on.
Simple example of wrong code:
char *string = malloc(...);
string += someValue; // Change the value of string
free(string); <-------- ERROR because the value of string changed
Simple example of good code:
char *string = malloc(...);
char *read_head = string; // Give read_headthe same value as string
read_head += someValue; // Change the value of read_head
free(string); <-------- FINE because the value of string did NOT change
Related
Question : https://leetcode.com/problems/find-and-replace-in-string/
"""
char * findReplaceString(char * s, int* indices, int indicesSize, char ** sources, int
sourcesSize, char ** targets, int targetsSize){
int len = strlen(s);
char *copyS;
char *copy = (char*) malloc(sizeof(char)*len);
memcpy(copy, s, sizeof(char)*len);
copyS = copy;
int x = indicesSize-1;
int indexArr[1001] = {0};
int y;
for(int j=0; j<indicesSize; j++)
{
indexArr[indices[j]] = j;
}
qsort(indices, indicesSize, sizeof(int), cmp);
while((x >= 0))
{
y = indexArr[indices[x]];
copy = copyS+(indices[x]);
if(!(strncmp(copy, sources[y], strlen(sources[y]))))
{
copy = (char *)realloc(copy, sizeof(char)*(sizeof(copy) + sizeof(targets[y])));
strcpy(copy, targets[y]);
}
x--;
}
return copyS;
}
I am getting a runtime error due to the use of realloc. I was trying to modify the input string 's'. Got a runtime error due to realloc: Trying to free memory that was not malloced.
So I malloced new string pointer , *copy. Still getting same error when I use realloc on copy
There are several problems with the code.
For starters it is unclear whether the dynamically allocated array pointed to by the pointer copy shall contain a string or not.
If it shall contain a string then instead of
char *copy = (char*) malloc(sizeof(char)*len);
memcpy(copy, s, sizeof(char)*len);
you need to write
char *copy = (char*) malloc(sizeof(char)*( len + 1 ));
memcpy(copy, s, sizeof(char)*( len + 1 ));
Also it is unclear why there is used the magic number 1001 in this declaration
int indexArr[1001] = {0};
The pointer copyS was assigned with the address of the initially allocated memory
char *copyS;
char *copy = (char*) malloc(sizeof(char)*len);
memcpy(copy, s, sizeof(char)*len);
copyS = copy;
but then you are trying to reallocate the memory
copy = (char *)realloc(copy, sizeof(char)*(sizeof(copy) + sizeof(targets[y])));
As a result the pointer copyS can have an invalid value. And this pointer with an invalid value is returned from the function
return copyS
In turn the pointer copy is changed within the while loop
while((x >= 0))
{
y = indexArr[indices[x]];
copy = copyS+(indices[x]);
//..
So after such an assignment it does not point to the previously allocated memory extent. Hence using the pointer in the call of realloc
copy = (char *)realloc(copy, sizeof(char)*(sizeof(copy) + sizeof(targets[y])));
invokes undefined behavior.
And again this statement
copy = copyS+(indices[x]);
also invokes undefined behavior because after the memory reallocation the pointer copyS can be invalid.
Once you do this
copy = copyS+(indices[x]);
you can no longer use 'copy' as an argument to realloc or free. The pointer you pass to these functions must be the value returned by a prior malloc or realloc (or calloc)
Save the original 'copy' in a variable like 'originalCopy'
So I'm practicing and learning C right now and came across a rather easy challenge from CodeWars that asked to print out a string of "Aa~", "Pa!", and "Aa!" depending on whether n was <= 6 or not. I know how we can do this with arrays but wanted to try out using dynamically allocated char arrays like with malloc for efficiency sake.
I want to make sure I get the basics down with these questions
So I know in other malloc examples with int we set up a pointer (of type int) to point to an allocated memory block. Is it still a pointer when I declare "char *ptr" to point to an allocated memory block because pardon me I thought "char *anything" meant it was a convention to represent a string. So not sure why the below is working somewhat if I'm not setting up a pointer like "char **ptr" as I thought.
why do I get a "malloc: *** error for object 0x100000fab: pointer being freed was not allocated" type of error when I try to return the answer especially when the "val" is 1 or 0? I read somewhere that changing the pointer(string?), answer, to NULL will solve the issue but not entirely sure why this works.
3 To continue in general with the above question, for freeing up space, what is the best method to do so if we dynamically allocate a memory block in a function but need to return a value from that function? As in, do we free up the space after or before?
Thank you all for your input.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define val 1
char *sc(int); // function declaration/prototype
int main(int argc, const char * argv[]) {
char *answer = sc(val);
printf("The answer is %s\n", answer);
answer = NULL; // why does this work
free(answer);
return 0;
}
char *sc(int n) {
// if n < 6 then will have an extra "Aa!" after "Pa!" at the nth position
char *ptr = (char*) malloc(n*4);
if (ptr == NULL){
printf("malloc failed");
}
char *first = "Aa~ ";
char *second = "Pa! Aa!";
char *third = "Pa!";
if (n <= 6 && n >1) {
for (int i = 0; i <n-1; i++){
ptr = strcat(ptr, first);
}
ptr = strcat(ptr, second);
}
else if (n> 6){
for (int i = 1; i < n; i++) {
ptr = strcat(ptr, first);
}
ptr = strcat(ptr, third);
}
else if (n <= 1){
ptr = "";
}
else {
printf("Error!");
exit(0);
}
return ptr;
}
The main issue you have with your code is that you're not zeroing out the buffer you get from malloc(), so the first strcat() is not necessarily going to write at the start of the string but at the end.
You can fix that with a strcpy() right after the malloc() call and check:
strcpy(ptr, "");
Or, equivalently, you can just set the first byte of the buffer to zero. Since C strings are zero-terminated strings, setting a character to zero will indicate it's at the end:
ptr[0] = 0;
You also seem to be allocating your buffer too short. If you write n-1 copies of Aa~ (4 bytes) plus one copy of Pa! Aa! (8 bytes when you include the terminating zero!) you'll actually need 4 * (n+1) as space. So either always allocate that or do so in case n < 6 which is where you need the additional bytes.
This is also a problem:
ptr = "";
Because now your ptr is no longer pointing to a buffer returned by malloc(), but to a static (empty) string in your binary. It's quite probable that this is the place where you're getting the trouble from free(), since calling it on a static string in your binary is definitely wrong.
Furthermore, after you set ptr = "" you no longer have any reference to the buffer you allocated, which means you most likely just created a memory leak!
In that case, you should simply use strcpy() or set the first byte to zero. But if you do that at the start of the program, you don't need to do it here.
Finally, free(NULL); works (as in, doesn't throw an error) because that's part of its specification, you can pass it a NULL pointer and it will do nothing. But note that it's not freeing the buffer you allocated, so you have a memory leak here too.
I'd further refactor the second part of your code so you don't have too much repetition appending the strings:
char *sc(int n) {
/* if n <= 6 then will have an extra "Aa!"
* after "Pa!" at the nth position.
*/
char *ptr;
if (n < 0) {
printf("Error!");
return NULL;
}
ptr = (char*) malloc(4 * (n+1));
if (ptr == NULL){
printf("malloc failed");
return NULL;
}
strcpy(ptr, "");
if (n > 1) {
for (int i = 1; i < n; i++){
strcat(ptr, "Aa~ ");
}
strcat(ptr, "Pa!");
if (n <= 6) {
strcat(ptr, " Ah!");
}
}
return ptr;
}
Also note you don't need to assign the result of strcat() back to ptr every time, since it always returns its first argument anyways, so assigning it there isn't changing anything really.
I thought "char *anything" meant it was a convention to represent a string. So not sure why the below is working somewhat if I'm not setting up a pointer like "char **ptr" as I thought.
You're allocating memory for a string, so it just needs to be char *. char ** would be used for an array of multiple strings, or for a pointer to a variable that contains a pointer to a string.
why do I get a "malloc: *** error for object 0x100000fab: pointer being freed was not allocated"
You get that when you do ptr = "";. After you do this, ptr no longer points to the memory that was allocated with malloc, it points to that string literal. If you want to set the allocated memory to an empty string, you can do
ptr[0] = '\0';
This puts a null terminator in the first element of the string.
You also need to do that before the code that uses strcat() to append to the string. Otherwise you're appending to uninitialized data. Simplest would be to do it immediately after allocating the memory (then you don't need it in the n <= 1 block.
The else block is not needed. There are no other possibilities than the 3 you test for unless the CPU is malfunctioning (in which case all bets are off). However, you should check for n < 1 before calling malloc(), as you can't allocate negative memory, and malloc(0) may return NULL.
When you allocate space for ptr, you need to add 1 byte for the terminating null of the string.
char *sc(int n) {
// if n < 6 then will have an extra "Aa!" after "Pa!" at the nth position
if (n >= 1) {
char *ptr = malloc(n*4 + 1);
} else {
char *ptr = malloc(1);
}
if (ptr == NULL){
printf("malloc failed");
exit(1);
}
ptr[0] = '\0'; // initialize empty string
char *first = "Aa~ ";
char *second = "Pa! Aa!";
char *third = "Pa!";
if (n <= 6 && n >1) {
for (int i = 0; i <n-1; i++){
ptr = strcat(ptr, first);
}
ptr = strcat(ptr, second);
}
else if (n> 6){
for (int i = 1; i < n; i++) {
ptr = strcat(ptr, first);
}
ptr = strcat(ptr, third);
}
else if (n <= 1){
// nothing to do
}
return ptr;
}
I have one function, alloc_str, which takes a string pointer and an array of pointers. It dynamically increases the size of the array by one and appends the string into the array. I have run a GDB debugger and highlighted my memory leak and const error below.
My expected input/output:
array = alloc_str(array, "test_1");
array = alloc_str(array, "test_2");
array = alloc_str(array, "test_3");
--> ["test_1", "test_2", "test_3"]
My alloc_str function:
char **alloc_str(char **existing, const char *add)
{
int length = 0; //find the length of the array
for (; existing[length]; length++)
{
}
//allocate memory to copy array array
char **existing_c = (char **)calloc(length + 2, sizeof(char *));
for (int i = 0; i < length; i++) //copy original array into new array
{
existing_c[i] = existing[i];
}
//possible memory leak error
strncat(existing_c, add, sizeof(existing_c) - strlen(existing_c) - 1);
existing_c[sizeof(existing_c)-1] = '\0';
//possible memory leak error
strncpy(existing, existing_c, sizeof(existing - 1));
s_copy[sizeof(destsize)-1] = '\0'; //error here
free(existing);
return existing_c;
}
void free_array(char **strings) //free's data in array, should be fine
{
int length = 0;
for (; strings[length]; length++)
{
}
strings = (char **)calloc(length + 2, sizeof(char *));
}
My main function:
#include<string.h>
#include<stdio.h>
#include<stdlib.h>
int main(){ //should be fine
char **array = NULL;
char **test;
array = (char **)calloc(1, sizeof(char *)); //array has no strings yet
array = alloc_str(array, "test_1");
array = alloc_str(array, "test_2");
array = alloc_str(array, "test_3");
for (test = array; *test; test++)
{
printf("%s\n", *test);
}
free_array(array);
}
My error:
Subscript of pointer to function type 'void (const void *, void *, size_t)' (aka 'void (const void *, void *, unsigned long)')
There are multiple problems:
char **alloc_str(char **existing, const char *add)
{
int length = 0; //find the length of the array
for (; existing[length]; length++)
{
}
//allocate memory to copy array array
char **existing_c = (char **)calloc(length + 2, sizeof(char *));
for (int i = 0; i < length; i++) //copy original array into new array
{
existing_c[i] = existing[i];
}
////////////////////////////////////
//possible memory leak error
strncat(existing_c, add, sizeof(existing_c) - strlen(existing_c) - 1);
existing_c[sizeof(existing_c)-1] = '\0';
//possible memory leak error
strncpy(existing, existing_c, sizeof(existing - 1));
s_copy[sizeof(destsize)-1] = '\0'; //error here
////////////////////////////////////
free(existing);
return existing_c;
}
The part marked with //////////////////////////////////// does not make much sense.
You allocated an array of pointers. Don't treat it like a string. It is no string.
Instead simply assign the new pointer to the end of the array and add terminator again.
existing_c[length] = add;
existing_c[length+1] = NULL;
With that terminater you could use normal malloc instead of calloc because you assign all elements of the array anyway.
Besides the problem with allocation, you have another memory leak:
void free_array(char **strings) //free's data in array, should be fine
{
int length = 0;
for (; strings[length]; length++)
{
}
strings = (char **)calloc(length + 2, sizeof(char *));
}
You pass a pointer to an array of pointers. This array takes some memory that you allocated with calloc earlier.
Then you allocate a bit more memory and assign the address to local variable string.
This has two problems:
The memory that was allocated earlier is not freed.
The memory you allocate in this function is not accessible outside of that function.
In the end, your free_array function does not free anything but consumes more memory.
Another problem might be present with the strings that you store in that array.
In your example you use string literals. These are static objects and there is no need to free them.
If you will use your functions to store pointers to dynamically allocated string as well, you will need to take care about allocating and freeing the strings as well.
strncat() works on a memory buffer containing a NUL-terminated (aka "C") string:
char buf[10] = {'a', 'b', 'c', '\0'};
strncat(buf, "def", sizeof(buf) - strlen(buf) - 1);
assert(strcmp(buf, "abcdef") == 0); // buf now equals to "abcdef"
https://ideone.com/fWXk8C
(Well, the use of strlen() kinda killed the benefit of strncat() over good ol' strcat() but that's another story...)
So it's very different from what you want to do in your exercise. You actually don't need either of strncat() or strncpy().
I call the function getdata() below inside main(). getdata() reads in characters from the uart and puts them in an array. At the end of the function it writes out the array over uart.
My question is, how can I get this function to return the data? I understand that you cannot return arrays in c and that you should declare a function returning a pointer.
How could I do that with the function below so that I can write out the data in main instead of having to do it inside getdata().
int main(void)
{
getdata();
}
void getdata(void)
{
static uint8_t ndx;
char recChars[6];
char retchar;
ndx = 0;
retchar = getch();
recChars[ndx] = retchar;
ndx++;
if (retchar == '\r'){
recChars[ndx] = '\n';
ndx = 0;
uart_write(UART_D, (uint8_t *)recChars, sizeof(recChars));
}
}
char getch(void) {
uint8_t ch = 0;
chuart_read(UART_D, &ch);
return ((char) ch);
}
You need to make recChars a pointer and allocate dynamic memory to it using malloc() or family. Then, you can return the pointer to the caller and make use of it in the caller.
Something like
char * getdata() //change return type
{
static uint8_t ndx;
char * recChars = NULL; // change to pointer
char retchar;
ndx = 0;
if ( (recChars = malloc(6)) == NULL ) return NULL;
retchar = getch();
recChars[ndx] = retchar;
ndx++;
if (retchar == '\r'){
recChars[ndx] = '\n';
ndx = 0;
//uart_write(UART_D, (uint8_t *)recChars, sizeof(recChars));
}
return recChars; //finally return
}
Remember, the returned pointer needs to be free()-d in the caller, after the usage is over to avoid memory leak.
You have to write a function that returns a pointer to char and use malloc to allocate memory. You must use malloc because arrays declared like this
char v[11];
belong to the automatic storage class which means that they have block scope,they get deleted as soon as your function returns and they are not initialized by default. Dynamic memory instead can be accessed anywhere in your program if you have a pointer to that memory block. You have also remember to free the memory using free() to avoid memory leak. If you returned a pointer to an automatic array,you'd probably get a SIGSEGV because your pointer is holding a memory location that doesn't exist anymore. So you could write something like this:
char *foo(void)
{
char *p = malloc(sizeof(type) * n);
return p;
}
In main
int main(void)
{
char *pointer = foo();
/*Do something*/
free(pointer);
return EXIT_SUCCESS;
}
PS: I apologize for my english
You can write a function that returns a char * and use malloc to create some storage for this table, as mentioned above, or you can simply declare your array as static and return it.
More explicitly:
char *getdata(void) {
static char retChar[6];
...
return retChar;
}
Works. The reason for this is that the array storage is reserved in a special segment.
A version with malloc reserves the storage for your array in the heap, which requires you to free it afterwards:
char *getdata(void) {
char *retChar = (char *) malloc(6);
...
return retChar;
}
main() {
char * ptr = getdata();
...
free(ptr);
}
Finally the only thing you can't do is to declare the array and return it as is, with no static declaration and no malloc... The reason for this is that your
array is allocated in the call-stack and so is potentially lost when you return
from getdata.
In other words, never ever do:
char *getdata(void) {
char retChar[6];
...
return retChar;
}
I would advice you to declare an array in the main() function itself pass the arrray as reference to getdata function, so whenever getdata() gets updated that will be reflected in the array in main().
Note: By the way why are you using sizeof(recChars), which will give 6, but you're only updating upto 2 location. I've incorporated this also in the code
int main(void)
{
char recChars[6];
int Rxd_Len = 0;
Rxd_Len = getdata(&recChars); //Pass the address of array
uart_write(UART_D, (uint8_t *)recChars, Rxd_Len );
}
int getdata(char *ptr_recChars)
{
uint8_t ndx; // removed static since its not a required/mandatory
char retchar;
ndx = 0;
retchar = getch();
*(ptr_recChars + ndx) = retchar; //Asign the value to the array address + offset
if (retchar == '\r'){
ndx++;
*(ptr_recChars + ndx) = '\n';
}
return ndx;
}
char getch(void) {
uint8_t ch = 0;
int ret;
ret = uart_read(UART_D, &ch);
return ((char) ch);
}
UPDATE:
Is it ok to call uart_write() in main() ?
Yes you can do that, but since the uart_write() will be using the length to transfer you need to keep track of it using another variable.
Also, why is this line necessary? What does it do*(ptr_recChars + ndx) = retchar;?
ptr_recChars is a pointer which points to the array recChars[6], so using this pointer we can update the array recChars[6] even though it is declared in main(), *(ptr_recChars + ndx) , here ndx is 0 so the first element of array is updated, then after that you increment ndx then, using the pointer variable we can point to the new updated location by *(ptr_recChars + ndx) (since ndx is new value now)
Also, I should the & operator in getdata(&recChars);
No, the array name itself is a pointer so for recChars[6] simplay giving recChars alone will give the base address of the array, also note recChars and &recChars[0] means same. So if you give &recChars it means recChars is a address then adding &recChars assumes the address of a address which will give you an invalid value in your expression.
Say for example I have a function called from main that returns a pointer:
EDIT
: I was a little unclear, sorry! Let's say I used a scanf in the main() and then I passed this into the function, and I wanted to copy the argument into a new pointer then return that one.
main(void)
{
char *word = malloc(50);
scanf("%s", word);
printf("%s", function(word));
}
char *function(char *array)
{
char *a = malloc(50);
while (*array)
{
*a = *array;
a++;
array++;
}
return a;
}
In this case, if I tried to return the pointer array to main, the pointer would be pointing to the memory location 1 space past where my values are held.
How would I make so I can return the pointer to the first value again?
Thanks!
The best way is to not increment your pointers at all:
char *function(char *array)
{
const size_t maxLength = 49;
char * a = malloc(maxLength + 1);
if ( !a ) {
perror("couldn't allocate memory");
exit(EXIT_FAILURE);
}
size_t i;
for ( i = 0; array[i] && i < maxLength; ++i ) {
a[i] = array[i];
}
a[i] = '\0';
return a;
}
Your original code does not null-terminate a, yet you pass it to printf() as if it's a string. Also, you're leaking memory, since you don't store the pointer you're returning, so you can never free() it.
The basic approach is to use a temporary variable to hold the pointer value you want to keep.
Assuming the only one you care about in your example is a.
char *function(char *array)
{
char *a, *t;
t = a = malloc(50);
while (*array)
{
*t = *array;
++t;
++array;
}
*t = '\0'; /* since the caller passes returned pointer to printf() */
return a; /* a unchanged, so return it */
}
Note that the above will have undefined behaviour if strlen(array) >= 50.
In your example, array is passed by value, so changes to it (repeated incrementing) do not propagate to the caller - there is no need to reset array back to its original value.
The best way would be to not use the parameter to the function, but a copy of it inside the function.
char* pTmp = array;
Also it's better to do ++pTmp rather than array++ because for non-POD types it can be quicker.