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'
Related
I am attempting to create a structure (2nd) in a structure (1st) with dynamic memory allocation. For the sequence of steps below (case 1), where I call malloc for a pointer to the 2nd structure before calling realloc for the 1st structure, I see garbage when printing the value of the member (str[0].a1) in the first structure. If I place the same realloc code before malloc (case 2), there are no issues.
#include<stdio.h>
#include<stdlib.h>
typedef struct string2_t {
int a2;
} string2;
typedef struct string1_t {
int a1;
string2 * b;
} string1;
string1 * str = NULL;
int size = 0;
string1 test(int val){
// case 2
//str = (string1 *) realloc(str, size*sizeof(string1));
string1 S;
S.a1 = val;
size += 1;
S.b = (string2 *) malloc(2*sizeof(string2));
S.b[0].a2 = 11;
S.b[1].a2 = 12;
// case1
str = (string1 *) realloc(str, size*sizeof(string1));
return S;
}
int main() {
size += 1;
str = (string1 *) malloc(size*sizeof(string1));
str[0] = test(10);
printf("value of a:%d\n",str[0].a1);
str[1] = test(20);
printf("value of a:%d\n",str[0].a1);
return(0);
}
I can see that memory location changes for case 1, but I don't quite understand why doesn't pointer point to the right contents (str[0].a1 shows junk). I haven't returned the address of 1st structure before realloc, so I feel it should have worked. Could someone explain why it's pointing to garbage?
As has been stated by several in the comments, lines like this cause undefined behavior:
str[0] = test(10);
The test() function reallocates str, and this is not sequenced with retrieving the address of str[0] as the location to store the result. It's very likely to be compiled as if it had been written
string1 *temp = str;
temp[0] = test(10);
temp caches the old address of str from before the realloc(), and this is invalid after the function returns.
Change your code to:
string1 temp = test(10);
str[0] = temp;
Better design would be to reorganize the code so that all maintenance of the str array is done in one place. test() should be a black box that just allocates the string1 object, while main() allocates and reallocates str when assigning to it.
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
I have allocated an array of chars and I want to add another char at the beginning of the array while maintaining the order.
Ex. If pointer points to the beginning of 4 char blocks: A,B,C,D -> pointer[0]==A . If I add E the block of memory should look: E,A,B,C,D -> pointer[0]==E.
Additionally I want to do it in one line, without manually copying elements to another block and erasing the first. All functions have to be from C standard library.
I have though of something like pointer = realloc(pointer-1, (n-1)*size), but I'm not guaranteed that pointer-1 is free.
Thankful for your answers in advance
Adding space before the memory block rather than after it using realloc
Re-allocate with realloc() and then shift the data with memove().
I want to do it in one line,
Either use a helper function like below or employ a long hard to read un-maintainable line.
char *realloc_one_more_in_front(char *ptr, size_t current_size) {
void *new_ptr = realloc(ptr, sizeof *ptr * (current_size + 1));
if (new_ptr == NULL) {
return NULL; // Failure to re-allocate.
}
ptr = new_ptr;
memmove(ptr + 1, ptr, sizeof *ptr * current_size);
return ptr;
}
Sample usage. For simplicity of example, error handling omitted.
size_t current_size = 4;
char *ptr = malloc(current_size);
for (size_t i = 0 ; i<current_size; i++) {
ptr[i] = 'A' + i;
}
ptr = realloc_one_more_in_front(ptr, current_size++);
ptr[0] = 'E';
printf("%.*s\n", (int) current_size, 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 am having trouble understanding how to assign memory
to a double pointer.
I want to read an array of strings and store it.
char **ptr;
fp = fopen("file.txt","r");
ptr = (char**)malloc(sizeof(char*)*50);
for(int i=0; i<20; i++)
{
ptr[i] = (char*)malloc(sizeof(char)*50);
fgets(ptr[i],50,fp);
}
instead of this I just assign a large block of memory and
store the string
char **ptr;
ptr = (char**)malloc(sizeof(char)*50*50);
would that be wrong? And if so why is it?
Your second example is wrong because each memory location conceptually would not hold a char* but rather a char. If you slightly change your thinking, it can help with this:
char *x; // Memory locations pointed to by x contain 'char'
char **y; // Memory locations pointed to by y contain 'char*'
x = (char*)malloc(sizeof(char) * 100); // 100 'char'
y = (char**)malloc(sizeof(char*) * 100); // 100 'char*'
// below is incorrect:
y = (char**)malloc(sizeof(char) * 50 * 50);
// 2500 'char' not 50 'char*' pointing to 50 'char'
Because of that, your first loop would be how you do in C an array of character arrays/pointers. Using a fixed block of memory for an array of character arrays is ok, but you would use a single char* rather than a char**, since you would not have any pointers in the memory, just chars.
char *x = calloc(50 * 50, sizeof(char));
for (ii = 0; ii < 50; ++ii) {
// Note that each string is just an OFFSET into the memory block
// You must be sensitive to this when using these 'strings'
char *str = &x[ii * 50];
}
char **ptr;
fp = fopen("file.txt","r");
ptr = (char**)malloc(sizeof(char*)*50);
for(int i=0; i<50; i++)
{
ptr[i] = (char*)malloc(sizeof(char)*50);
fgets(ptr[i],50,fp);
}
fclose(fp);
may be your typo mistake but your loop should be of 50 instead of 20 if you are looking for 50 x 50 matrix. Also after allocation of memory mentioned above you can access the buffer as ptr[i][j] i.e in the 2D format.
A double pointer is just a pointer to another pointer. So you can allocate it like this:
char *realptr=(char*)malloc(1234);
char **ptr=&realptr;
You have to keep in mind where your pointer is stored at (in this example the double pointer points to a pointer variable on the stack so it's invalid after the function returns).
i will give one example, which might clear of the doubt,
char **str; // here its kind a equivalent to char *argv[]
str = (char **)malloc(sizeof(char *)*2) // here 2 indicates 2 (char*)
str[0]=(char *)malloc(sizeof(char)*10) // here 10 indicates 10 (char)
str[1]=(char *)malloc(sizeof(char)*10) // <same as above>
strcpy(str[0],"abcdefghij"); // 10 length character
strcpy(str[1],"xyzlmnopqr"); // 10 length character
cout<<str[0]<<endl; // to print the string in case of c++
cout<<str[1]<<endl; // to print the string in case of c++
or
printf("%s",str[0]);
printf("%s",str[1]);
//finally most important thing, dont't forget to free the allocated mem
free(str[0]);
free(str[1]);
free(str);
other simpler way to memorize
Case -1 :
step-1 : char *p;
step -2 :
please read it like below
char (*p); ==> p is a pointer to a char
now you just need to do malloc for the type (step-2) without braces
i.e., p = malloc(sizeof(char) * some_len);
Case -2 :
step-1 : char **p;
step -2 :
please read it like below
char* (* p); ==> p is a pointer to a char *
now you just need to do malloc for the type (step-2) without braces
i.e., p = malloc(sizeof(char *) * some_len);
Case -3 :
No one uses this but just for sake of explanation
char ***p;
read it as,
char** (*p); ==> p is a pointer to a char** (and for this check case-2 above)
p = malloc(sizeof(char**) * some_len);
Adding to Pent's answer, as he correctly pointed out, you will not be able to use this double pointer once the function returns, because it will point to a memory location on the function's activation record on stack which is now obsolete (once the function has returned). If you want to use this double pointer after the function has returned, you may do this:
char * realptr = (char *) malloc(1234);
char ** ptr = (char **) malloc(sizeof(char *));
*ptr = realptr;
return ptr;
The return type of the function must obviously be char ** for this.
well, this is how I do it:
#include <stdlib.h>
int main(void)
{
int i = -1; // just a counter
int j = 5; // how many strings
char *s[j];
while(++i < j)
s[i] = malloc(sizeof(char*)); // allocating avery string separately
return (0);
}
this also works:
char **allocate(int lines)
{
int i = -1;
char **s = malloc(sizeof(char *) * lines); // allocating lines
while (++i < lines)
{
s[i] = malloc(sizeof(char*)); // alicating line
scanf("%s", s[i]);
}
return (s);
}
int main(int ac, char *av[])
{
int lines = 5; // how many lines
char **s = allocate(lines);
return (0);
}
Double pointer is, simply put, a pointer to a pointer,
In many cases it is used as an array of other types.
For example, if you want to create an array of strings you can simply do:
char** stringArray = calloc(10, 40);
this will create an array of size 10, each element will be a string of length 40.
thus you can access this by stringArray[5] and get a string in the 6th position.
this is one usage, the others are as mentioned above, a pointer to a pointer, and can be allocated simply by:
char* str = (char*)malloc(40);
char** pointerToPointer = &str //Get the address of the str pointer, valid only in the current closure.
read more here:
good array tutorial