I'm new to c so sorry if the question might seem basic. I'm trying to read a string with unknown size from the user and store it in a dynamic array.
This program is going to make accounts for users but I can't successfully scan the username or the password.
Please note that no arrays with fixed size can be used.
Any solutions using files can be used and also be really helpful.
void main(){
user *dummyUser = (user *) malloc(sizeof(user));
dummyUser->next=NULL;
char* password=(char* )malloc(sizeof(char));
char* name=(char* )malloc(sizeof(char));
int i=0;
char c;
char ptr;
while((c=getchar())!=' '){
name[i]=c;
ptr=(char *)realloc(name,sizeof(char));
if(ptr==NULL){
printf("realloc failed");
exit( EXIT_FAILURE );
}
i++;
}
i=0;
while((c=getchar())!='\n'){
password[i]=c;
password=(char *)realloc(password,sizeof(char));
i++;
}
}
realloc seem to work for 1 time, but the next times it returns a null pointer and makes the program crash.
note: I know I have to check if realloc returns a null pointer, I checked it in my watchlist so I didn't write the related code.Thanks for helping.
This isn't doing what you want:
ptr=(char *)realloc(name,sizeof(char));
The second argument of realloc specifies the total number of bytes you want allocated, not just how many more bytes to allocate. You're not extending the array by 1 each time, you're just reallocating the same 1-byte space (sizeof (char) is 1 by definition).
Remember that to store an N-character string, you need to allocate at least N+1 bytes to account for the string terminator.
The typical way to do this is to double the size of the buffer each time - you'll need to keep track of the total buffer size as well as the number of bytes used, like so:
#include <ctype.h> // for the isspace call below:
...
size_t size = 2; // 2 bytes can store a 1-character string
char *name = malloc( size ); // no need for a cast
size_t i = 0;
int c;
...
/**
* You'll probably want to break on EOF and *any* whitespace
* character
*/
while( (c = getchar()) != EOF && !isspace( c ) )
{
if ( i == size )
{
/**
* Double the size of the buffer; again, no need for a cast
*
* Since realloc will return NULL if it can't extend the
* buffer, we want to assign the result to a temporary;
* otherwise we risk overwriting the pointer value in name
* with a NULL pointer and losing our access to the memory
* that's been previously allocated.
*/
char *tmp = realloc( name, size * 2 );
if ( tmp )
{
name = tmp;
size *= 2;
}
else
{
/**
* We were unable to extend the buffer; you can treat this
* as a fatal error and exit immediately, or you can
* try to proceed with the data you have. The previous
* buffer is still allocated at this point.
*
* For this particular program, you'd probably just want
* to exit with an error message at this point, like so:
*/
fputs( "Failed to extend name buffer, exiting...", stderr );
free( name ); // clean up what we've already allocated
exit( 0 );
}
}
name[i++] = c;
}
name[i] = 0; // terminate the string
For convenience's sake, you'll want to move the buffer extension into its own function:
char *extend( char **buf, size_t *size )
{
char *tmp = realloc( *buf, *size * 2 );
if ( tmp )
{
*buf = tmp;
*size *= 2;
}
return tmp;
}
and you'd call it as
while( (c = getchar()) != EOF && !isspace( c ) )
{
if ( i == size )
{
if ( !extend( &name, &size ) )
{
// handle realloc failure
}
}
name[i++] = c;
}
name[i] = 0; // terminate the string
ptr=(char *)realloc(name,sizeof(char));
Please note that this is allocating a single byte. You have done this several times. A C string is an array of characters with a null terminator ('\0') byte at the end. An array that can only hold one byte can only ever hold an empty C string, or lack that null terminator, resulting in undefined behavior.
You likely want to start by allocating a more useful amount of space, and then grow exponentially as your input grows to avoid excessive calls to realloc.
E.g.
size_t allocated_bytes = 64;
char *name = malloc(allocated_bytes);
size_t read_bytes = 0;
char ch;
while ((ch = getchar()) != ' ') {
if (read_bytes >= allocated_bytes - 1) {
allocated_bytes *= 2;
name = realloc(name, allocated_bytes);
}
name[read_bytes++] = ch;
}
name[read_bytes] = '\0';
Checking the return of realloc and for EOF I leave as an exercise for the OP.
Related
I am trying to read a 2d array of values from a file and then trying to copy that to a 2d array of Strings in C. When I ran my code using gdb I got an error that said "munmap_chunk(): invalid pointer" for the line where I "free( tmval )". Then when I ran the code using valgrind I get several "Invalid write size of 8" that happen whenever I try to read or write a string in the 2d array.
The problem happens during this portion of the code:
//allocate memory for transition matrix
tm = (char ***) malloc( numstates*NUM_CLASSES-1*4*sizeof( char ) );
//initialize variables needed for loop
int i = 0;
char *tmval = (char *) calloc( 4, sizeof( char ) );
// read and process all the remaining lines from the file
while( fgets(buf, MAXBUF, fp) != NULL ) {
//add comment detection
if( buf[0] !='#' ){
//allocate transition states for each row using calloc
tm[i] = (char **) calloc( NUM_CLASSES-1, (4*sizeof( char )) );
//strok first with space to skip row number
ptr = strtok( buf, " " );
for( int j = 0;j<NUM_CLASSES-1;j++ ){
//allocate space for string in array
tm[i][j] = (char *) calloc( 4, sizeof( char ) );
tm[i][j] = "-1d";
}
//loop through line to get class numbers and corresponding states
ptr = strtok( NULL, " " );
while( ptr!=NULL ){
int cls = strtol( ptr, end, 10 );
tmval = *end+1;
tm[i][cls] = tmval;
ptr = strtok( NULL, " " );
}
//iterate i
i++;
}
}
//free up tmval and file
fclose( fp );
free( tmval );
free( end );
I believe this maybe the root of the problem, but I'm not sure how to fix it:
tm[i] = (char **) calloc( NUM_CLASSES-1, (3*sizeof( char )) );
The input file for the program is formatted like this
0 0/0d 1/0d 2/1s 3/3s 4/2s 5/2s 6/5s 7/4s 8/4s 10/9d
1 0/9d 1/9d 2/1s 3/1s 4/1s 5/1s 10/9d
The first number is the row number and the number before the / column number for the value that comes after the /.
I think that many of the Valgrind errors are happening because my memory allocation sizes don't match, but I'm not sure how I can fix that because to me they look ok. Also what is causing the error when I try to free up the space for tmval.
You have the line char *tmval = (char *) calloc( 4, sizeof( char ) ); , which allocates some memory and assigns its address to tmval. You later have the line tmval = *end+1; which reassigns tmval the address of some memory that is in buf. Reassigning the value discards your only copy of the address of the memory that the calloc allocated, and is effectively a memory leak. The subsequent free(tmval) is invalid, because the memory that tmval now addresses was not created by calloc, but is inside buf.
Assigning to a pointer does not copy memory. You need memcpy or strcpy (or something similar) to make a copy of the data.
The allocation size in tm = (char ***)malloc( numstates*NUM_CLASSES-1*4*sizeof(char)) is bogus because
NUM_CLASSES-1 must be parenthesized.
you compute the size of a 3D packed array but use types that are inconsistent with this: char ***tm has nothing to do with char tm[numstates][NUM_CLASSES-1][4];
Parsing the line of input is incorrect too:
tmval = *end+1; makes tmval point inside the array buf, so the next statement tm[i][cls] = tmval; makes the entry in the pseudo-2D array point inside the buf array, which will be overwritten immediately upon reading the next line.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define NUM_CLASSES 20
#define MAXBUF 1024
// load_matrix allocates and returns a 3D matrix loaded with the transition states
char (*load_matrix(FILE *fp, int numstates))[NUM_CLASSES - 1][4] {
char buf[MAXBUF];
//allocate memory for transition matrix
char (*tm)[NUM_CLASSES - 1][4] = calloc(sizeof(*tm), numstates);
//initialize transition states for all rows
for (int i = 0; i < numstates; i++) {
for (int j = 0; j < NUM_CLASSES - 1; j++)
strcpy(tm[i][j], "-1d");
}
// read and process all the remaining lines from the file
while (fgets(buf, MAXBUF, fp) != NULL) {
char *ptr, *end;
//add comment detection
if (buf[0] == '#')
continue;
//strok first with space to skip row number
ptr = strtok(buf, " \t\n");
if (!ptr)
continue;
int row = strtol(ptr, &end, 10);
if (ptr == end || row < 0 || row >= numstates) {
// invalid row
continue;
}
//loop through line to get class numbers and corresponding states
while ((ptr = strtok(NULL, " \t\n")) != NULL) {
int cls = strtol(ptr, &end, 10);
if (end > ptr && *end++ == '/' && strlen(end) < 4 && cls >= 0 && cls < NUM_CLASSES - 1)
strcpy(tm[row][cls], end);
}
}
return tm;
}
The matrix is allocated in a single call to calloc() and can be freed with free(tm). Here is an example:
int main() {
char (*tm)[NUM_CLASSES - 1][4] = load_matrix(stdin, 100);
[...]
free(tm);
return 0;
}
Closed. This question needs details or clarity. It is not currently accepting answers.
Want to improve this question? Add details and clarify the problem by editing this post.
Closed 2 years ago.
Improve this question
I am trying to dynamically allocate memory for this C program I have constructed which takes a single string input and reverses it then prints the reversed output. I am very new to C and am unsure on how to use malloc to allocate memory for specified user input. This is the current code I have, we are running these programs in linux, using gcc code.c -o code to compile. Where the file is named code.c
int main(void)
{
char input[256];
char temp;
int i = 0, j = 0;
scanf("%s", input);
j = strlen(input) - 1;
while (i < j)
{
temp = input[j];
input[j] = input[i];
input[i] = temp;
i++;
j--;
}
printf("Reverse = %s", input);
return 0;
}
For a malloc implementation you just need to replace
char input[256];
with
char* input = malloc(256);
if(input == NULL){
//uppon bad allocation NULL will be returned by malloc
perror("malloc");
return EXIT_FAILURE;
}
Since malloc needs the allocated space in bytes normally you would multiply the needed space by the type of variable:
char *input = malloc(256 * sizeof *input);
but, since the size of a char is always 1 byte, in this case you won't need it.
The rest of the code can be the same, then after you use input you can/should free the allocated memory:
free(input);
You will need to #include <stdlib.h>.
Side note:
To avoid buffer overflow it's recommmended that you define a maximum size for scanf specifier which sould be at most the size of the buffer:
scanf("%255s", input);
or to also parse spaces:
scanf("%255[^\n]", input);
Notice that there is one less space, which is reserved for the null terminator, automatically added by scanf and mandatory for the char array to be treated as a string.
Once you get a string from user, you can allocate memory like this.
malloc() returns a pointer to allocated memory, or NULL if it failed.
size_t input_len = strlen(input);
char* mem_data = malloc(input_len + 1); // +1 for null-terminate
if(!mem_data)
{
// failed to allocate memory. do dome error process
}
Following code is copying input reversely to the allocated memory.
int i;
for (i = 0; i < input_len; ++i)
{
mem_data[i] = input[input_len - i - 1];
}
mem_data[input_len] = 0; // null terminate
printf("Reverse = %s", mem_data);
Remember, dynamically allocated memory should be free()d after use.
free(mem_data); // never forget to free memory when you finished using.
To dynamically allocate space in c you need to know beforehand exactly how much space you want to allocate. So, allocate space exactly same size as input string, you need to take length of the string as input.
Sample code will be like below:
int n;
char* input;
int main(){
scanf("%d",&n);
input= (char*)malloc((n+1)*sizeof(char));
scanf("%s",input);
return 0;
}
You can read about dynamic memory allocation here https://www.geeksforgeeks.org/dynamic-memory-allocation-in-c-using-malloc-calloc-free-and-realloc/
The approach that is more often used in books on C for beginners is writing a function that reads character by character from the input stream and reallocates memory dynamically when a new character is read.
Something like the function shown in this demonstrative program below
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char * getline( size_t n )
{
char *s = NULL;
if ( n != 0 )
{
s = malloc( sizeof( char ) );
size_t i = 0;
for ( int c; i < n - 1 && ( c = getchar() ) != EOF && c != '\n'; ++i )
{
s = realloc( s, i + 2 );
if ( s == NULL ) break;
s[i] = c;
}
if ( s ) s[i] = '\0';
}
return s;
}
char * reverse( char *s )
{
if ( *s != '\0' )
{
for ( size_t i = 0, j = strlen( s ); i < --j; i++ )
{
char c = s[i];
s[i] = s[j];
s[j] = c;
}
}
return s;
}
int main(void)
{
const size_t N = 256;
printf( "Enter a string (no more than %zu symbols): ", N );
char *s = getline( N );
if ( s ) printf( "The reversed string is \"%s\"\n", reverse( s ) );
free( s );
return 0;
}
The program output might look like
Enter a string (no more than 256 symbols): Hello Mgert33
The reversed string is "33tregM olleH"
How to allocate initial memory,and increase memory in each user input for a array of strings which that number of columns are known.
for example: ` char* type[20];
I want to allocate initial memory for it and increase space for each scanf("%s", type[i]); which is in the loop.
could you please help Me
You can use dynamic memory allocation for that
char *read_string(void)
{
int c;
int i = 0;
char *s = malloc(1);
printf("Enter a string: \t"); // It can be of any length
/* Read characters until found an EOF or newline character. */
while((c = getchar()) != '\n' && c != EOF)
{
s[i++] = c;
s = realloc(s, i+1); // Add memory space for another character to be read.
}
s[i] = '\0'; // Nul terminate the string
return s;
}
int main(void)
{
char* type[20];
for( size_t i = 0; i < sizeof(type); i++)
type[i] = read_string();
// Do some other stuff
}
Do not forget to free memory when you are done with it.
an array is a a contiguous block of memory, when you declare an array of a certain type, you can no longer increase or decrease its size.
one approach would be for you to declare a reasonable large sized array of char to hold your "string". like this:
const int size=256;
char input[size]; //declares an array of 256 chars
as for inputting actual "strings" in the arary of char, you COULD use scanf but I recommend you use fgets because it is much safer.
while(fgets(input, size, stdin)!=NULL)
{
//do something with input
}
This approach is susceptible to buffer overflow and is not necessarily safe, but is common approach nonetheless
as for your "array of string" problem, you want to allocate everything dynamically. ( if you dynamically allocate a char** and make it point to stack allocated char[] you are asking for big time trouble)
you should use a default size for your char** (say to take in 1000 char* ) and use a default allocation size for each of your char* ,for example 256 *sizeof(char) bytes.
this way you can use realloc every time you exhaust your space.
You can use standard function realloc declared in header <stdlib.h> each time when a new string has to be read.
Here a demonstrative program that instead of reading strings just copies a fixed number of them
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
int main( void )
{
char ( *s )[20] = NULL;
char ( *p )[20] = NULL;
size_t n = 0;
do
{
p = realloc( s, ( n + 1 ) * sizeof( *s ) );
if ( p )
{
s = p;
strcpy( s[n], ( char[] ){ 'A' + n, '\0'} );
++n;
}
} while ( p && n < 10 );
for ( size_t i = 0; i < n; i++ ) puts( s[i] );
free( s );
}
The program output is
A
B
C
D
E
F
G
H
I
J
Pay attention to how the function realloc is used.
If you know that the number of strings can not be less than some constant then you can initially allocate dynamically an array of the size that is equal to this constant.
For example
#define MIN_SIZE 10
//...
char ( *s )[20] = malloc( MIN_SIZE * sizeof( *s ) );
I'm using this function to read, char by char, a text file or a stdin input
void readLine(FILE *stream, char **string) {
char c;
int counter = 0;
do {
c = fgetc(stream);
string[0] = (char *) realloc (string[0], (counter+1) * sizeof(char));
string[0][counter++] = c;
} while(c != ENTER && !feof(stream));
string[counter-1] = '\0';
}
But when I call it, my program crashed and I really don't know why, because I don't forget the 0-terminator and I'm convinced that I stored correctly the char sequence. I've verified the string length, but it appears alright.
This is an error:
do {
c = fgetc(stream);
// What happens here?!?
} while(c != ENTER && !feof(stream));
"What happens here" is that you add c to string before you've checked for EOF, whoops.
This is very ungood:
string[0] = (char *) realloc (string[0], (counter+1) * sizeof(char));
in a loop. realloc is a potentially expensive call and you do it for every byte of input! It is also a silly and confusing interface to ask for a pointer parameter that has (apparently) not been allocated anything -- passing in the pointer usually indicates that is already done. What if string were a static array? Instead, allocate in chunks and return a pointer:
char *readLine (FILE *stream) {
// A whole 4 kB!
int chunksz = 4096;
int counter = 0;
char *buffer = malloc(chunksz);
char *test;
int c;
if (!buffer) return NULL;
while (c = fgetc(stream) && c != ENTER && c != EOF) {
buffer[counter++] = (char)c;
if (counter == chunksz) {
chunksz *= 2;
test = realloc(buffer, chunksz);
// Abort on out-of-memory.
if (!test) {
free(buffer);
return NULL;
} else buffer = test;
}
}
// Now null terminate and resize.
buffer[counter] = '\0';
realloc(buffer, counter + 1);
return buffer;
}
That is a standard "power of 2" allocation scheme (it doubles). If you really want to submit a pointer, pre-allocate it and also submit a "max length" parameter:
void *readLine (FILE *stream, char *buffer, int max) {
int counter = 0;
int c;
while (
c = fgetc(stream)
&& c != ENTER
&& c != EOF
&& counter < max - 1
) buffer[counter++] = (char)c;
// Now null terminate.
buffer[counter] = '\0';
}
There are a few issues in this code:
fgetc() returns int.
Don't cast the return value of malloc() and friends, in C.
Avoid using sizeof (char), it's just a very clumsy way of writing 1, so multiplication by it is very redundant.
Normally, buffers are grown more than 1 char at a time, realloc() can be expensive.
string[0] would be more clearly written as *string, since it's not an array but just a pointer to a pointer.
Your logic around end of file means it will store the truncated version of EOF, not very nice.
Change this line
string[counter-1] = '\0';
to
string[0][counter-1] = '\0';
You want to terminate string stored at string[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;
}