Getting string with C function - c

I need to get strings dynamically but as I need to get more than one string, I need to use functions. So far I wrote this
(I put //**** at places i think might be wrong)
char* getstring(char *str);
int main() {
char *str;
strcpy(str,getstring(str));//*****
printf("\nString: %s", str);
return 0;
}
char* getstring(char str[]){//*****
//this part is copy paste from my teacher lol
char c;
int i = 0, j = 1;
str = (char*) malloc (sizeof(char));
printf("Input String:\n ");
while (c != '\n') {//as long as c is not "enter" copy to str
c = getc(stdin);
str = (char*)realloc(str, j * sizeof(char));
str[i] = c;
i++;
j++;
}
str[i] = '\0';//null at the end
printf("\nString: %s", str);
return str;//******
}
printf in the function is working but not back in main function.
I tried returning void, getting rid of *s or adding, making another str2 and tring to strcpy there or not using strcpy at all. Nothing seems to working. Am I misssing something? Or maybe this is not possible at all
//Thank you so much for your answers

Getting the string part can be taken from this answer. Only put a \n as input to the getline funtion.
char * p = getline('\n');
Three things :-
don't cast malloc, check if malloc/realloc is successful and sizeof is not a function.

The problem is not with the function that you are using, but with the way you try copying its result into an uninitialized pointer.
Good news is that you don't have to copy - your function already allocates a string in dynamic memory, so you can copy the pointer directly:
char *str = getstring(str);
This should fix the crash. A few points to consider to make your function better:
main needs to free(str) when it is done in order to avoid memory leak
Store realloc result in a temporary pointer, and do a NULL check to handle out-of-memory situations properly

There are two things to take away from the lesson as it stands now:
(1) You should have one way of returning the reference to the new string, either as an argument passed by reference to the function OR as a return value; you should not be implementing both.
(2) Because the subroutine your teacher gave you allocates memory on the heap, it will be available to any part of your program and you do not have to allocate any memory yourself. You should study the difference between heap memory, global memory, and automatic (stack) memory so you understand the differences between them and know how to work with each type.
(3) Because the memory is already allocated on the heap there is no need to copy the string.
Given these facts, your code can be simplified to something like the following:
int main() {
char *str = getstring();
printf( "\nString: %s", str );
return 0;
}
char* getstring(){
.... etc
Going forward, you want to think about how you de-allocate memory in your programs. For example, in this code the string is never de-allocated. It is a good habit to think about your strategy for de-allocating any memory that you allocate.

Let's simplify the code a bit:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char* getstring()
{
char c = 0;
int i = 0, j = 2;
char *str = NULL;
if ((str = (char*) malloc(sizeof(char))) == NULL)
return NULL;
printf("Input String: ");
while (c = getc(stdin)) {
if (c == '\n') break;
str = (char*) realloc(str, j * sizeof(char));
str[i++] = c;
j++;
}
str[i] = '\0';
printf("getstring() String: %s\n", str);
return str;
}
int main()
{
char *str = getstring();
printf("main() String: %s\n", str);
free(str);
return 0;
}
Then execute:
$ make teststring && ./teststring
cc teststring.c -o teststring
Input String: asdfasfasdf
getstring() String: asdfasfasdf
main() String: asdfasfasdf

Related

Memory allocation of pointer working for fixed variable assigned string but not for user input string

Given program is working for string that is fixed in code for example
char str[100] = "With fixed string this code works"
// Output of the program is "fixed string this code works"
But as soon as I take the str input using
scanf("%s", &str);
it seems error is found with memory allocation because after input is given code returns error value.
The full code is as following
int main (void) {
char str[100];
char *p = (char *)malloc(sizeof(char) * str[100]);
printf("Enter something: ");
scanf("%s", &str);
*p = str;
p = strchr(str, ' ');
puts(p + 1);
// Check for the first space in given input string if found then
while (*p++)
if (*p == ' ' && *++p)
printf("%s", *p);
printf ("\n\n");
return 0;
}
Not sure if for dynamic memory allocation while using scanf function to input string any other allocation process is required
Your malloc has a bug:
char *p = (char *)malloc(sizeof(char)*str[100]);
Let's simplify a bit first.
Don't cast malloc (See: Do I cast the result of malloc?):
char *p = malloc(sizeof(char)*str[100]);
sizeof(char) is (by definition) always 1 on all architectures, regardless of how many bits it occupies, so we can eliminate it:
char *p = malloc(str[100]);
Now we have:
char str[100];
char *p = malloc(str[100]);
You have undefined behavior. str has no values (i.e. unitialized) and you are passing the element that is one past the end of the array, so you have undefined behavior.
So, the length parameter passed to malloc is, thus, random.
You have four problems:
First: with scanf, it should be like that:
scanf("%s",str);
because str is an address. Also make sure that scanf will scan for a string from stdin until it finds space or new line and that what you don't want. So you'd better use fgets(str, 100, stdin);.
Second: with malloc, it should be like that:
malloc(sizeof(char)*100)
because str[100] has not a specific value.
Third: You shouldn't change the address of memory allocated using malloc
malloc function allocates memory in heap and return the address of memory allocated, so you shouldn't do this p = strchr(str, ' '); since strchr will return the address of the first occurrence of the space (the address returned by malloc will be lost) .
Fourth: freeing the memory allocated using malloc
You should free the memory allocated using malloc using free function which take the address of the memory allocated.
Your code should be like that:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main (void) {
char str[100];
char *p = malloc(sizeof(char)*100); //Do NOT cast the return of malloc
printf("Enter something: ");
fgets(str, 100, stdin); //Use fgets to include the spaces between words
strcpy(p, str);//use stcpy to Not change the address of memory allocated
//p = strchr(str, ' '); -->This step will change the address
//of memory allocated using malloc
//puts (p + 1);
/*Instead you can do this*/
char *c = strchr(str, ' ');
puts(c+1);
// Check for the first space in given input string if found then
char *mem =p;
while (*p++)
if (*p == ' ' && *++p)
printf ("%s", p);
printf ("\n\n");
free(mem);
return 0;
}
Scanf %s only reads in a string up to the first whitespace and then stops, which is probably what is causing you problems. I would avoid scanf anyway, it's dangerous and can cause problems if you're not familiar with it. You could try fgets to read from stdin instead. See if this does what you want:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define MAX_LENGTH 100
int main (void)
{
char *str = (char *) malloc (sizeof(char) * MAX_LENGTH + 1);
bzero(str, MAX_LENGTH + 1);
printf("Enter something: ");
fgets(str, MAX_LENGTH, stdin);
// Remove the newline
if ((strlen(str) > 0) && (str[strlen (str) - 1] == '\n'))
{
str[strlen (str) - 1] = '\0';
}
char *p = strchr(str, ' ');
if (p != NULL)
{
// Pointing to the space, which we will skip
p++;
printf ("%s\n\n", p);
}
return 0;
}

Why Does my program have Memory Leaks?

I am trying to create a small c program that will read a string with arbitrary size, without having any memory leaks.
According to my research, the function malloc can be used to allocate a number of bytes for whatever data we want to store.
In my program, I start by allocating space for 0 characters, and I make the pointer word point to it. Then whenever I read a single character, I make a pointer oldWord that points to word, which frees the old memory location once I allocate a larger memory location for the new character.
My research shows that the function free can be used to free an old memory location that is no longer needed. However, I am not sure where I am going wrong. Below you can see my code.
#include <stdio.h>
#include <stdlib.h>
int main(void){
char *word = malloc(0);
printf("Enter name: ");
readWord(word);
printf("Your name is: %s\n", word);
free(word);
word = realloc(0);
printf("Enter name: ");
readWord(word);
printf("Your name is: %s\n", word);
free(word);
return 0;
}
void readWord(char *word){
int i = 0;
char *oldWord, c = getchar();
while(c != ' ' && c != '\n'){
oldWord = word;
word = realloc(word, i + 1);
free(oldWord);
word[i++] = c;
c = getchar();
}
oldWord = word;
word = realloc(word, i + 1);
free(oldWord);
word[i] = '\0';
}
The problem as I see it here is with
free(oldWord);
without checking the failure of realloc(). In case realloc() is success, passing the same pointer to free() causes undefined behavior.
That said, some more notes
a syntax like
word = realloc(word, i + 1);
is dangerous, in case realloc() fails, you'll lose the actual pointer, too. You should use a temporary pointer to hold the return value of realloc(), check for success and only then, assign it back to the original pointer, if you need.
In your code, c is of char type, which may not be sufficient to hold all the possible values returned by getchar(), for example, EOF. You should use an int type, that is what getchar() returns.
There are multiple problems in your code:
you free the pointer you passed to realloc(). This is incorrect as realloc() will have freed the memory already if the block was moved.
Otherwise the pointer is freed twice.
The pointer reallocated bu readWord() is never passed back to the caller.
Allocating a 0 sized block has unspecified behavior: it may return NULL or a valid pointer that should not be dereferenced but can be passed to free() or realloc().
You do not test for end of file: there is an infinite loop if the file does not have a space nor a linefeed in it, for example if the file is empty.
you do not have a prototype for readWord() before it is called.
Here is an improved yet simplistic version:
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
char *readWord(void);
int main(void) {
char *word;
printf("Enter name: ");
word = readWord();
if (word == NULL) {
printf("Unexpected end of file\n");
else
printf("Your name is: %s\n", word);
free(word);
return 0;
}
char *readWord(void) {
int c;
size_t i = 0;
char *word = NULL;
while ((c = getchar()) != EOF && !isspace(c)) {
word = realloc(word, i + 2);
if (word == NULL)
break;
word[i++] = c;
word[i] = '\0';
}
return word;
}

Can't free memory after char *

I have a problem when I am trying to free memory at the end of my program. It breaks all the time. Can you tell me where is the problem please?
int main() {
char* word = NULL;
int i = 0;
char str1[12] = "oko";
while (str1[i]) {
str1[i] = tolower(str1[i]);
i++;
}
printf("%s", str1);
word = (char *)malloc(strlen(str1) + 1);
word = str1;
printf("%s", word);
free(word);
system("pause");
return 0;
}
In your code, by saying
word = str1;
you're overwriting the malloc()-ed pointer
creating memory leak.
Later , by calling free() on word, you're invoking undefined behavior, as the pointer is no longer returned by a malloc() or family of function.
Solution: You should use strcpy() to copy the content of a string.
That said,
Please see this discussion on why not to cast the return value of malloc() and family in C..
int main() should be int main(void) at least, to conform to the standard.

Beginner in C: strings and memory

So this course I'm doing wants us to play around with memory management and pointers. I'm not really fully understanding them.
I keep getting a error:
Segmentation fault (Core dumped)
Apparently I don't have access to memory?
It's something wrong in my slen function?
/*
In these exercises, you will need to write a series of C functions. Where possible, these functions should be reusable (not use global variables or fixed sized buffers) and robust (they should not behave badly under bad input eg empty, null pointers) .
As well as writing the functions themselves, you must write small programs to test those functions.
- Remember, in C, strings are sequences of characters stored in arrays AND the character sequence is delimited with '\0' (character value 0).
----------------------------------------------------
1) int slen(const char* str)
which returns the length of string str [slen must not call strlen - directly or indirectly]
*/
#include <stdio.h>
#include <stdlib.h>
/* Returns the length of a given string */
int slen(const char* str) {
int size = 0;
while(str[size] != '\0') {
size++;
}
return size;
}
/*
2) char* copystring(const char* str)
which returns a copy of the string str. [copystring must not call any variant of strcpy or strdup - directly or indirectly]*/
char* copystring(const char* str) {
int size = slen(str);
char *copy = (char*) malloc (sizeof(char) * (size + 1));
copy[size] = '\0';
printf("before loop");
int i = 0;
while (*str != '0') {
copy[i++] = *str++;
}
return copy;
}
int main() {
char *msg = NULL;
printf("Enter a string: ");
scanf("%s", &msg);
int size = slen(msg);
//printf("The length of this message is %d.", size);
// printf("Duplicate is %s.", copystring(msg));
// Reading from file
}
The problem isn't in your slen function, it happens before that when you're using scanf:
you need to make some space for the string that you're reading from the user using scanf
you don't need to pass the address of your memory buffer to scanf, the variable is already holding an address.
Amended code:
char msg[101];
printf("Enter a string: ");
scanf("%s", msg);
int size = slen(msg);
Alternately, if you're being asked to learn about memory allocation, study the usage of malloc:
char *msg = malloc(101);
printf("Enter a string: ");
scanf("%s", msg);
int size = slen(msg);
While learning about malloc, don't forget to also study up on the associated usage of free.
Also important and significant here is the management of your buffer size: when you make memory for the string that you'll be scanning from the user, you should put a limit on the amount of string that you actually read. There are a few ways to do this: start by studying the scanf format string, where you can use:
scanf("%100s", msg);
You need to assign memory to msg in your main
Either use char msg[10] or use malloc.
char *msg = malloc(10*sizeof(char))

Char concatenation and memory reallocation

I am trying to concatenate single digits to a string:
include <stdio.h>
include <stdlib.h>
include <string.h>
int main() {
char *test="";
int i;
for (i = 0; i < 10; i++)
char *ic;
ic = malloc(2);
sprintf(ic, "%d", i);
// printf("%d\n", strlen(test));
if (strlen(test) == 0)
test = malloc(strlen(ic));
strcpy(test, ic);
} else {
realloc(test, strlen(test) + strlen(ic));
strcat(test, ic);
}
}
printf("%s\n", test);
// printf("%c\n", test);
free(test);
test = NULL;
return 0;
}
My goal is for the result of the final printf ("%s", test) be 0123456789.
Remember that strings are terminated with null characters. When you allocate memory for a string, you must add an extra byte for the null. So you'll need to add 1 to each of your malloc() and realloc() calls. For example:
test = malloc(strlen(ic) + 1);
Remember, also, that realloc() is allowed to "move" a variable to a new location in memory. It may need to do that in order to find enough contiguous unallocated space. It can also return NULL if it's unable to allocate the memory you've requested, so you should call it like this:
char *new_mem = realloc(test, strlen(test) + strlen(ic) + 1);
if (new_mem == NULL) {
// Not enough memory; exit with an error message.
} else {
test = new_mem;
}
A few issues:
char *test=""; - you point test to a constant C string. You don't write to it, but it's dangerous and will compile in C++. The type of "" is const char*.
strlen returns the length of the string not the buffer size. You need to add +1 to include the NULL character. This is your biggest issue.
A short known fixed size small buffer like ic should be allocated on the stack. A simple char array. You also forgot to free() it.

Resources