I am trying to create a program which reads integers from a file with 103690 pairs of integers while skipping lines starting with # and saves them inside an array. Eventhough it does it successfully, it suddenly stops after a specific line (line 5115).
The file looks like this:
#I must
#be
#skipped
8050 6737
8050 7238
The code is:
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
typedef struct {
int start;
int end;
} path;
int doublesize(path* array,int n){
path* new_array=malloc(n*2*sizeof(path));
if(new_array==NULL){
printf("Error allocating memory\n");
abort();
}
for(int i=0;i<n;i++){
new_array[i]=array[i];
}
free(array);
array=new_array;
n*=2;
return n;
}
int main()
{
int maxsize=10;
int test;
path* array=malloc(maxsize*sizeof(path));
if(array==NULL) {
printf("Error allocating memory\n");
abort();
}
FILE* fd=fopen("Wiki-Vote2.txt","r");
if(fd==NULL) {
printf("Error opening file\n");
abort();
}
char buff[200];
int counter=0;
char c;
while(fgets(buff,200,fd)) {
c=buff[0];
if(c=='#') {
continue;
}
test=sscanf(buff,"%d%d",&array[counter].start,&array[counter].end);
printf("%d\t%d\n",array[counter].start,array[counter].end);
printf("Read %d numbers\n", test);
counter++;
if(counter==maxsize){
maxsize=doublesize(array,maxsize);
}
}
fclose(fd);
free(array);
return 0;
}
I have tried reducing the number of integers which works but when I used gdb I saw that it returned the signal sigsegv(I use windows).Could the memory be insufficient or is it something else?
Function arguments are passed by value. That includes pointers. So when you do array=new_array; inside doublesize you are assigning to a copy of the pointer array pointer from main. The value of array inside main function stays the same.
You can pass a pointer to the pointer to change it's value.
int doublesize(path **array,int n){
...
// first dereference array, then access element number i
new_array[i] = (*array)[i];
}
// free the array where array points to, ie array in main
free(*array);
// assign new value to array
*array = new_array;
n *= 2;
return n;
}
int main()
{
...
// pass array by pointer to let doublesize modify it
maxsize = doublesize(&array, maxsize);
...
}
I think it could be clearer to change the doublesize function to return the new pointer and to take a pointer to int variable that represents maxsize, like so:
path *doublesize(path *array, int *maxsize){
int n = *maxsize;
...
free(array);
// maxsize here points to the variable maxsize in main
// let's write n * 2 to it
*maxsize = n * 2;
// return the new pointer
return new_array;
}
int main()
{
...
// array is updated with the new value
// maxsize is updated with
array = doublesize(array, &maxsize);
...
}
The problem is in your resizing function:
int doublesize(path* array,int n){
...
array=new_array;
The variable array is local to the function, so changes to it aren't reflected in the calling function. As a result, array in main now points to freed memory after this function returns, and attempting to dereference that pointer invokes undefined behavior.
You should change this function to accept a path **:
int doublesize(path **array,int n){
path *new_array=malloc(n*2*sizeof(path));
if(new_array==NULL){
printf("Error allocating memory\n");
abort();
}
for(int i=0;i<n;i++){
new_array[i]=(*array)[i];
}
free(*array);
*array=new_array;
n*=2;
return n;
}
And pass the address of array in main:
maxsize=doublesize(&array,maxsize);
In doublesize() you reassign array, but here it's only a local variable, so after the function returns, array in main() still holds the original now freed pointer. So you should pass a double pointer (and use realloc()) so that your function could look like that:
int doublesize(path** array,int n){
path* new_array=realloc( *array, n*2*sizeof(path));
if(new_array==NULL){
printf("Error allocating memory\n");
abort();
}
*array=new_array;
return n*2;
}
Call the function by
maxsize=doublesize(&array,maxsize);
Related
hi im trying to make my array increase its size with realloc from function when even number is typed, but the compiler is displying Segmentation Fault whatever number I type.Any ideas how can i fix this?
#include <stdio.h>
#include <stdlib.h>
int MakeArray(int n,int *ptr)
{
ptr = (int*) malloc(n*sizeof(int));
if(ptr==NULL)
{
puts("Allocation failed");
}
return *ptr;
}
int ReAllocArray(int n,int *ptr)
{
ptr = (int*) realloc(ptr,n*sizeof(int));
if(ptr==NULL)
{
puts("Reallocation failed");
}
return *ptr;
}
int main() {
int n;
int *ptr=NULL;
puts("Enter size of n");
scanf("%d",&n);
MakeArray(n,ptr);
puts("Entering even number is increasing the size of the array by 1");
for(int i =0;i<n;++i)
{
scanf("%d",&ptr[i]);
if(ptr[i]%2==0)
{
++n;
ReAllocArray(n,ptr);
}
}
puts("Your array is:");
for(int i =0;i<n;i++)
{
printf("%d",ptr[i]);
}
return 0;
}
You need to pass pointer to pointer to int to modify it or/and return the reference to the allocated memory
int *MakeArray(size_t n, int **ptr)
{
if(ptr)
{
*ptr = malloc(n*sizeof(**ptr));
if(!*ptr)
{
puts("Allocation failed");
}
}
return *ptr;
}
Same when you realloc
int *ReAllocArray(size_t n, int **ptr)
{
int *tmp = NULL;
if(ptr)
{
tmp = realloc(*ptr,n * sizeof(**ptr));
if(!tmp)
{
puts("Reallocation failed");
}
else
{
*ptr = tmp;
}
}
return tmp;
}
When you call it you need to pass pointer to pointer:
MakeArray(n,&ptr);
ReAllocArray(n,&ptr);
It would be worth checking what those functions return to know if allocations succeeded.
Also:
Use the correct type for sizes (size_t nor int)
Do not cast the result of malloc/realloc. If it does not compiler you are using the wrong (C++) compiler to compile the C code.
Use objects not types in sizeofs
When realloc use a temporary variable. Otherwise, you may have a memory leak
BTW you do not need the MakeArray function at all as realloc will work fine when you pass NULL pointer (it will simple not copy any data to the allocated memory)
I am trying to receive a number from the user.
And create an array with that number, but, inside a function.
Here are my few attempts, I get into run time errors.
Help is very much appreciated.
#include <stdio.h>
#include <stdlib.h>
int* Init(int* p, int num);
int main() {
int *p;
int num, i;
puts("Enter num of grades:");
scanf("%d", &num);
Init(&p, num);
//for (i = 0; i < num; i++)
//{
// scanf("%d", &p[i]);
//}
free(p);
}
int* Init(int* p, int num)
{
int *pp;
p = (int *)malloc(num*sizeof(int));
if (!pp)
{
printf("Cannot allocate memory\n");
return;
}
p = pp;
free(pp);
}
You have done well upto the point you understood you need to pass a pointer to pointer. But your function signature doesn't take an int **. Either you pass a pointer to pointer and store the allocated memory in it:
void Init(int **pp, int num)
{
int *p;
p = malloc(num*sizeof(int));
if (!p)
{
printf("Cannot allocate memory\n");
}
*pp = p;
}
And check if the Init() returns a proper pointer:
Init(&p, num);
if(p == NULL) {
/*Memory allocation failed */
}
Or allocate memory and return the pointer:
int* Init(int num)
{
int *p;
p = malloc(num*sizeof(int));
if (!p)
{
printf("Cannot allocate memory\n");
}
return p;
}
and from main() call as:
int * p = Init(num);
if(p == NULL) {
/*Memory allocation failed */
}
Change the prototype of Init() accordingly.
In any case, you must not free() the pointer in Init(). That just de-allocates memory immediately and you'll be left with a dangling pointer.
And you need to free() in the main() after you are done with it.
int *pp;
p = (int *)malloc(num*sizeof(int));
if (!pp) /* pp is used uninitialized at this point */
int *p;
int num, i;
puts("Enter num of grades:");
scanf("%d", &num);
Init(&p, num);
free(p); /* p is used uninitialized at this point */
If you want to allocate space for a pointer to int inside another function, you need to pass a pointer to pointer:
...
Init(&p, num);
...
int Init(int **pp, int num)
{
*pp = malloc(num * sizeof(int));
...
First you need to fix the prototype of your function. It should be
int* Init(int** p, int num);
Then fix the function definition
int* Init(int** p, int num)
{
//int *pp; // You don not need this variable
*p = malloc(num*sizeof(int)); // Allocate memory
if (!*p)
{
printf("Cannot allocate memory\n");
return NULL; // Return a NULL pointer
}
return *p;
}
Some typos in your code,
p = (int *)malloc(num * sizeof(int));
should be
pp = (int *)...
Your free(pp); is what is causing it to not work chiefly, you do not want to call that or the memory you allocated will not be saved. Also the memory of pp is essentially "lost" at the end of the function call as method parameter to Init p is a value copy not exact reference to main's version of p, thus when Init returns, the changes to p are 'lost'.
simply do: p = Init(); and in init return pp;
Exp:
This line p = pp, sets variable p to point to the memory allocated by pp, thus a free of pp is a free to p as well.
I am not sure if returning an address to memory is always considered good practice, as you have to ensure it is freed, but for your program it would work.
It's very important to know that your function doesn't modify your pointer (*p),The **p is lost And *p doesn't have a valid and known memory address in the Main function.
To allocate the memory safely I suggest these two functions.
void init(int **p,int number){
*p = malloc(number*sizeof(int));
}
If you want that your function returns the pointer allocated you can do this:
int* init(int number){
int* p = malloc(number*sizeof(int));
return p;
}
I want to create function that adds words into dictionary
so far i made this
void addWord(char **dictionary,int *dictionarySize,int *wordsInDictionary,char *word){
if(dictionary == NULL)
{
*dictionary = (char *)malloc(sizeof(char*)*(*dictionarySize));
}
else
{
if(*wordsInDictionary==*dictionarySize)
{
*dictionary = (char *)realloc(dictionary,sizeof(char*)*(*dictionarySize)*2);
(*dictionarySize)*=2;
}
}
dictionary[*wordsInDictionary]=word;
(*wordsInDictionary)++;
}
in main() i have
int i;
int dictSize = 1;
int wordsInDict = 0;
char *word;
char *dictionary;
dictionary=NULL;
then i want to print all words in dictionary , but here i get warning that %s is expecting char* but it is int
printf("Stats: dictsize: %d, words in dict: %d\n", dictSize,wordsInDict);
for(i=0;i<wordsInDict;i++)
{
printf("%d. %s\n",i, dictionary[i]);
}
it also gives me errors when i try to add words
i use this call to add words
addWord(&dictionary,&dictSize,&wordsInDict,word);
In your addWord function, dictionary will never be NULL.
And that's only the start of your problems. Because you want dictionary to be an array of arrays, which mean you need to declare it as a pointer to a pointer (if you want it to be dynamic). However, you declare it as just a (single) pointer. It's in the main function (or where ever you declare it originally) that you need to declare it as a pointer to a pointer. And you need to initialize it, or it will have an indeterminate value and using it in any way other than initializing it will lead to undefined behavior.
That means your addWord function should take a pointer to a pointer to a pointer, i.e. one more level of indirection. And you need to use the dereference operator to get the original pointer to pointer.
So the addWord function should start like e.g.
void addWord(char ***dictionary, int *dictionarySize, int *wordsInDictionary,char *word){
if(*dictionary == NULL)
{
*dictionary = malloc(sizeof(char*) * (*dictionarySize));
}
...
}
Also note that I don't cast the return of malloc.
Also note that realloc can fail, and then will return NULL, so if you assign the return to the same pointer you reallocate you will loose the original pointer. Always use a temporary pointer for the return-value of realloc and only assign to the real pointer after checking that the reallocation succeeded.
I suggest that you put together the members of the dictionary in one as a structure, rather than having individually.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct dictionary {
char **words;//array of char *
int size;
int numOfWords;
} Dictionary;
Dictionary *D_new(void){
Dictionary *dic = malloc(sizeof(*dic));
if(dic){
dic->size = 16;//initial size
dic->words = malloc(dic->size * sizeof(*dic->words));//check omitted
dic->numOfWords = 0;
}
return dic;
}
void D_drop(Dictionary *dic){
int i;
for(i=0;i<dic->numOfWords; ++i)
free(dic->words[i]);
free(dic->words);
free(dic);
}
void addWord(Dictionary *dic, const char *word){
if(dic == NULL){
return ;
}
if(dic->numOfWords == dic->size){
dic->words = realloc(dic->words, sizeof(*dic->words)*(dic->size*=2));//check omitted
}
dic->words[dic->numOfWords++]=strdup(word);//make copy
}
int main(void){
int i;
Dictionary *dictionary = D_new();
addWord(dictionary, "apple");
addWord(dictionary, "banana");
addWord(dictionary, "melon");
printf("Stats: dictsize: %d, words in dict: %d\n",
dictionary->size, dictionary->numOfWords);
for(i=0;i<dictionary->numOfWords;i++){
printf("%d. %s\n", i, dictionary->words[i]);
}
D_drop(dictionary);
return 0;
}
In one of the programs, I created a function whose one argument was a pointer. The function dynamically allocated some memory to the pointer and returned the size of allocated memory along with other details. But, the allocated memory is destroyed as soon as the function is executed.
How can I retain access and data integrity outside the function to the memory allocated inside the function?
Here's the code modified after reading the replies:
void initialize(int **arr)
{
int i = 0;
*arr = malloc(sizeof(int) * 10);
for (; i < 10; ++i)
*arr[i] = i + 1;
for (i = 0; i < 10; ++i)
printf("\n%d", *arr[i]);
}
int main()
{
int i = 0;
int *arr;
initialize(&arr);
for (; i < 10; ++i)
printf("\n%d", arr[i]);
return 0;
}
But when I run it, it says "rr.exe has stopped working"; although it compiles successfully. Nothing gets printed, not even from the printf in the the function.
Do not call free() on the pointer received by the dynamical allocation, but return it from the function to the calling process.
Example:
#include <stdlib.h>
#include <stdio.h>
#include <errno.h>
/* give_me_memory(void ** ppv, size_t n) allocates n bytes to *ppv. */
/* The function returns 0 on success or -1 on error. On error errno is set accordingly. */
int give_me_memory(void ** ppv, size_t n)
{
if (NULL == ppv)
{
errno = EINVAL; /* Bad input detected. */
return -1;
}
*ppv = malloc(n);
if (NULL == *ppv)
{
return -1; /* malloc() failed. */
}
return 0; /* Getting here mean: success */
}
int main(void)
{
void * pv = NULL;
if (-1 == give_me_memory(&pv, 42))
{
perror("give_me_memory() failed");
return 1;
}
/* Do something with the 42 bytes of memory. */
free(pv);
return 0;
}
I guess your function looks like:
void f(int *pointer)
{
pointer = (int*)malloc(sizeof(int));
}
this is bad because, your function gets a copy of pointer. Imagine your function takes int as argument and changes its value. Original variable passed to function won't changed, because you passed it as a copy. Here We have the same - you can modify what's poitner pointing at, but not pointer itself.
What do we do when we want to pass variable to function so it can be changed inside? We pass it as a pointer. here You need to do the same - pass pointer to pointer:
void f(int **pointer)
{
*pointer = (int*)malloc(sizeof(int));
}
and call it like this:
int *p = 0;
f(&p);
This is one of those annoying things where you know the answer is easy, but you just can't see it.
The printf statement in AllocIntArray shows that arrayPtr is correctly being assigned a memory location, however when the printf statement in main is run, it shows arrayB is still set to NULL.
Can someone show me what I am doing wrong when passing in arrayB to AllocIntArray?
#include <stdio.h>
#include <stdlib.h>
void AllocIntArray(int *arrayPtr, int numElements);
int main()
{
int *arrayB = NULL;
AllocIntArray(arrayB, 10);
printf("Pointer: %p\n", arrayB);
free(arrayB);
getchar();
return EXIT_SUCCESS;
}
void AllocIntArray(int *arrayPtr, int numElements)
{
arrayPtr = (int *)malloc(sizeof(int) * numElements);
printf("Pointer: %p\n", arrayPtr);
if(arrayPtr == NULL)
{
fprintf(stderr, "\nError allocating memory using malloc");
exit(EXIT_FAILURE);
}
}
Pass the double pointer.
#include <stdio.h>
#include <stdlib.h>
void AllocIntArray(int **arrayPtr, int numElements);
int main()
{
int *arrayB = NULL;
AllocIntArray(&arrayB, 10);
printf("Pointer: %p\n", arrayB);
free(arrayB);
getchar();
return EXIT_SUCCESS;
}
void AllocIntArray(int **arrayPtr, int numElements)
{
*arrayPtr = malloc(sizeof(int) * numElements);
printf("Pointer: %p\n", *arrayPtr);
if(*arrayPtr == NULL)
{
fprintf(stderr, "\nError allocating memory using malloc");
exit(EXIT_FAILURE);
}
}
That's because arrayB is passed to AllocIntArray by value. Either pass it by reference (with a pointer-to-pointer), or better, return it from AllocIntArray:
int *AllocIntArray(int numElements)
{
int *arrayPtr = malloc(sizeof(int) * numElements);
printf("Pointer: %p\n", arrayPtr);
if(arrayPtr == NULL)
{
fprintf(stderr, "\nError allocating memory using malloc");
exit(EXIT_FAILURE);
}
return arrayPtr;
}
You need to brush up a bit on parameter passing to functions.
The pointer you are sending to AllocIntArray is being copied into arrayPtr, The line
arrayPtr = (int *)malloc(sizeof(int) * numElements);
assigns a value into the copy, and not the original variable, and therefore the original variable still points to nowhere.
First solution that comes to mind is to send a pointer to that pointer, but I think you'd best do some general brushing up on the matter of parameter passing before going much further.
arrayPtr is a pointer and the pointer is passed by value to the parameter. AllocIntArray can modify its version of arrayPtr but the changes won't be seen by main().
(Edit: if you're using C++) modifying the signature for AllocIntArray to change the type of arrayPtr to a reference ought to fix your problem.
void AllocIntArray(int *&arrayPtr, int numElements)
The basic problem here is you are passing arrayB to AllocIntArray function as passed by value .In AllocIntArray its allocating memory properly and arrayptr is valid but in main function its not the same memory which you are expecting .
This is the basic C programming concept and you can check bu adding print in both the function .
EX: I am sharing the difference between both problem and success case with below example .
/*Code with passed by value as a parameter*/
#include<stdio.h>
#include<stdlib.h>
void AllocateIntarray(int *arrayptr,int numElements)
{
arrayptr = (int*) malloc(sizeof(int)*numElements);
printf("Inside _func_AllocateIntarray_pointer:%p\n",arrayptr);
if(arrayptr == NULL)
{
printf("ERR_MEM_ALLOCATION_FAILED:\n");
}
}
int main()
{
int *arrayB = NULL;
AllocateIntarray(arrayB,10);
printf("Inside _func_mainPointer:%p\n",arrayB);
free(arrayB);
return 0;
}
/*Output :
Inside _func_AllocateIntarray_pointer:0x55be51f96260
Inside _func_mainPointer:(nil)*/
Code with Passed by reference and using double pointer .
#include<stdio.h>
#include<stdlib.h>
void AllocateIntarray(int **arrayptr,int numElements)
{
*arrayptr = malloc(sizeof(int)*numElements);
printf("Inside _func_AllocateIntarray_pointer:%p\n",*arrayptr);
if(*arrayptr == NULL)
{
printf("ERR_MEM_ALLOCATION_FAILED:\n");
}
}
int main()
{
int *arrayB = NULL;
AllocateIntarray(&arrayB,10);
printf("Inside _func_mainPointer:%p\n",arrayB);
free(arrayB);
return 0;
}
/*Output :
Inside _func_AllocateIntarray_pointer:0x562bacd1f260
Inside _func_mainPointer:0x562bacd1f260*/