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.
i'm trying to implement little program that takes a text and breaks it into lines and sort them in alphabetical order but i encountered a little problem, so i have readlines function which updates an array of pointers called lines, the problem is when i try to printf the first pointer in lines as an array using %s nothing is printed and there is no errors.
I have used strcpy to copy an every single text line(local char array) into a pointer variable and then store that pointer in lines array but it gave me the error.
Here is the code:
#include <stdio.h>
#define MAXLINES 4
#define MAXLENGTH 1000
char *lines[MAXLINES];
void readlines() {
int i;
for (i = 0; i < MAXLINES; i++) {
char c, line[MAXLENGTH];
int j;
for (j = 0; (c = getchar()) != '\0' && c != '\n' && j < MAXLENGTH; j++) {
line[j] = c;
}
lines[i] = line;
}
}
int main(void) {
readlines();
printf("%s", lines[0]);
getchar();
return 0;
}
One problem is the following line:
lines[i] = line;
In this line, you make lines[i] point to line. However, line is a local char array whose lifetime ends as soon as the current loop iteration ends. Therefore, lines[i] will contain a dangling pointer (i.e. a pointer to an object that is no longer valid) as soon as the loop iteration ends.
For this reason, when you later call
printf("%s", lines[0]);
lines[0] is pointing to an object whose lifetime has ended. Dereferencing such a pointer invokes undefined behavior. Therefore, you cannot rely on getting any meaningful output, and your program may crash.
One way to fix this would be to not make lines an array of pointers, but rather an multidimensional array of char, i.e. an array of strings:
char lines[MAXLINES][MAXLENGTH+1];
Now you have a proper place for storing the strings, and you no longer need the local array line in the function readlines.
Another issue is that the line
printf("%s", lines[0]);
requires that lines[0] points to a string, i.e. to an array of characters terminated by a null character. However, you did not put a null character at the end of the string.
After fixing all of the issues mentioned above, your code should look like this:
#include <stdio.h>
#define MAXLINES 4
#define MAXLENGTH 1000
char lines[MAXLINES][MAXLENGTH+1];
void readlines() {
int i;
for (i = 0; i < MAXLINES; i++) {
char c;
int j;
for (j = 0; (c = getchar()) != '\0' && c != '\n' && j < MAXLENGTH; j++) {
lines[i][j] = c;
}
//add terminating null character
lines[i][j] = '\0';
}
}
int main(void) {
readlines();
printf("%s", lines[0]);
return 0;
}
However, this code still has a few issues, which are probably unrelated to your immediate problem, but could cause trouble later:
The function getchar will return EOF, not '\0', when there is no more data (or when an error occurred). Therefore, you should compare the return value of getchar with EOF instead of '\0'. However, a char is not guaranteed to be able to store the value of EOF. Therefore, you should store the return value of getchar in an int instead. Note that getchar returns a value of type int, not char.
When j reaches MAX_LENGTH, you will call getchar one additional time before terminating the loop. This can cause undesired behavior, such as your program waiting for more user input or an important character being discarded from the input stream.
In order to also fix these issues, I recommend the following code:
#include <stdio.h>
#define MAXLINES 4
#define MAXLENGTH 1000
char lines[MAXLINES][MAXLENGTH+1];
void readlines() {
int i;
for (i = 0; i < MAXLINES; i++)
{
//changed type from "char" to "int"
int c;
int j;
for ( j = 0; j < MAXLENGTH; j++ )
{
if ( (c = getchar()) == EOF || c == '\n' )
break;
lines[i][j] = c;
}
//add terminating null character
lines[i][j] = '\0';
}
}
int main(void) {
readlines();
printf("%s", lines[0]);
return 0;
}
Problem 1
char *lines[MAXLINES];
For the compiler it makes no difference how you write this, but for you, as you are learning C, maybe it is worth consider different spacing and naming. Question is: what is lines[]? lines[] is supposed to be an array of strings and hold some text inside. So lines[0] is a string, lines[1] is a string and so on. As pointed in a comment you could also use char lines[MAX_LINES][MAX_LENGTH] and have a 2D box of NxM char. This way you would have a pre-determined size in terms of number and size of lines and have simpler things at a cost of wasting space in lines of less than MAX_LENGTH chars and having a fixed number of lines you can use, but no need to allocate memory.
A more flexible way is to use an array of pointers. Since each pointer will represent a line, a single one
char* line[MAXLINES];
is a better picture of the use: line[0] is char*, line[1] is char* and so on. But you will need to allocate memory for each line (and you did not) in your code.
Remember int main(int argc, char**argv)
This is the most flexible way, since in this way you can hold any number of lines. The cost? Additional allocations.
size_t n_lines;
char** line;
This may be the best representation, as known by every C program since K&R.
Problem 2
for (
j = 0;
(c = getchar()) != '\0' && c != '\n' && j < MAXLENGTH;
j++) {
line[j] = c;
}
lines[i] = line;
This loop does not copy the final 0 that terminates each string. And reuses the same line, a char[] to hold the data as being read. And the final line does not copy a string, if one existed there. There is no one since the final 0 was stripped off by the loop. And there is no data too, since the area is being reused.
A complete C example of uploading a file to a container in memory
I will let an example of a more controlled way of writing this, a container for a set of lines and even a sorting function.
a data structure
The plan is to build an array of pointers as the system does for main. Since we do no know ahead the number of lines and do not want this limitation we will allocate memory in groups of blk_size lines. At any time we have limit pointers to use. From these size are in use. line[] is char* and points to a single line of text. The struct is
typedef struct
{
size_t blk_size; // block
size_t limit; // actual allocated size
size_t size; // size in use
char** line; // the lines
} Block;
the test function
Block* load_file(const char*);
Plan is to call load_file("x.txt") and the function returns a Block* pointing to the array representing the lines in file, one by one. Then we call qsort() and sort the whole thing. If the program is called lines we will run
lines x.txt
and it will load the file x.txt, show its contents on screen, sort it, show the sorted lines and then erase everything at exit.
main() for the test
int main(int argc, char** argv)
{
char msg[80] = {0};
if (argc < 2) usage();
Block* test = load_file(argv[1]);
sprintf(msg, "==> Loading \"%s\" into memory", argv[1]);
status_blk(test, msg);
qsort(test->line, test->size, sizeof(void*), cmp_line);
sprintf(msg, "==> \"%s\" after sort", argv[1]);
status_blk(test, msg);
test = delete_blk(test);
return 0;
};
As planned
load_file() is the constructor and load the file contents into a Block.
status_blk() shows the contents and accepts a convenient optional message
qsort() sorts the lines using a one-line cmp_line() function.
status_blk() is called again and shows the now sorted contents
as in C++ delete_blk() is the destructor and erases the whole thing._
output using main() as tlines.c for testing
PS M:\> .\lines tlines.c
loading "tlines.c" into memory
Block extended for a total of 16 pointers
==> Loading "tlines.c" into memory
Status: 13 of 16 lines. [block size is 8]:
1 int main(int argc, char** argv)
2 {
3 char msg[80] = {0};
4 if (argc < 2) usage();
5 Block* test = load_file(argv[1]);
6 sprintf(msg, "==> Loading \"%s\" into memory", argv[1]);
7 status_blk(test, msg);
8 qsort(test->line, test->size, sizeof(void*), cmp_line);
9 sprintf(msg, "==> \"%s\" after sort", argv[1]);
10 status_blk(test, msg);
11 test = delete_blk(test);
12 return 0;
13 };
==> "tlines.c" after sort
Status: 13 of 16 lines. [block size is 8]:
1 Block* test = load_file(argv[1]);
2 char msg[80] = {0};
3 if (argc < 2) usage();
4 qsort(test->line, test->size, sizeof(void*), cmp_line);
5 return 0;
6 sprintf(msg, "==> Loading \"%s\" into memory", argv[1]);
7 sprintf(msg, "==> \"%s\" after sort", argv[1]);
8 status_blk(test, msg);
9 status_blk(test, msg);
10 test = delete_blk(test);
11 int main(int argc, char** argv)
12 {
13 };
About the code
I am not sure if it needs much explanation, it is a single function that does the file loading and it has around 20 lines of code. The other functions has less than 10. The whole file is represented in line that is char** and Block has the needed info about actual size.
Since line[] is an array of pointers we can call
qsort(test->line, test->size, sizeof(void*), cmp_line);
and use
int cmp_line(const void* one, const void* other)
{
return strcmp(
*((const char**)one), *((const char**)other));
}
using strcmp() to compare the strings and have the lines sorted.
create_blk() accepts a block size for use in the calls to realloc() for eficiency.
Delete a Block is a 3-step free() in the reverse order of allocation.
The complete code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
size_t blk_size; // block
size_t limit; // actual allocated size
size_t size; // size in use
char** line; // the lines
} Block;
Block* create_blk(size_t);
Block* delete_blk(Block*);
int status_blk(Block*, const char*);
Block* load_file(const char*);
int cmp_line(const void*, const void*);
void usage();
int main(int argc, char** argv)
{
char msg[80] = {0};
if (argc < 2) usage();
Block* test = load_file(argv[1]);
sprintf(msg, "\n\n==> Loading \"%s\" into memory", argv[1]);
status_blk(test, msg);
qsort(test->line, test->size, sizeof(void*), cmp_line);
sprintf(msg, "\n\n==> \"%s\" after sort", argv[1]);
status_blk(test, msg);
test = delete_blk(test);
return 0;
};
int cmp_line(const void* one, const void* other)
{
return strcmp(
*((const char**)one), *((const char**)other));
}
Block* create_blk(size_t size)
{
Block* nb = (Block*)malloc(sizeof(Block));
if (nb == NULL) return NULL;
nb->blk_size = size;
nb->limit = size;
nb->size = 0;
nb->line = (char**)malloc(sizeof(char*) * size);
return nb;
}
Block* delete_blk(Block* blk)
{
if (blk == NULL) return NULL;
for (size_t i = 0; i < blk->size; i += 1)
free(blk->line[i]); // free lines
free(blk->line); // free block
free(blk); // free struct
return NULL;
}
int status_blk(Block* bl,const char* msg)
{
if (msg != NULL) printf("%s\n", msg);
if (bl == NULL)
{
printf("Status: not allocated\n");
return -1;
}
printf(
"Status: %zd of %zd lines. [block size is %zd]:\n",
bl->size, bl->limit, bl->blk_size);
for (int i = 0; i < bl->size; i += 1)
printf("%4d\t%s", 1 + i, bl->line[i]);
return 0;
}
Block* load_file(const char* f_name)
{
if (f_name == NULL) return NULL;
fprintf(stderr, "loading \"%s\" into memory\n", f_name);
FILE* F = fopen(f_name, "r");
if (F == NULL) return NULL;
// file is open
Block* nb = create_blk(8); // block size is 8
char line[200];
char* p = &line[0];
p = fgets(p, sizeof(line), F);
while (p != NULL)
{
// is block full?
if (nb->size >= nb->limit)
{
const size_t new_sz = nb->limit + nb->blk_size;
char* new_block =
realloc(nb->line, (new_sz * sizeof(char*)));
if (new_block == NULL)
{
fprintf(
stderr,
"\tCould not extend block to %zd "
"lines\n",
new_sz);
break;
}
printf(
"Block extended for a total of %zd "
"pointers\n",
new_sz);
nb->limit = new_sz;
nb->line = (char**)new_block;
}
// now copy the line
nb->line[nb->size] = (char*)malloc(1 + strlen(p));
strcpy(nb->line[nb->size], p);
nb->size += 1;
// read next line
p = fgets(p, sizeof(line), F);
}; // while()
fclose(F);
return nb;
}
void usage()
{
fprintf(stderr,"Use: program file_to_load\n");
exit(EXIT_FAILURE);
}
Try something like this:
#include <stdio.h>
#include <stdlib.h> // for malloc(), free(), exit()
#include <string.h> // for strcpy()
#define MAXLINES 4
#define MAXLENGTH 1000
char *lines[MAXLINES];
void readlines() {
for( int i = 0; i < MAXLINES; i++) {
char c, line[MAXLENGTH + 1]; // ALWAYS one extra to allow for '\0'
int j = 0;
// RE-USE(!) local array for input characters until NL or length
// NB: Casting return value to character (suppress warning)
while( (c = (char)getchar()) != '\0' && c != '\n' && j < MAXLENGTH )
line[ j++ ] = c;
line[j] = '\0'; // terminate array (transforming it to 'string')
// Attempt to get a buffer to preserve this line
// (Old) compiler insists on casting return from malloc()
if( ( lines[i] = (char*)malloc( (j + 1) * sizeof lines[0][0] ) ) == NULL ) {
fprintf( stderr, "malloc failure\n" );
exit( -1 );
}
strcpy( lines[i], line ); // preserve this line
}
}
int my_main() {
readlines(); // only returns after successfully reading 4 lines of input
for( int i = 0; i < MAXLINES; i++)
printf( "Line %d: '%s'\n", i, lines[i] ); // enhanced
/* Maybe do stuff here */
for( int j = 0; j < MAXLINES; j++) // free up allocated memory.
free( lines[j] );
return 0;
}
If you would prefer to 'factor out` some code (and have a facility that you've written is absent, here's a version:
char *my_strdup( char *str ) {
int len = strlen( str ) + 1; // ALWAYS +1
// Attempt to get a buffer to preserve this line
// (Old) compiler insists on casting return from malloc()
char *pRet = (char*)malloc( len * sizeof *pRet );
if( pRet == NULL ) {
fprintf( stderr, "malloc failure\n" );
exit( -1 );
}
return strcpy( pRet, str );
}
The the terminating and preserve is condensed to:
line[j] = '\0'; // terminate array (transforming it to 'string')
lines[i] = my_strdup( line ); // preserve this line
I'm trying to read from a file and put pointers of each line to a double pointer "stack" but always fail to realloc it. Maybe I should use a triple pointer????
int i = 1;
char * line = malloc(BUFSIZ);
char ** stack;
stack = (char ** ) malloc(sizeof(char * ));
while (fgets(line, BUFSIZ, file) != NULL) {
stack = & line;
printf("//%s", line);
printf("??%s", * stack);
i++;
stack = (char ** ) realloc(stack, sizeof(char * ) * i);
}
For starters the code has a memory leak. At first a memory was allocated
stack = (char ** ) malloc(sizeof(char * ));
and then the pointer stack was reassigned with the address of the pointer line.
while (fgets(line, BUFSIZ, file) != NULL) {
stack = & line;
//…
This statement
stack = (char ** ) realloc(stack, sizeof(char * ) * i);
results in undefined behavior because the pointer stack after the statement
stack = & line;
does not point to a dynamically allocated memory. It points to a local variable line.
It seems what you are trying to do is the following shown in the demonstrative program below. Only instead of a file there is used the standard input stream stdin.
#include <stdio.h>
#include <stdlib.h>
#include<string.h>
int main(void)
{
char *line = malloc( BUFSIZ );
char **stack = NULL;
size_t n = 0;
while ( fgets( line,BUFSIZ, stdin ) != NULL )
{
line[strcspn( line, "\n" )] = '\0';
char **tmp = realloc( stack, ( n + 1 )* sizeof( char * ) );
if ( tmp != NULL )
{
stack = tmp;
++n;
stack[n-1] = malloc( BUFSIZ );
if ( stack[n-1] != NULL ) strcpy( stack[n-1], line );
}
}
for ( size_t i = 0; i < n; i++ )
{
if ( stack[i] != NULL ) puts( stack[i] );
}
for ( size_t i = 0; i < n; i++ )
{
free( stack[i] );
}
free( stack );
free( line );
return 0;
}
If to enter two strings
Hello
World
then the output will be
Hello
World
You get this error message because you set stack to the address of line. As a consequence, stack is no more an allocated block.
There are a few errors in your code.
you should store the line in the stack at index i
you should allocate a new block for each line
you should reallocate for i+1 lines to create room for the next line if any
Here is the corrected code:
int i = 0; // number of line pointers in the stack
char *line = malloc(BUFSIZ);
char **stack = malloc(sizeof(char*));
while( fgets(line, BUFSIZ, file) != NULL) {
stack[i] = line;
printf("//%s", line);
printf("??%s", stack[i]);
i++;
line = malloc(BUFSIZ); // allocate a new block for the next line
stack = realloc(stack, sizeof(char*)*(i+1)); // make room for the next line
}
char *buffer; /* holds the file contents. */
char **transfer;
unsigned long countNewLine = 0;
size_t rowTrack;
size_t columnTrack;
// assume countNewLine is 12
buffer_size = BUFSIZ;
buffer = malloc(buffer_size);
transfer = (char**)malloc(sizeof(char*)*sizeof(countNewLine));
columnTrack = 0;
while ( columnTrack < countNewLine ) {
for ( rowTrack = 0; buffer[rowTrack] != '\n' || buffer[rowTrack] != '\0'; rowTrack++ )
transfer[columnTrack][rowTrack] = buffer[rowTrack];
columnTrack++;
}
I'm trying to convert 1D string array to 2D. I don't have any idea about my mistake. Thank you for solution.
Debugger result:
buffer char * "first\nsecond\nthird\nfourth\nfifth\nsixth\nseventh\n
eighth\nninth\ntenth\neleventh\ntwelfth\nthirteenth" 0x0000000100801200
*buffer char 'f' 'f'
countNewLine unsigned long 12 12
transfer char ** 0x100105520 0x0000000100105520
*transfer char * NULL 0x0000000000000000
rowTrack size_t 0 0
columnTrack size_t 0 0
There are several errors in your code. In this line
transfer = (char**)malloc(sizeof(char*)*sizeof(countNewLine));
the second sizeof() is incorrect, the line should be
transfer = malloc(sizeof(char*) * countNewLine);
Next, you did not allocate memory for each row, which could be something like this
for ( rowTrack = 0; rowTrack < countNewLine; rowTrack++)
transfer[rowTrack] = malloc(BUFSIZ); // or whatever the line length is
The for loop will never terminate by using ||
for ( rowTrack = 0; buffer[rowTrack] != '\n' || buffer[rowTrack] != '\0'; rowTrack++ )
should be
for ( rowTrack = 0; buffer[rowTrack] != '\n' && buffer[rowTrack] != '\0'; rowTrack++ )
And lastly, I think you have your row and column indexing reversed in this statement:
transfer[columnTrack][rowTrack] = buffer[rowTrack];
There is a much cleaner way to split your string, like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define BUFSIZ 512
int main(void) {
char *buffer;
char *sptr;
char **transfer = NULL;
int rows = 0, row;
/* ... load the file contents */
buffer = malloc(BUFSIZ);
strcpy (buffer, "first\nsecond\nthird\nfourth\nfifth\nsixth\nseventh\neighth\nninth\ntenth\neleventh\ntwelfth\nthirteenth");
/* split the input */
sptr = strtok(buffer, "\r\n");
while (sptr) {
transfer = realloc(transfer, (rows+1) * sizeof(char*)); // expand string array
transfer[rows] = malloc(1+strlen(sptr)); // memory for string
strcpy (transfer[rows], sptr); // copy the token
rows++;
sptr = strtok(NULL, "\r\n");
}
/* show array */
printf ("Showing %d rows\n", rows);
for (row=0; row<rows; row++) {
printf ("%s\n", transfer[row]);
free (transfer[row]); // release mem
}
free (transfer); // release mem
free (buffer); // release mem
return 0;
}
Program output:
Showing 13 rows
first
second
third
fourth
fifth
sixth
seventh
eighth
ninth
tenth
eleventh
twelfth
thirteenth
I'm trying to write a program in C that takes an unknown number of strings (each of unknown size) from the user as input and stores them then prints them when the user has finished entering strings.
First I use a pointer that points to character pointers (char** strings) and allocate 1 char* sized block of memory to it with malloc. I then allocate 1 char sized block to the pointer that strings is pointing to ( (strings) ) with malloc also. From there I take a string input from the user using a user-defined function called get_String() and place it into the char pointer that char* string is pointing to. I then use a for loop to continue allocating an extra char* of memory to char** strings and 1 char of memory to the new pointer.
However, I keep experiencing an error on the 2nd iteration of the for loop, on the line strings = (char**) realloc (strings, index+1); and I receive the error message: Heap block at 00558068 modified at 00558096 past requested size of 26. It seems like I am writing past the allocated memory to char** strings, but I don't know where or how I am doing this.
Here is my entire code:
#include "stdio.h"
#include "string.h"
#include "stdlib.h"
void get_strings( char* strings); // function to take in a string of an unknown size
int main( void )
{
char** strings;
int index, count;
(strings) = (char**) malloc( sizeof(char*)); // this is the pointer that holds the addresses of all the strings
*strings = (char*) malloc( sizeof(char)); // the address of the first string
printf( "Enter a list of stringss. Quit by pressing enter without entering anything\n" );
get_strings( *strings );
for( index = 1; strlen(*(strings+index-1))!=1; index++) // stores strings from the user until they enter a blank line which is detected when string length is 1 for the \n
{
strings = (char**) realloc (strings, index+1); // adds an extra character pointer for another string
*(strings + index) = (char*) malloc(sizeof(char)); // allocates memory to the new character pointer
get_strings( *(strings + index) ); // stores the string from the user
}
printf( "You entered:\n" );
for( count = 0; strlen(*(strings + count)) != 1; count++ ) //prints every string entered by the user except for the terminating blank line
{
printf( "%s", *(strings + count ) );
free( *(strings + count ));
}
free( strings );
system( "PAUSE" );
return 0;
}
void get_strings( char* strings )
{
fgets( strings, 1, stdin );
while( strings[ strlen( strings ) - 1 ] != '\n' )
{
strings = (char*) realloc( strings, strlen(strings)+2 );
fgets( strings + strlen(strings), 2, stdin );
}
}
As stated before, heap block occurs on the second iteration of the for loop while executing the line: strings = (char**) realloc (strings, index+1);
for( index = 1; strlen(*(strings+index-1))!=1; index++) // stores strings from the user until they enter a blank line which is detected when string length is 1 for the \n
{
strings = (char**) realloc (strings, index+1); // error occurs here
*(strings + index) = (char*) malloc(sizeof(char)); // allocates memory to the new character pointer
I would very much appreciate it if someone could explain to me the cause of this error and a direction to fix it. Thank you.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
char *get_strings(void);
int main( void ){
char **strings = NULL;
char *string;
int index, count;
printf( "Enter a list of stringss. Quit by pressing enter without entering anything\n" );
for(index = 0; string = get_strings(); ++index){
strings = (char**) realloc (strings, (index+1)*sizeof(*strings));
strings[index] = string;
}
printf( "You entered:\n" );
for( count = 0; count < index; ++count ){
printf("%s\n", strings[count]);
free( strings[count] );
}
free( strings );
system( "PAUSE" );
return 0;
}
char *get_strings(void){
char *string = NULL;//or calloc(1,sizeof(char)) for return "" (test by caller: *string == '\0')
int ch;
size_t len = 0;
while(EOF != (ch=fgetc(stdin)) && ch != '\n' ) {
string = (char*)realloc( string, len + 2);//To realloc to each character is inefficient
string[len++] = ch;
}
if(string)
string[len] = '\0';
return string;//The value is NULL when there is no input substantial.
}