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.
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 have the following simple program that reads character by character a text file. Each time a character is read from the file, must go at the end of the str which is a string. For this reason I made a small function called conc which takes the character, reallocates the str and then takes the character at the end of the string (str[count] = ch).
After the EOF character, I put the '\0' character to the str as an end for the string variable.
My question is why the last printf displays garbage?? Any ideas??
Thanks in advance.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void conc(char* str,char ch,int* count);
int main(int argc,char** argv)
{
char* str = (char*)malloc(sizeof(char));
char ch;
int count = 0,i;
FILE* fp = fopen("path","r");
if(fp == NULL){
printf("No File Found");
return 1;
}
ch=fgetc(fp);
while(ch!=EOF){
conc(str,ch,&count);
ch=fgetc(fp);
}
str[count] = '\0';
printf("%s",str);
free(str);
return(0);
}
void conc(char* str,char ch,int* count){
str[*count] = ch;
(*count)++;
//printf("\n%c",str[(*count)-1]);
str = (char*)realloc(str,(*count)+1);
}
The problem is with how you realloc() the pointer. The changes you do to str will not modify the original pointer in main(). You are only assigning to the copy of the pointer str in conc(). You need to pass a pointer to pointer in order to modify it.
void conc(char** str,char ch,int* count){
(*str)[*count] = ch;
(*count)++;
*str = realloc(*str,(*count)+1);
}
and pass a pointer to it from main():
conc(&str,ch,&count);
Change the prototype to match:
void conc(char** str,char ch,int* count);
Others notes:
1) when realloc() fails it returns NULL and you will lose the original pointer. So you need to use a temporary and assign to the original.
See: Having dynamically allocated an array can I change its size?
2) Casting malloc()/realloc() etc is also dangerous.
3) Always check the return value of malloc() etc to see if the memory allocation failed.
3) Allocating one char at a time is not very efficient. Typical way is to allocate a buffer of size N and double the size when you realloc().
It is not necessary to pass count to your function because you are (or rather, should be) passing it a proper zero terminated string, and the new character should always be added to its end.
If you are going to modify str anyway, it's slightly better to start out with str = NULL. On its first call, set str to occupy 2 bytes to begin with, and add 1 character each next call.
Be careful with char ch; and then using while(ch!=EOF) ..! This will only work when your default char is signed. It will also prematurely stop when you encounter a byte 0FFh in your input.
With these points in mind, I end up with this:
char *conc (char *str, char ch);
int main (void)
{
char *str = NULL;
int ch;
FILE* fp = fopen("path","r");
if(fp == NULL){
printf("No File Found");
return 1;
}
ch=fgetc(fp);
while(ch!=EOF)
{
str = conc (str, ch);
ch = fgetc(fp);
}
printf("%s",str);
free(str);
return 0;
}
char *conc (char *str, char ch)
{
int last_pos;
if (str)
{
last_pos = strlen(str);
str = realloc (str, last_pos+1);
} else
{
str = malloc(2);
last_pos = 0;
}
str[last_pos] = ch;
str[last_pos+1] = 0;
return str;
}
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]);
I want to read input from user using C program. I don't want to use array like,
char names[50];
because if the user gives string of length 10, then the remaining spaces are wasted.
If I use character pointer like,
char *names;
then I need to allocate memory for that in such a way of,
names = (char *)malloc(20 * sizeof(char));
In this case also, there is a possibility of memory wastage.
So, what I need is to dynamically allocate memory for a string which is of exactly same as the length of the string.
Lets assume,
If the user input is "stackoverflow", then the memory allocated should be of 14 (i.e. Length of the string = 13 and 1 additional space for '\0').
How could I achieve this?
Read one character at a time (using getc(stdin)) and grow the string (realloc) as you go.
Here's a function I wrote some time ago. Note it's intended only for text input.
char *getln()
{
char *line = NULL, *tmp = NULL;
size_t size = 0, index = 0;
int ch = EOF;
while (ch) {
ch = getc(stdin);
/* Check if we need to stop. */
if (ch == EOF || ch == '\n')
ch = 0;
/* Check if we need to expand. */
if (size <= index) {
size += CHUNK;
tmp = realloc(line, size);
if (!tmp) {
free(line);
line = NULL;
break;
}
line = tmp;
}
/* Actually store the thing. */
line[index++] = ch;
}
return line;
}
You could have an array that starts out with 10 elements. Read input character by character. If it goes over, realloc another 5 more. Not the best, but then you can free the other space later.
You can also use a regular expression, for instance the following piece of code:
char *names
scanf("%m[^\n]", &names)
will get the whole line from stdin, allocating dynamically the amount of space that it takes. After that, of course, you have to free names.
If you ought to spare memory, read char by char and realloc each time. Performance will die, but you'll spare this 10 bytes.
Another good tradeoff is to read in a function (using a local variable) then copying. So the big buffer will be function scoped.
Below is the code for creating dynamic string :
void main()
{
char *str, c;
int i = 0, j = 1;
str = (char*)malloc(sizeof(char));
printf("Enter String : ");
while (c != '\n') {
// read the input from keyboard standard input
c = getc(stdin);
// re-allocate (resize) memory for character read to be stored
str = (char*)realloc(str, j * sizeof(char));
// store read character by making pointer point to c
str[i] = c;
i++;
j++;
}
str[i] = '\0'; // at the end append null character to mark end of string
printf("\nThe entered string is : %s", str);
free(str); // important step the pointer declared must be made free
}
First, define a new function to read the input (according to the structure of your input) and store the string, which means the memory in stack used. Set the length of string to be enough for your input.
Second, use strlen to measure the exact used length of string stored before, and malloc to allocate memory in heap, whose length is defined by strlen. The code is shown below.
int strLength = strlen(strInStack);
if (strLength == 0) {
printf("\"strInStack\" is empty.\n");
}
else {
char *strInHeap = (char *)malloc((strLength+1) * sizeof(char));
strcpy(strInHeap, strInStack);
}
return strInHeap;
Finally, copy the value of strInStack to strInHeap using strcpy, and return the pointer to strInHeap. The strInStack will be freed automatically because it only exits in this sub-function.
This is a function snippet I wrote to scan the user input for a string and then store that string on an array of the same size as the user input. Note that I initialize j to the value of 2 to be able to store the '\0' character.
char* dynamicstring() {
char *str = NULL;
int i = 0, j = 2, c;
str = (char*)malloc(sizeof(char));
//error checking
if (str == NULL) {
printf("Error allocating memory\n");
exit(EXIT_FAILURE);
}
while((c = getc(stdin)) && c != '\n')
{
str[i] = c;
str = realloc(str,j*sizeof(char));
//error checking
if (str == NULL) {
printf("Error allocating memory\n");
free(str);
exit(EXIT_FAILURE);
}
i++;
j++;
}
str[i] = '\0';
return str;
}
In main(), you can declare another char* variable to store the return value of dynamicstring() and then free that char* variable when you're done using it.
Here's a snippet which I wrote which performs the same functionality.
This code is similar to the one written by Kunal Wadhwa.
char *dynamicCharString()
{
char *str, c;
int i = 0;
str = (char*)malloc(1*sizeof(char));
while(c = getc(stdin),c!='\n')
{
str[i] = c;
i++;
realloc(str,i*sizeof(char));
}
str[i] = '\0';
return str;
}
char* load_string()
{
char* string = (char*) malloc(sizeof(char));
*string = '\0';
int key;
int sizer = 2;
char sup[2] = {'\0'};
while( (key = getc(stdin)) != '\n')
{
string = realloc(string,sizer * sizeof(char));
sup[0] = (char) key;
strcat(string,sup);
sizer++
}
return string;
}
int main()
{
char* str;
str = load_string();
return 0;
}
realloc is a pretty expensive action...
here's my way of receiving a string, the realloc ratio is not 1:1 :
char* getAString()
{
//define two indexes, one for logical size, other for physical
int logSize = 0, phySize = 1;
char *res, c;
res = (char *)malloc(sizeof(char));
//get a char from user, first time outside the loop
c = getchar();
//define the condition to stop receiving data
while(c != '\n')
{
if(logSize == phySize)
{
phySize *= 2;
res = (char *)realloc(res, sizeof(char) * phySize);
}
res[logSize++] = c;
c = getchar();
}
//here we diminish string to actual logical size, plus one for \0
res = (char *)realloc(res, sizeof(char *) * (logSize + 1));
res[logSize] = '\0';
return res;
}