Array "pointer" on writing the value? - c

I'm try to get from the user 5 strings, and store that string into a array of char string, but, when I try to use the program, the output of the program is allways the same, the last value of user have inputed...
See my code:
#include <stdio.h>
int main()
{
int i = 0;
char *s[50];
char str[50];
for(i=0;i<5;i++)
{
fgets(str, 50, stdin);
s[i] = str;
}
for(i=0;i<5;i++)
printf("%s\n ", s[i]);
}
So, How I can solve this, how I can put the value digited by the user into array, and print the values in other time ???

You need to use strcpy instead of simple assignment.
str is a memory location, all s[i] = str is doing is pointing to the same buffer that is overwritten every time you call fgets.
Something like the following will get you what you need:
#include <stdio.h>
int main()
{
int i = 0;
char s[5][50];
char str[50];
for(i=0;i<5;i++)
{
fgets(str, 50, stdin);
strcpy(s[i],str);
}
for(i=0;i<5;i++)
printf("%s\n ", s[i]);
}

You're creating a single array of characters with the following line
char str[50];
And then every pointer in your array s is pointing to that same single memory location. Everytime you call fgets, you're overwriting the string that is stored in that memory, and as such when you print out each of the strings in the s array, you're getting the same thing: the last value the user entered, which is stored in that single locally allocated block of memory.
Try allocating a new block of memory for each string you read in from the user, and then storing the new memory block's pointer in s:
char *str;
for(i=0;i<5;i++)
{
str = malloc(50);
fgets(str,50,stdin);
s[i] = str;
}

All the pointers of s point to str. So only the last input is stored.
Do:
for(i=0;i<5;i++)
{
fgets(str, 50, stdin);
s[i] = strdup(str);
}
If strdup() is not available (POSIX function) then you can implement it or use malloc() + strcpy().
for(i=0;i<5;i++)
{
fgets(str, 50, stdin);
s[i] = malloc(strlen(str) + 1);
strcpy(s[i], str);
}
And finally free() the pointers in s:
for(i=0;i<5;i++)
{
free(s[i]);
}

Note that char *s[50] only declares 50 pointers (not pointers to 50 characters!); they need to point somewhere before you can copy something to them. What about a 2-dim array of char:
char s[5][50];
and then reading into them with
fgets (s[i], 50, stdin);
Advantage: No need to mess with strdup, malloc and free.

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;
}

Getting string with C function

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

Copy a string into another without \0

I have to put a string into another without \0, I tryed a lot of ways but the string is always dirty.
char string[100];
int pos=0;
fgets(string, 99, stdin);
len = strlen(string);
printf("%d\n", len);
char array[len-1];
for(pos=0; pos<(len-1); pos++)
{
array[j]=string[pos];
j++;
}
printf("%s", string);
printf("%s", array);
In the terminal I have:
dogs dogs(ENTER)
10(ENTER)
dogs dogs(ENTER)
dogs dogs#
I also tryed to remove \0 using another symbol but it can't see '\0' or '\n', help me plz!
Passing pointer to what is not a null-terminated string to %s without length specification will invoke undefined behavior. You have to specify the length to print if you hate terminating null-character for some reason.
Try this:
#include <stdio.h>
#include <string.h>
int main(void) {
int len;
char string[100];
int pos=0;
fgets(string, 99, stdin);
len = strlen(string);
printf("%d\n", len);
char array[len];
for(pos=0; pos<len; pos++)
{
array[pos]=string[pos];
}
printf("%s", string);
printf("%*s", len, array);
return 0;
}
TL;DR You don't want null-terminator, fine. Along with that you should be ready to give up those properties, which comes with the presence of null-terminator. You can no longer make use of the array as string.
To elaborate, in your code, your array array is not null-terminated, so it cannot be used as a string. the %s format specifier expects a pointer to the null-terminated char array (in short, a string)
So, in your code,
printf("%s", array);
invokes undefined behavior by going past the allocated memory in search of the null-terminator.
You can however, print it element by element using a for loop.
To copy without the terminating null, use
memcpy( myCharArray, string, strlen(string) );
(assumes size of myCharArray is sucfficient). To print out the result, you need to use a loop instead of printf.

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))

Array of pointers to strings not storing data as it should

I am trying to store words from a text file in dynamically assigned arrays of chars. I am using pointer arrays to array of chars in order to allocate memory dynamically but for some reason it only stores the last input word to all the arrays of chars I am pointing to, even though in some places that strings should not fit as I allocated space for smaller strings.
Here is the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main () {
char input_string[30];
int string_length, text_length;
// Calculating number of words in text file.
text_length=0;
freopen("in.txt", "r", stdin);
while (scanf("%s", &input_string)!=EOF) {
text_length++;
}
freopen("CON", "r", stdin);
// Dynamically assigning array of chars to store words
char **pointer;
int i;
pointer=(char*)calloc(text_length, sizeof(char));
freopen("in.txt", "r", stdin);
for (i=0;i<text_length;++i) {
scanf("%s", &input_string);
string_length = strlen(input_string);
pointer[i]=(char*)calloc(string_length, sizeof(char));
*(pointer+i)=input_string;
}
for (i=0;i<text_length;++i) {
printf("%s ", *(pointer+i));
}
freopen("CON", "r", stdin);
return 0;
}
*(pointer+i)=input_string
Here input_string is the array and it takes the string from the file. So in the above statement, you are overwriting address of pointer array(allocated memory) with the input string.
pointer[i]=(char*)calloc(string_length, sizeof(char)); // alloacted memory
*(pointer+i)=input_string; //alloacted memory overwritten here pointer[i] and *(pointer+i) both both notifies same
So each index of the array has the same base address of input_string and while de-refer it will give the string which is present in the array(last string). This is the reason for your problem. Better you do memcpy or strcpy.
pointer[i]=(char*)calloc(string_length, sizeof(char));
strcpy(pointer[i], input_string)
or
pointer[i]=(char*)calloc(string_length, sizeof(char));
memcpy(pointer[i], input_string, string_length));
((pointer+i)+string_length)='\0'; /* assigning null character at end of string * /

Resources