I have a dynamically allocated char array, I want to combine two strings into it, so I tried the following:
char *strcpy2 (char *str1, char *str2)
{
int total = strlen (str1) + strlen (str2) + 1;
char *nstr = malloc (sizeof (char) * total);
while (*str1 != '\0') *nstr++ = *str1++;
while (*str2 != '\0') *nstr++ = *str2++;
*nstr = '\0';
printf ("size: %d\n", strlen (nstr));
return &(nstr[0]);
}
int main (void)
{
char *concat = strcpy2 ("Hello, ", "World.");
puts (concat);
free (concat);
return 0;
}
When I ran it, it printed the size of nstr is 0 and then Segmentation fault (core dumped).
However when I did this:
char *strcpy2 (char *str1, char *str2)
{
int total = strlen (str1) + strlen (str2) + 1;
char *nstr = malloc (sizeof (char) * total);
char *p = nstr;
while (*str1 != '\0') *p++ = *str1++;
while (*str2 != '\0') *p++ = *str2++;
*p = 0;
printf ("size: %d\n", strlen (nstr));
return nstr;
}
It worked fine and printed the correct length of nstr. I'm puzzled, what caused the crash?
You need to return the value of nstr that was originally returned by malloc().
Your first code block increments nstr until it points to the end of the allocated memory. The code then attempts to use and free that address, which is not owned by your program.
You need to save the starting address of the string so you can return it.
In your first case, you increment the nstr constantly, and in the end, you use
printf ("size: %d\n", strlen (nstr));
where nstr points to the final location after all the increment (containing null).Results in 0 length. Then, you return the incremented pointer to the caller and try to free() it. Results in Undefined Behavior.
OTOH, in the second case, you have the pointer to the primarily allocated memory intact, through which you count the string length, returns correct value and later, free()-ing is also proper, so that works as expected.
In the first function, you're returning the wrong pointer. It's pointing at the null terminator of the string, so the length is zero. When you try to free() it, it isn't a pointer you got from malloc(). Undefined behavior results.
You're incrementing the nstr pointer when copying the two strings, and that's the pointer you're using to represent the string itself. Simply copy it in another variable and use it when referring to the string:
char *strcpy2 (char *str1, char *str2)
{
int total = strlen (str1) + strlen (str2) + 1;
char *nstr = malloc (sizeof (char) * total);
char *str = nstr; // the string
while (*str1 != '\0') *nstr++ = *str1++;
while (*str2 != '\0') *nstr++ = *str2++;
*nstr = '\0';
printf ("size: %d\n", strlen (str)); // used here
return str; // and here
}
You can see it in action here: https://ideone.com/ncpVMU
I also took the liberty of fixing your goofy return statement:
return &(nstr[0]);
Related
i have function which is written in c ,in this function i allocate 2 string as temp and found, but i cant free temp string.
i think it may due to using of temp in result array.
can any one helps me.
here is the function.
void split(char* input, char* delim, char** result,int size) {
char* tmp = malloc((strlen(input)) * sizeof(char));
char* found = malloc((strlen(input)) * sizeof(char));
tmp=strcpy(tmp, input);
// #pragma omp parallel for
for (int i=0; i<size; i++) {
found = strstr(tmp, delim);
if (found != NULL) {
int length = found - tmp;
result[i]=malloc((length+1) * sizeof(char));
result[i] = strncpy(result[i], tmp, length);
*(result[i] + length) = '\0';
tmp = found + strlen(delim);
} else {
result[i]=malloc(strlen(tmp) * sizeof(char));
result[i] =strncpy(result[i], tmp, strlen(tmp));
}
}
// free(tmp);
free(found);
}
here size is number of sub strings after split
when i remove the comment of this line:
// free(tmp);
then this err occurs:
munmap_chunk(): invalid pointer
Aborted (core dumped)
can i ask you to help me for writing correct split function
You do assignments to tmp. That means the pointer tmp might no longer point to the same location that malloc returned.
You need to pass the exact same pointer to free that was returned by malloc.
You have the same problem with found, you assign to it and possible change where it points.
Passing an invalid pointer to free leads to undefined behavior.
You also have another problem: You go out of bounds of the original memory allocated and pointed to by tmp. That's because you seem to have forgotten that strings in C are really called null-terminated strings.
When you allocate memory for a string, you need to include space for the null-terminator at the end. And it's not counted by strlen.
Going out of bounds of allocated memory also leads to undefined behavior.
The function does not make a sense.
For starters it invokes undefined behavior
char* tmp = malloc((strlen(input)) * sizeof(char));
char* found = malloc((strlen(input)) * sizeof(char));
tmp=strcpy(tmp, input);
//...
because you allocated to enough memory to store the terminating zero character '\0' of the string input in the character array tmp.
Secondly the function has a memory leak because at first memory was allocated and its address was assigned to the pointer found and then the pointer found was reassigned in the call of strstr in the for loop.
char* found = malloc((strlen(input)) * sizeof(char));
//...
// #pragma omp parallel for
for (int i=0; i<size; i++) {
found = strstr(tmp, delim);
//...
So the address of the early allocated memory is lost and the memory can not be freed.
And this for loop
for (int i=0; i<size; i++) {
is just senseless.
You may not call free neither for tmp nor for found. The pointer found does not point to a dynamically allocated memory and the pointer tmp is being changed within the for loop.
here is my new function. i wrote it in recursive mode.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int get_number_of_occurence(char* string, char* delim) {
char* found = strstr(string, delim);
if(found == NULL || strcmp(found,delim) ==0 ||found =="" ){
return 0;
}else{
return 1+get_number_of_occurence(found+strlen(delim), delim);
}
}
int split(char* input, char* delim, char** result,int array_idx) {
char* found= strstr(input, delim);
if (found==""||strlen(input)==0){
return 0;
}else if(found == NULL){
result[array_idx]=malloc(strlen(input)+1 * sizeof(char));
strncpy(result[array_idx], input, strlen(input));
*(result[array_idx] + strlen(input)) = '\0';
return 0;
}else{
int length = found - input;
result[array_idx]=malloc((length+1) * sizeof(char));
strncpy(result[array_idx], input, length);
*(result[array_idx] + length) = '\0';
return split(found+strlen(delim),delim,result,array_idx+1);
}
}
int main () {
char * delim = "ooo";
char * input="ssooonn";
int size = get_number_of_occurence(input, delim);
printf("size is : %d \n",size);
char *splitted_values[size+1];
split(input, delim,splitted_values,0);
for (int i=0; i<(size+1); i++) {
printf("%s\n",splitted_values[i]);
free(splitted_values[i]);
}
}
in this code, first i count the number of occurrence of delimiter.
then i create array in that size and fill it with the help of split function.
thanks for helping.
#include <stdio.h>
#include <stdlib.h>
int ft_strlen(char *str)
{
int i = 0;
if (str)
while (str[i])
i++;
return (i);
}
void ft_append(char **str, char c)
{
int len = ft_strlen(*str);
char *str2 = *str;
char *newstr = malloc(len + 2);
int i = 0;
if (len != 0)
{
while (i < len)
{
newstr[i] = str2[i];
i++;
}
}
newstr[i] = c;
newstr[i + 1] = '\0';
*str = newstr;
//this line causes *str to also be freed.
// free(newstr);
}
int main()
{
char *str;
ft_append(&str, 'x');
ft_append(&str, 'y');
ft_append(&str, 'z');
printf("str = %s\n", str);
}
This code works as intended. printf returns xyz. But I am wondering if it is okay for me to not use free() in ft_append? I always read that when a new array is created using malloc I should follow up with free when I am not using the array anymore, but when I type free(newstr), str also gets free resulting in printf returning nothing.
For starters the program has undefined behavior because the pointer str defined in main was not initialized and has an indeterminate value.
char *str;
So at least calling the function ft_strlen for such a pointer
int len = ft_strlen(*str);
invokes undefined behavior.
Also the function ft_append produces memory leaks because early allocated memory the address of which is stored in the pointer str is not freed in subsequent calls of the function.
You need initially to set the pointer str to NULL
char *str = NULL;
and within the function ft_append to use the function realloc instead of malloc.
The program can look the following way
#include <stdio.h>
#include <stdlib.h>
size_t ft_strlen( const char *str )
{
size_t i = 0;
while ( str[i] ) i++;
return i;
}
int ft_append( char **str, char c )
{
size_t len = *str == NULL ? 0 : ft_strlen( *str );
char *newstr = realloc( *str, len + 2 );
int success = newstr != NULL;
if ( success )
{
newstr[len] = c;
newstr[len + 1] = '\0';
*str = newstr;
}
return success;
}
int main( void )
{
char *str = NULL;
ft_append( &str, 'x' );
ft_append( &str, 'y' );
ft_append( &str, 'z' );
printf( "str = %s\n", str );
free( str );
}
Yes its a problem as your program will have memory leaks , where information you have put in memory will stay there even after your program has exited.
look at a program called Valgrind Website and Install it.
Run valgrind --leak-check=yes nameofyourprogram and it will indicate how much memory is leaked .
The problem is malloc() allocates memory randomly which means that once the memory leak happens its hard to trace and delete unless you restart you computer ,A lot of memory leaks can cause out of memory issues if this was a big project.
In Short
free(newstr);
newstr=NULL;
Also use ((len +2 )* sizeof(char)) Instead so the malloc is char size based
At the end of ft_append the old value of *str must be freed:
if (str2 != NULL) {
free(str2);
}
You must decide whether *str is allowed to be NULL.
But consider doing ft_append twice. then there are three values of *str the first two needing to be freed in ft_append. After calling ft_append, you lose the old *str.
The other issues are already addressed in the older answers.
I'm fairly new to C and I'm trying to work out dynamic memory allocation for reading from a file. At least I think that's what I'm doing.
Anyway, this code works:
int readfromfile(FILE *filepointer)
{
size_t size = 2;
char *str = (char *) malloc(sizeof(char));
int character = 0;
size_t counter = 0;
while((character = fgetc(filepointer)) != EOF)
{
str = (char *) realloc(str, size);
str[counter] = (char) character;
size ++;
counter++;
}
str[counter] = '\0';
printf("+%s+", str);
free(str);
return 0;
}
And this code does not:
int main()
{
char *str = (char *) malloc(sizeof(char));
...
readfromfile(ifpointer, &str);
}
int readfromfile(FILE *filepointer, char **str)
{
size_t size = 2;
int character = 0;
size_t counter = 0;
while((character = fgetc(filepointer)) != EOF)
{
*str = (char *) realloc(*str, size);
*str[counter] = (char) character;
size ++;
counter++;
}
str[counter] = '\0';
printf("+%s+", *str);
free(str);
return 0;
}
I cannot understand why because as far as I understand I'm sending a pointer to the location of the char array to the function and accessing the data everytime. The compilers shows no error messages, it just loops through once and on the second loop crashes after the realloc every time. The character assigned to the first value is garbage too.
I have spent an age trying to get this to worked and done a lot of research so I apologise if I've missed a solution but I'm truly stuck at this point.
You get a crash because
*str[counter] = (char) character;
is the same as
*(str[counter]) = (char) character;
as opposed to
(*str)[counter] = (char) character;
which is actually what you wanted. Read Operator Precedence on Wikipedia. You'll find that [] has more precedence than the * (dereference operator).
Also, the cast here, as well as in the calls to realloc and malloc, is unnecessary. Don't forget to check the return value of realloc, malloc etc to see if they were successful in allocating memory.
Now, you have another problem: free(str); in the second code should be free(*str);. Note that after *str has been freed from the function, you aren't supposed to read or write into this memory location from main as it has now become invalid for you to tamper with.
in your int readfromfile(FILE *filepointer, char **str) the parameter char **str is actually the same as char *str[], which means **str is expecting an array of char pointers. however you're passing to it char *str which is just an array of char
when you use readfromfile(...) you should do it this way (something like...):
char *str[2] = {"some char array", "another char array"};
readfromfile(ifpointer, str);
or:
char *a = "this char array";
char **str = &a[0];
readfromfile(ifpointer, str);
you'll get the idea...
I've written my own getline function following K&R c book
void getline(char * const str)
{
int c;
char* temp = str;
while ((c=getchar()) != '\n') {
*temp = c;
temp++;
}
*temp = '\0'
}
and it's used to initialize strings
char *str1, *str2;
printf("Type string 1: ");
getline(str1);
printf("Type string 2: ");
getline(str2);
Just wonder that, what if the memory locations str1 and str1 point to are very close, then getline(str2) overwrites contents in string 1?
It that's possible how could I avoid it? THANKS!
Update:
Yes the program stops executing the above code snippet but the code below works:
#include <stdio.h>
main()
{
char* str;
char* temp = str;
int c;
while ((c=getchar()) != '\n') {
*temp = c;
++temp;
}
*temp = '\0';
printf("%s\n", str);
}
Here the str is also uninitialized character pointer but why deoesn't it give me an error?
What you have is Undefined Behavior.
Explanation:
You declared two pointers to char:
char *str1, *str2;
but you haven't initialized them. They point to some "random" memory location as they are uninitialized.
Then, you pass str1 and str2 to getline and here:
char* temp = str;
temp points to where str points to. Then, in the loop,
*temp = c;
you write to this memory location. This writes into an invalid memory location. And invokes UB.
Fix:
You can use an automatic array with a fixed size:
char str1[101], str2[101];
Note that you should add a check in the loop in the getline function which breaks the loop when the user has entered 100 characters so that there won't be a buffer overflow.
A better solution would be to use dynamic memory allocation. You need to use malloc and realloc for that. These functions require the stdlib.h header.
Fixed code (untested):
char* getline()
{
char* str;
int c, size = 10, counter = 0;
str = malloc(size); /* Allocate `size` memory */
if(str == NULL)
{
printf("malloc failed to allocate memory");
exit(-1); /* Exit the program */
/* Or
return NULL;
*/
}
while ((c = getchar()) != '\n' && c != EOF) { /* Added check for EOF as well */
str[counter] = c;
counter++;
if(counter == size)
{
char* temp = str; /* Backup in case realloc fails */
size += 10; /* Which is the same as `size = size + 10` */
str = realloc(str, size); /* realloc size(20) memory */
if(str == NULL) /* If realloc failed */
{
printf("reallocing memory failed");
str = temp; /* str is NULL, retrieve the original contents */
break; /* Break out of the loop */
}
}
}
str = realloc(str, counter + 1); /* realloc `counter + 1` memory */
str[counter] = '\0';
return str;
}
and in the calling function,
char* str1 = getline();
if(str1)
puts(str1);
free(str1);
char* str2 = getline();
if(str2)
puts(str2);
free(str2);
str1 and str2 are not initialized thus it'll be undefined behaviour. You can access to not allowed memory which will crash your program.
You have to allocate enough memory for each pointer and pass its size to get line function to ensure you write only in allocated memory.
str1 and str2 are uninitialized.Right now you write (*temp = c;) at invalid (or unauthorized) memory location invoking UB .
First you need to allocate memory to str1 and str2 .
str1=malloc(100); // check return
str2=malloc(100);
To be able to write into that memory location.
Just wonder that, what if the memory locations str1 and str1 point to are very close, then getline(str2) overwrites contents in string 1?It that's possible how could I avoid it?
And as far as you concern , memory allocated by these malloc won't overlap (will be two different contagious memory blocks) , so if you also tend to write beyond these memory location ,you will invoke undefined behaviour (if you are lucky segmentation fault ) . So, IMHO, there won't be any case of str2 over-writing str1.
I have to make a function which concatenates two strings but I have to add a '\n' after the first word. I figured everything out and for some reason it doesn't print out anything. Any ideas? It probably has to do something with the pointers. I just can't get my head around them. Here's the code.
char *function(char *s1, char *s2){
char *newStr;
int size;
size = strlen(s1) + strlen(s2);
newStr = (char *)malloc((size+1)*sizeof(char));
while(*s1!= '\0'){
*newStr = *s1;
newStr++;
s1++;
}
*newStr = '\n';
newStr++;
while(*s2 != '\0'){
*newStr = *s2;
newStr++;
s2++;
}
*newStr = '\0';
return newStr;
}
int main (int argc, const char * argv[]) {
char *str1 = "Hello";
char *str2 = "World";
printf("%s",function(str1, str2));
return 0;
}
So as a result I should get:
Hello
World
but I'm not getting anything back.
You are returning a pointer to the end of the buffer rather than a pointer to the start of the buffer. Look at the last two lines of the function:
*newStr = '\0';
return newStr;
Clearly this returns a pointer to the null char, i.e. the empty string.
Solve the problem by introducing a temporary pointer which you will use to step through the output buffer. Then you can return the pointer to the beginning of the output buffer.
char *function(char *s1, char *s2){
int size = strlen(s1) + strlen(s2) + 2;//one for '\n', one for '\0'
char *result = malloc(size);
char *p = result;
while(*s1 != '\0'){
*p = *s1;
p++;
s1++;
}
*p = '\n';
p++;
while(*s2 != '\0'){
*p = *s2;
p++;
s2++;
}
*p = '\0';
return result;
}
You also need to allocate an extra char for the \n, as shown above. Finally, your calling code never frees the memory allocated by function.
I would take a look at two things:
how much space you're allocating for the new string, and compare that with how many characters you're actually writing to that string.
where in the string your returned pointer is pointing to.
You return from function() a pointer to the last element in the allocated char[] – instead of returning the pointer to the first element.
Every time you do newStr++; you increase the actual pointer you later return. to solve it you can do one of these:
create a copy of the pointer newStr, which is initialized to be the same as newStr and increase it - leave newStr as it is.
create an index [let it be i] and increase it, and use newStr[i] to access the allocated array.
I have debugged the code for you. Here is the debugged code:
char *function(char *s1, char *s2) {
char *newStr, *str;
int size;
size = strlen(s1) + strlen(s2);
newStr = (char *) malloc((size + 2) * sizeof(char));
str = newStr;
while (*s1 != '\0') {
*(newStr++) = *(s1++);
}
*newStr = '\n';
newStr++;
while (*s2 != '\0') {
*newStr = *s2;
newStr++;
s2++;
}
*newStr = '\0';
return str;
}
int main(int argc, const char *argv[]) {
char *str1 = "Hello";
char *str2 = "World";
printf("%s", function(str1, str2));
return 0;
}
The actual problem was that as you incremented newStr until the last, when you returned it from function() it was pointing to the end of the buffer. ie '\0'. That is why it didn't show up. Now In the above code I have introduced a variable str that points at the beginning of the string newStr.
Hope you understood..
Peace...