I am anxious to know why realloc() doesn't work in my loop.I made a grep function which i tested on a large text file and suddenly the program crashed telling me "corruption of the heap" so I decided to break it up and try it on a smaller scale,but the problem persist.Can someone explain what is wrong?
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
void grep(const char *Pattern,FILE *file);
int main(void)
{
FILE *file;
if(fopen_s(&file,"file.txt","r"))
return 1;
grep("word",file);
fclose(file);
return 0;
}
void grep(const char *Pattern,FILE *file)
{
size_t size = 5*sizeof(char);
char *_Buf = (char*)malloc(size);
int n = 0, c;
while(c=getc(file))
{
_Buf[n++] = c;
if(c == '\n' || c == EOF)
{
_Buf[n] = '\0';
if(strstr(_Buf,Pattern))
printf("%s",_Buf);
if(c == EOF)
break;
n = 0;
}
if(n == size)
{
size += 5;
realloc(_Buf,size);
}
}
free(_Buf);
}
Calling realloc() on a pointer does not adjust the old pointer. It deallocates the old pointer and returns a new pointer containing the new allocation. You need to make use of the returned pointer afterwards.
From the C11 standard, chapter ยง7.22.3.5, The realloc function
void *realloc(void *ptr, size_t size);
The realloc function deallocates the old object pointed to by ptr and returns a
pointer to a new object that has the size specified by size. [...]
So, you need to collect the returned pointer, check against NULL and assign it back to the previous pointer, as you may.
That said, please see this discussion on why not to cast the return value of malloc() and family in C..
You are not assinging the returned pointer of realloc() to a variable/pointer:
realloc(_Buf,size);
Use:
char * _New_Buf = realloc(_Buf,size);
if(_New_Buf != NULL)
_Buf = _NewBuf;
else
; // add some error handling here
Otherwise, free() will also be free-ing the wrong memory pointed to by a possible invalid _Buf.
Related
I been trying to figure out why Valgrind reports unreachable memory and the buffer gets corrupted when i don't return the pointer (case 2) .
As i understand it i give read_input a pointer and it uses it. If realloc is caused i get a new pointer and replace the old one, so the pointer of input_buffer in main,and wherever there is that pointer it should have that new pointer, but it doesn't.
Is it maybe that i am passing literally the address ?
So the input_buffer in main has the old address as it was never changed? (My C is a bit rusty)
Is there a way to keep the input_buffer "updated" without returning the value like case 1 ? thus being able to write code like case 2 ?
(without having the buffer global/static)
#include "dev_utils.h"
#include "promt.h"
#include "sh_input.h"
int main(int argc, char *argv[]) {
// char *input_buff = (char *)malloc(CMD_BUFF * sizeof(char));
char *input_buff = (char *)malloc(1024 * sizeof(char));
if (!input_buff) {
fprintf(stderr, "Memory allocation failed at %s:%d! Exiting.\n",
"cs345sh.c", 8);
exit(1);
};
while (1) {
put_promt();
// 1. input_buff = read_input(input_buff);
// 2. read_input(input_buff);
parse_input(input_buff);
}
free(input_buff);
return 0;
}
#include "sh_input.h"
#include "dev_utils.h"
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *read_input(char *input_buff) {
unsigned int input_buffer_size = CMD_BUFF;
unsigned int input_index = 0;
char input;
while(1) {
input = getchar();
if (input_index >= input_buffer_size) {
input_buffer_size += CMD_BUFF;
char *new_buff;
new_buff = realloc(input_buff, input_buffer_size);
if (!new_buff) {
fprintf(stdout, "Memory allocation failed at %s:%d! Exiting.\n",
"sh_input.c", 17);
exit(1);
};
input_buff = new_buff;
}
if (input == EOF || input == '\n') {
input_buff[input_index] = '\0';
return input_buff;
} else {
input_buff[input_index] = input;
}
++input_index;
}
// 1. return input_buff;
}
void parse_input(char *input) {
if (strcmp(input, "exit") == 0) {
free(input);
exit(EXIT_SUCCESS);
}
printf("%s\n", input);
}
Function arguments are passed by value in C. The input_buff parameter is a different object than the variable that you pass into the function when you call it (they have different memory addresses, even though the pointer value stored at these two addresses is initially the same). Thus, updating the parameter variable has no effect on the variable in the caller function.
So the caller function must take care of updating its own variable, which you can achieve by returning the new pointer, or as #UnholySheep has already pointed out in the comments to your question, you could instead pass a pointer to the variable to overwrite it from within the read_input function.
can anyone explain the differences between the two allocs and why bad and good? what happen in each case of bad and good?
bad alloc
void get_memory(char *arr, int length){
if((arr=(char*)malloc(length * sizeof(char))) == NULL)
{
puts("Not enough memory. Sorry.\n");
exit(-1);
}
}
void main(void){
char *str = NULL;
get_memory(str, 128);
strcpy(str,"Program illegally runs over memory !\n");
puts(str);
free(str);
}
good alloc
void get_memory(char **arr, int length){
if( (*arr = (char*)malloc(length * sizeof(char))) ==
NULL)
{
puts("Not enough memory. Sorry.\n");
exit(-1);
}
}
void main(void){
char *str = NULL;
get_memory(&str, 128);
strcpy(str, "This program works fine !\n");
puts(str);
free(str);
}
The bad is that in the first case the pointer arr is passed by value, it's value is modified in the function, and when returning the value is "forgotten". In the second code the reference to the pointer is passed, so the assigned value is retained when out of the function.
In the "bad" example you are actually throwing away malloc's result, since "str" parameter is passe dby value and will mantain its NULL value after the call. In the second case the function receives a POINTER TO "str", so it's able to manipulate "str" and leave the correct value in it.
As others have already answered your question, I add an alternative:
void get_memory(char **arr, size_t length){
if((*arr = malloc(length)) == NULL && 0 != length)
{
puts("Not enough memory. Sorry.\n");
exit(-1);
}
}
Reasoning: length shall not be negative. And when it is 0, the result of malloc can be NULL.
malloc returns void*, which is automatically casted to an appropriate pointer type in C.
As per later C standard, sizeof(char) is 1.
This question already has answers here:
How do I modify a pointer that has been passed into a function in C?
(7 answers)
Closed 8 years ago.
I want to make a function in C that would dynamically allocate memory for a pointer in parameter of the function.
#include <stdio.h>
#include <stdlib.h>
int allocate(char * arr, int size){
int code = -1;
arr = malloc(size);
if(arr != NULL) code = size;
return code;
}
void main(){
char * array;
if(allocate(array,4) != -1){
printf("allocated!\n");
if(array == NULL) printf("Oops it actually didn't allocate!\n");
}
}
When I execute the program; it will only display "allocated!" and "Oops it actually didn't allocate!". That means the memory allocation did happen (because the return code of the function is not -1. But then when I check if array is equal to NULL; it actually is!
This is a programming problem that I've had and sadly in some cases I can't use a workaround like this char * allocate(char * arr, int size); and assigning the return value to char * array.
You lack a level of indirection, you need char**.
Excuse the bad formatting, I write from my phone.
Char* array, array is bound to a memory slot (that will contain a value that points to another memory slot that would be interpreted as a char).
So you copy that value to the function and modify that value locally in allocate, but the modification never reaches the outside scope.
#include <stdio.h>
#include <stdlib.h>
int allocate(char ** arr, int size){
int code = -1;
*arr = malloc(size);
if(*arr != NULL) code = size;
return code;
}
void main(){
char * array;
if(allocate(&array,4) != -1){
printf("allocated!\n");
if(array == NULL) printf("Oops it actually didn't allocate!\n");
}
}
Not done C in something like 10 years but it should be OK.
You can allocate memory inside your function and return the address as shown below
There are also changes like instead of void main it should be int main()
#include <stdio.h>
#include <stdlib.h>
char *allocate( int size){
char *arr;
arr = malloc(size);
return arr;
}
int main(){
char * array;
if((array = allocate(4)) != NULL){
printf("allocated!\n");
}
return 0;
}
Arguments to functions in C are passed by value. This means following function has no sense:
void f(int x) {
x = 1;
}
int y = 0;
f(y);
// y is still 0
When f is invoked, y is copied to x. Any change to x changes that copy and won't affect y. To work around this, you need to either use return value or pass a pointer to y:
void f(int* x) {
*x = 1;
}
int y = 0;
f(&y);
// y is now 1
Here x is still a copy (of a pointer) but it points to y. Changes to x wont be visible outside that function. But changing *x modifies y.
The same rules apply to pointer arguments. You just need one more * for arguments you want to modify:
int allocate(char** arr, int size) {
*arr = malloc(size);
}
char *ptr;
allocate(&ptr);
Also note that checking array for NULL isn't sufficient here, because a locally defined variable could contain garbage value (thus, not being NULL). You have to assign NULL to it before the allocation:
char *array = NULL;
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;
}
Here I'm taking a sentence a checking if it is a palindrome or not.I'm doing this in the process of learning stacks.
Is there a way i can use pointers instead of char array 'sent' so that the number of input characters need not be constrained to 20 in the following code?
The code is working fine, but should there be any improvements in terms of performance or anything else?
is there anything important about pointers i should remember while using stacks, like initializing it to NULL?
Thanks
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <stdbool.h>
typedef struct node
{
char data;
struct node *link;
}StackNode;
void insertData(StackNode **);
void push(StackNode **, char);
void checkData(StackNode **);
bool pop(StackNode **,char *);
char sent[20] = "";
void main()
{
StackNode *stackTop;
stackTop = NULL;
insertData(&stackTop);
checkData(&stackTop);
printf("\n");
return;
}
void insertData(StackNode **stackTop)
{
char c;
int len;
printf("Enter the Sentence\n");
while( ( ( c = getchar() ) != '\n'))
{
if( ( ( c>='a' &&c<='z') || (c>='A' && c<='Z')))
{
if((c>='A' && c<='Z'))
{
int rem;
rem = c-'A';
c='a' + rem;
}
push(stackTop,c);
len = strlen(sent);
sent[len++]=c;
sent[len]='\0';
}
}
printf("Letters are %s\n\n",sent);
}
void push(StackNode **stackTop,char c)
{
StackNode *pNew;
pNew = (StackNode*) malloc(sizeof(StackNode));
if(!pNew)
{
printf("Error 100:Out of memory\n");
exit(100);
}
pNew->data = c;
pNew->link = *stackTop;
*stackTop = pNew;
}
void checkData(StackNode **stackTop)
{
char c;
int i=0;
while(pop(stackTop,&c))
{
if( c !=sent[i++])
{
printf("Not palindrome");
return;
}
}
printf("Palindrome");
}
bool pop(StackNode **stackTop,char *c)
{
StackNode *pNew;
pNew = *stackTop;
if(pNew == NULL)
return false;
*c = pNew->data;
*stackTop = pNew->link;
printf("char poped %c\n",*c);
free(pNew);
return true;
}
As far as I know, there is no way to have an "infinite array" or an array with no limitations. However, if you use malloc you can produce a section of memory large enough that you won't need to worry about the limitations as much. I see that later on in the code you have used malloc, so I assume you know how it works. However, I would use something like this;
char * sent = malloc(sizeof(char) * 100);
if(sent == NULL){
printf("OUT OF MEMORY!");
return 1;
}
Where 100 is the buffer size you wish to have. I have used a size up to 10000 and had no problems at runtime, so that may be what you need.
In C, arrays are really pointers to statically allocated memory. It is pretty straightforward to create a pointer to an array, or any element in an array. For example, suppose we have you array char sent[20]. If we wanted to create a pointer that pointed to the exact same memory as sent, we can declare char *sentP = sent. We can now replace any use of sent with sentP. We can even create a pointer to the middle of sent: char *sentMidP = sent + 9. Now, sentMidP[0] is the same as sent[9] and sentMidP[-9] is the same as sent[0].
However, unlike sent, we can change where sentP and sentMidP point (think of sent as a constant pointer char * const, which you can't change). Thus, if you had another array char sent2[100]'. You can set the value ofsentPtosent2. What's cool about this is that you can do it *at runtime*, which effectively means that you can change the size ofsentP` depending on the size of your input.
However, there is no need to limit yourself to statically allocated input. C provides the malloc function (see here) to allocate memory at runtime. Thus, if you don't know the size of your sentence at compile time, but you will know it at runtime (say in a variable called sentenceLength), you can allocate `sentP' like the following.
char *sentP = malloc(sizeof(char) * (sentenceLength + 1)); // Plus one for the NUL termination byte in C strings
if (sentP == NULL) {
fprintf(stderr, "No more memory :(");
exit(EXIT_FAILURE);
}
Note how we now have to handle out-of-memory errors. In general, dynamic allocation introduces more overhead, because there is a possibility that we run out of memory, a requirement that we ensure we only access what was allocated, and a need to release the memory with free once we're done.
When you're done with the sentP pointer, be sure to free it with:
free(sentP);
That's it! You can use the sentP pointer we made in your code, and everything should work great. Good luck!