change static array into dynamic with malloc and realloc? - c

Hallo the following code read the stdin and put it into stdout, but in reverse. I used for this a static array, because I know how much characters are in the input.txt. My question is how can I change my array in a dynamic array(pointer) with using malloc and realloc? All my tries failed.
#include <stdio.h>
#include <stdlib.h>
int main()
{
char ch;
int i,counter;
char array[50];
counter = 0;
i = 0;
while((ch=getchar()) != EOF)
{
array[i] = ch;
i++;
counter++;
}
for(i = (counter + 1); i >= 0; i--)
{
printf("%c",array[i]);
}
printf("\n");
return 0;
}

Even if you know that the input you use never has more than 50 characters, you should enforce that limit. When the program is run with arbitrary input, you will eventually access data beyond the array's end.
Anyway, here's your program core, extracted into a function:
void rev1()
{
char array[50]; // Allocate 50 bytes on the stack
int i = 0;
char ch;
while (i < 50 && (ch = getchar()) != EOF) array[i++] = ch;
while (i--) putchar(array[i]);
printf("\n");
// Do nothing - array goes out of scope
}
If you just want to use the same fixed-length buffer on the heap, the code is very similar. You should define a pointer to char instead of the array and then call malloc in order to obtain the required memory. After you are done using that memory, you must release it with free.
Here's a second version that uses memory on the heap:
void rev2()
{
char *array;
int i = 0;
char ch;
array = malloc(50 * sizeof(*array)); // Allocate on the heap
if (array == NULL) exit(1); // Check for failure
while (i < 50 && (ch = getchar()) != EOF) array[i++] = ch;
while (i--) putchar(array[i]);
printf("\n");
free(array); // Explicitly release data after use
}
Things to note:
sizeof(*array) is sizeof(char) in this case, which is always 1 and therefore often is omitted. But p = malloc(count * sizeof(*p)) is a very useful allocation pattern for allocating an array of count elements that will still work if you change the type of the things pointed to.
Memory allocation on the heap may fail; malloc will then return NULL. You must cater for such cases. The simple strategy is to just print an error message and abort the program. Depending on what you need the memory for, you might chose other failure strategies.
Note how the core of the function, the loop is exactly the same as in the first version.
You also must enforce the limit of 50 chars. The array is on the heap, but it doesn't grow.
Free the memory after use. If you don't you "leak memory", i.e. you keep chunks of memory blocked. Here, array - the pointer variable that holds the array, not the array itself - is a local variable that goes out of scope. Forgetting to free the memory here will mean that you lose its address and can't access it again.
The variable array points to the start of the memory. This variable must be passed to free. Don't change this variable, e.g. by incrementing it, otherwise you will lose your "key" to the memory.
A slightly more involved version re-allocates memory as needed. You can use realloc instead of malloc if your array grows. The already allocated data stays in place, even if the memory is not the same:
void rev3()
{
char *array = NULL; // Initially unallocated NULL array
size_t size = 0; // Allocated size, initially 0
int i = 0;
char ch;
while ((ch = getchar()) != EOF) {
if (i >= size) { // Check current bounds
size += 50; // Increase memory
array = realloc(array, // Reallocate
size * sizeof(*array));
if (array == NULL) exit(1);
}
array[i++] = ch;
}
while (i--) putchar(array[i]);
printf("\n");
free(array); // Explicitly release data after use
}
Notes:
realloc(NULL, size) behaves like malloc(size). Therefore you can implement a reallocation scheme easily by starting with a NULL pointer.
Although the kernel keeps track of the allocated size internally, you have no means to know it, so you must keep track of this information yourself, in this case with size.
Again, you must ensure the the allocation was successful. I've used quick-and-dirty (and silent) program termination above, but you can chose other strategies.
In this case, the core loop is somewhat more involved. Before appending to the memory, you must check whether you should increase it. After you have populated your memory, access (within the allocated bounds) is as usual.

The obvious solution:
#include <stdlib.h>
#include <stdio.h>
void readandprint(void)
{
int c = getchar();
if (c == EOF)
return;
readandprint();
printf("%c", c);
return;
}
int main()
{
readandprint();
printf("\n");
return 0;
}

#include <stdio.h>
#include <stdlib.h>
int main(void){
int ch;//It must be int for comparison with the EOF.
int i, counter;
char *array = malloc(50);
int size = 50;
counter = 0;
while((ch=getchar()) != EOF){
array[counter++] = ch;
if(counter == size){
char *temp = realloc(array, size += 50);
if(temp==NULL){
free(array);
fprintf(stderr, "realloc error!\n");
return -1;
}
array = temp;
}
}
while(counter){
printf("%c", array[--counter]);
}
free(array);
return 0;
}

Related

Why does free() cause an error in my code when it's there, but everything runs well when it is not there?

My program takes an arbitrary number of words at runtime and stores them in a dynamically-sized array of words.
Currently, my program runs well, except when I use free() to free up the memory of the temporary double pointer temp. I am not quite sure why it does this, as I thought it would cause errors if I didn't use it.
int wordSize = 10, arrSize = 1, i = 0;
char **stringArr, **temp;
char *input;
stringArr = malloc(arrSize * sizeof(char *));
puts("Accepting input...");
for (;;) {
if (i >= arrSize) {
arrSize += 1;
temp = realloc(stringArr, arrSize * sizeof(char *));
if (temp != NULL) {
stringArr = temp;
free(temp); // This is the line that is giving me issues; removing it works
} else {
puts("Could not allocate more memory");
return 0;
}
}
stringArr[i] = malloc(sizeof(input));
input = malloc(wordSize * sizeof(char));
scanf("%10s", input);
if (strcmp(input, "END")) {
strcpy(stringArr[i], input);
i++;
} else
break;
}
free(stringArr);
At the bottom of my program I use free() without any issues. How come it works OK here but not earlier on in the program.
I feel I am missing something about how free() works.
Note: this is my first program implementing malloc() and realloc(), so I am only just getting used to how they work. If you know of a better way to accomplish what I am doing that, please feel free to describe.
The free(temp); line is causing an error (later on) because, in the preceding line, stringArr = temp;, you are assigning the address that is stored in the temp pointer to that in the stringArr pointer. Thus, when you free the memory pointed to by temp you also free the memory pointed to by stringArr, because it is the same memory block. Copying a pointer's value from one variable to another does not make a (separate) copy of the memory.
Omitting the free(temp); line is correct, because that memory is freed later on, in the free(stringArr); call.
You must not free the reallocated array when reallocation was successful. If you do that, the code will modify this freed block, which has undefined behavior and you will have further undefined behavior when you later try and reallocate or free this block.
Note also the following:
pre-allocating stringArr with a size of 1 is not necessary. Just initialize stringArr to 0 and arrSize to 0. realloc() can take a null pointer and will behave like malloc().
stringArr[i] = malloc(sizeof(input)); is incorrect: it will allocate a char array with a size of 4 or 8 depending on the size of a pointer on the target architecture, not 11 bytes as it should.
if the wordSize is the maximum length of a word, you should allocate one more byte for the null terminator. The 10 in %10s must match the value of wordSize, which is cumbersome because there is no easy way to pass this to scanf() as a variable.
you do not check the return value of scanf(), causing undefined behavior in case of premature end of file.
you have memory leaks: input is allocated for each iteration but never freed, freeing stringArr without freeing the strings pointed to by its elements makes them inaccessible.
It would be more efficient to use a local array to try and read the words with scanf() and only allocate the string and reallocate the array if successful.
Here is a modified version:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
int arrSize = 0;
char **stringArr = NULL;
char input[11];
puts("Accepting input...");
while (scanf("%10s", input) == 1 && strcmp(input, "END") != 0) {
char **temp = realloc(stringArr, (arrSize + 1) * sizeof(*stringArr));
if (temp != NULL) {
stringArr = temp;
} else {
puts("Could not allocate more memory");
break;
}
stringArr[arrSize] = strdup(input);
if (stringArr[arrSize] == NULL) {
puts("Could not allocate more memory");
break;
}
arrSize++;
}
puts("Array contents:");
for (int i = 0; i < arrSize; i++) {
printf("%i: %s\n", i, stringArr[i]);
}
for (int i = 0; i < arrSize; i++) {
free(stringArr[i]);
}
free(stringArr);
return 0;
}

memory corruption when manipulating a long string

I am writing a program to print out any line input that is longer than 3.
It works for some fairly long input lines, but for the string that is too long, I got a error message of memory corruption
*** Error in `./print-80': malloc(): memory corruption (fast): 0x00000000022ff030 ***
I don't know where the error is from. Can anyone explain me why there is the error and how to fix it?
Below is the program
#include <stdio.h>
#include <stdlib.h>
#define LIMIT 3
#define LEAST_LENGTH 3
//function prototype
void copy(char* from, char* to);
int getline(char* s, int capacity);
int increase_capacity(char* s, int capacity);
int main(void)
{
int length, i;
char* line = calloc(LIMIT, sizeof(char));
while ((length = getline(line, LIMIT)) > 0)
{
if (length > LEAST_LENGTH)
printf("Output: %s\n", line);
//reset the line
for (i = 0; i < length; i++)
*(line + i) = 0;
}
free(line);
return 0;
}
int getline(char* line, int capacity)
{
int c, length;
length = 0;
while ((c = getchar()) != EOF && c != '\n')
{
if (length > (capacity - 1))
{
capacity = increase_capacity(line, capacity);
printf("Address of line after increasing cap: %p\n", line);
}
line[length++] = c;
}
if (c == '\n')
line[length++] = '\0';
return length;
}
int increase_capacity(char* s, int capacity)
{
int i;
capacity *= 2;
char *new_s = calloc(capacity, sizeof(char));
copy(s, new_s);
s = new_s;
free(new_s);
return capacity;
}
void copy(char* from, char* to)
{
int i = 0;
while ((to[i] = from[i]) != '\0')
++i;
}
Your increase_capacity function can change the address at which the data is stored. But it doesn't return this information to its caller. So getline will write to the old buffer address. Similarly, main has no way to get the new address, so it will access the old address and free a block that may already be freed.
Also, your increase_capacity function allocates memory to hold the data and then frees that memory. That leaves no place to hold the data!
int increase_capacity(char* s, int capacity)
{
int i;
capacity *= 2;
char *new_s = calloc(capacity, sizeof(char)); // allocate a larger block
copy(s, new_s); // copy the data into the larger block
s = new_s; // stash a pointer to the larger block in a local
free(new_s); // free the block?!
return capacity;
}
So we allocate a new block, copy the data into it, and then free it. That makes no sense, we need to keep the larger block since that's the whole point of a function to increase capacity. We also don't return the address of the new block, so even if we didn't free it, no other code could access it and we'd just wind up leaking it. Double oops.
I suggest you create a struct that holds both the pointer to the block and its size. Pass a pointer to that struct to functions like increase_capacity so it can modify the pointer and the size in the structure and callers can see the changes.

Segmentation fault in C. What is the reason?

I am getting segmentation fault in C and I have no idea what is the reason. As far as I know segmentation fault occurs when system run our of memory. I checked my loops and they seem to have clear termination conditions. Thus, I am confused what causes my code to crash. As I checked this fault should occurs in mygetline or readlines functions.
Is there any debugger that I can use to find our why program crashes?
#include <stdio.h>
#include <string.h>
#define MAXLINE 100
#define MAXLINENUM 10
int readlines(char *lines[]);
int mygetline(char line[]); /* getline: read a line into s, returns length */
void writelines(char *lines[], int nlines);
int main()
{
int i = 0;
char *lines[MAXLINE];
i = readlines(lines);
writelines(lines, i);
return 0;
}
int mygetline(char line[]){
int i, c;
for(i = 0; i < MAXLINE-1 && (c = getchar()) != '\n' && c != EOF; i++){
line[i] = c;
}
line[i] = '\0';
return i;
}
int readlines(char *lines[]){
int i, c;
i = 0;
while((c = mygetline(lines++)) > 0 && i < MAXLINENUM){ //line[i]
i++;
}
lines[--i] = '\0';
return i;
}
void writelines(char *lineptr[], int nlines) {
int i;
for (i = 0; i < nlines; i++)
printf("%s\n", lineptr[i]);
}
The reason for the segmentation fault is that you don't allocate any storage for the strings. You declare an array of char* here:
char *lines[MAXLINE];
But nowhere do you ever allocate memory to hold the actual strings.
To continue using an array of char*, allocated that way, you'd need to use malloc to allocate memory for the actual strings.
lines[i] = malloc(...);
Obviously you'll need to:
Decide how much memory to allocate for each string.
Call free to dispose of the memory when you are done with it.
Add some code to check that you don't write beyond the end of any of your buffers.
You created an array char *lines[MAXLINE] which is an array of pointers. However, you've not initialized those pointers, so they're pointing to garbage. You then pass the garbage pointer into mygetline which writes to the garbage pointer, and this is the problem.
Not only do you need to allocate memory for the line to be stores in, but you also need to get mygetline how many characters it can read. If you allocate space for 10 characters, but the user enters 20 you're going to have a similar problem.
The reason that you get a segfault is that your code reads the data into lines without allocating any memory for the characters that you read.
Your main allocates memory for the pointers to strings, but it does not initialize these pointers. You need to add code to set these pointers to valid blocks of memory, for example, by allocating some max number of characters with malloc:
while(i < MAXLINENUM) {
lines[i] = malloc(MAXLINE);
if (!mygetline(lines[i++])) {
break;
}
}
Also note that you confused MAXLINE with MAXLINENUM in the declaration of lines.
The reason for the segmentation fault is the memory allocation.
You can not allocate memory like char *lines[MAXLINE];.
Try the following code
If you are Using 1D array
char *lines;
lines=(char *)malloc(MAXLINE*sizeof(char));
If you are using 2D array go with this code
char **lines;
lines=(char **)malloc(MAXLINENUM*sizeof(char *));
for(i=0;i<MAXLINENUM;i++)
lines[i]=(char *)malloc(MAXLINE*sizeof(char));

is this a nice way to allocate memory for an array of arrays? (C)

Okay, imagine I have a char**, would this be the correct way to allocate memory?
I mean: allocate memory for the char** itself and then for each char*...
char** fraseUsuario = NULL;
int length = 100, i = 0;
fraseUsuario = (char **) malloc(sizeof (char*)); //Not pretty sure
for (i = 0; i < 3; i++) {
fraseUsuario[i] = (char *) malloc(length * sizeof (char));
if (fraseUsuario[i] == NULL) {
printf("error\n");
return -1;
}
gets(fraseUsuario[i]);
}
for (i = 0; i < 3; i++) {
printf("%s\n", fraseUsuario[i]);
free(fraseUsuario[i]);
}
And btw, how exactly does free() work? I mean, when I call it at the end, with the debugger it seems as if it does "nothing", if "Hello" is stored in the array, it will continue to be stored there after the free call... is that the normal behavior?
What do you mean allocate memory for the char ** itself? You allocate memory for a variable on the stack when you define it. The following statement defines (allocates memory) fraserUsuario and initializes it to NULL.
char **fraseUsuario = NULL;
I think what you probably meant is how to dynamically allocate an array of char **, i.e., pointer to a pointer to a character. Then you again dynamically allocate an array for each element of the previous allocated array. Do not use gets. It's deprecated and unsafe to use. Use fgets instead. Also, please don't cast the result of malloc. You don't get any benefit and you can run into error if you forget to include the header stdlib.h which contains its prototype. Here's how you do it.
char **fraseUsuario = NULL;
int max_string_len = 100 + 1; // maximum string length. +1 for null byte
int num_string = 3; // number of strings to read
int i, j;
fraseUsuario = malloc(num_string * sizeof *fraseUsuario);
if(fraseUsuario == NULL) { // check for NULL
// handle the case
printf("not enough memory\n");
return -1;
}
for(i = 0; i < num_string; i++) {
fraseUsuario[i] = malloc(max_string_len * sizeof(char));
if(fraseUsuario[i] == NULL) { // check for NULL
printf("not enough memory\n");
for(j = 0; j < i; j++)
free(fraseUsuario[j]); // free memory before returning
free(fraseUsuario); // free memory before returning
return -1;
}
if(fgets(fraserUsuario[i], max_string_len, stdin) == NULL) {
// reading string failed
*fraserUsuario[i] = '\0'; // empty string
}
}
for(i = 0; i < 3; i++) {
printf("%s\n", fraseUsuario[i]);
free(fraseUsuario[i]); // free memory allocated for strings
}
free(fraseUsuario); // free memory allocated for pointers to strings
fraseUsuario = NULL;
When you call free on a memory address which you got by a call to malloc, the memory block is returned to the free pool on the heap. This memory block can then later be reused by malloc. Once you free memory, you have given up your ownership of it. It no longer belongs to you and attempting to use it is illegal and will result in undefined behaviour and likely segfault.
You only allocate memory for one char* but use three.
To fix this do:
#define STR_MAXIMUM (3)
...
size_t length = 100, i = 0; /* No need to use a signed type.
size_t is meant as index and size type. */
char ** fraseUsuario = malloc(STR_MAXIMUM * sizeof(*fraseUsuario));
for (i = 0; i < STR_MAXIMUM; ++i)
{
fraseUsuario[i] = malloc(length * sizeof(*fraseUsuario));
...
Also add error checking to system calls.
Also^2: Do not use gets() as there is no way for the compiler or the machine to prevent the buffer passed in from overflowing. Use fgets() instead.
fgets(fraseUsuario[i], length, stdin);

getting string with dynamic memory management

I wanna get string like 34,34;34,21;45,12;45,12(length is not certain.)
I wanna dynamic memory allocation with realloc but i can't do it.
How i can get like this characters to string??
it will be string={34,34,34,21,45,12,45,12}
You will have to know the length beforehand, and when you know that your buffer is too small for data that is going to be newly entered, use:
realloc(ptr, newLength);
If you're looking to do this at compile time (which is the only way to perform initializers similar to what you have in your question), you can let the initializer define the size f your array:
char string[] = {34,34,34,21,45,12,45,12, 0}; // added a 0 to the end to
// make it '\0' terminated
// You might not need that
If you want your string to take it's data from a runtime source (a file or other input), you'll need to perform the allocation yourself, and exactly how to do it depends on how you're going to be getting the data.
The following example reads data from stdin into a dynamically allocated character array, growing the array as needed until EOF is reached. It grows the array by 20 bytes each time so you can easily check what's happening in a debugger, but a real life program would do better to grow by something larger like by doubling the size or just growing in increments of 100KB - the details of your expected data should guide you in this decision).
#include <stdlib.h>
#include <stdio.h>
void fatal_error(void);
int main( int argc, char** argv)
{
int buf_size = 0;
int buf_used = 0;
char* buf = NULL;
char* tmp = NULL;
char c;
int i = 0;
while ((c = getchar()) != EOF) {
if (buf_used == buf_size) {
//need more space in the array
buf_size += 20;
tmp = realloc(buf, buf_size); // get a new larger array
if (!tmp) fatal_error();
buf = tmp;
}
buf[buf_used] = c; // pointer can be indexed like an array
++buf_used;
}
puts("\n\n*** Dump of stdin ***\n");
for (i = 0; i < buf_used; ++i) {
putchar(buf[i]);
}
free(buf);
return 0;
}
void fatal_error(void)
{
fputs("fatal error - out of memory\n", stderr);
exit(1);
}
Maybe you are passing the pointer as an argument to a function b() which is in turn calling the realloc
In this case you need to also return the pointer.

Resources