I am new to C and I was trying to code up a dynamic int array that lets the user type in numbers via terminal untill the user types in -1. So the user can type any amount of int's and the data is reallocated each time another valid int is input.
Sometimes it works as expected other times I get: free(): double free detected in tcache 2
Aborted (core dumped) error.
I am printing the values after every input and everything seems fine untill -1 is input. And the bug only occures every other time.
Here is my Code:
void output(int *ptr, int len){
printf("\n");
for(int i=0; i<len; i++){
printf("%d %p \n", ptr[i], ptr+i);
}
printf("\n");
}
int input(int *ptr, int *size){
int x;
printf("Insert your numbers:\n");
while(1){
scanf("%d", &x);
if(x == -1) break;
size[0]++;
// printf("Size: %d\n", size[0]);
ptr = realloc(ptr, size[0] * sizeof(int));
if(ptr == NULL) return -1;
int indexToStore = size[0]-1;
// printf("Index: %d\n", indexToStore);
ptr[indexToStore] = x;
output(ptr, size[0]);
}
return 0;
}
int main()
{
int size = 0;
int *array = (int*)malloc(sizeof(int));
if(array == NULL) return -1;
input(array, &size);
output(array, size);
input(array, &size);
output(array, size);
free(array); array = NULL;
return 0;
}
The argument ptr of the function input is a copy of what is passed and modifying that will not affect what is passed in caller.
Therefore, the change in buffer via realloc() is not saved from the 1st call of input() to the 2nd call of input() and it will lead to troubles.
You should pass a pointer to what should be modified to have functions modify caller's local things.
#include <stdio.h>
#include <stdlib.h>
void output(int *ptr, int len){
printf("\n");
for(int i=0; i<len; i++){
printf("%d %p \n", ptr[i], ptr+i);
}
printf("\n");
}
int input(int **ptr, int *size){
int x;
printf("Insert your numbers:\n");
while(1){
scanf("%d", &x);
if(x == -1) break;
size[0]++;
// printf("Size: %d\n", size[0]);
*ptr = realloc(*ptr, size[0] * sizeof(int));
if(*ptr == NULL) return -1;
int indexToStore = size[0]-1;
// printf("Index: %d\n", indexToStore);
(*ptr)[indexToStore] = x;
output(*ptr, size[0]);
}
return 0;
}
int main()
{
int size = 0;
int *array = (int*)malloc(sizeof(int));
if(array == NULL) return -1;
input(&array, &size);
output(array, size);
input(&array, &size);
output(array, size);
free(array); array = NULL;
return 0;
}
Related
This is my beginner program experimentation with what I have learned on dynamic memory allocation, pointers, and files. Every time I compile I keep having a segmentation fault. I haven't been able to fix this error that occurs during fscanf().
#include <stdio.h>
#include <stdlib.h>
// create int aboveavg();
double average(int *ptr, int size){
int count = 0;
double sum = 0;
while(count <= size){
sum += *ptr;
ptr++;
count++;
}
sum /= size;
return sum;
}
int main(){
int n = 10;
int *ptr = (int*)calloc(n, sizeof(int)); //allocate dynamic memory
printf("Allocated %d integers\n", n);
FILE *input = fopen("a.txt" , "r"); //open file
if(input = NULL){ //error check
printf("Error! memory not allocated.");
exit(0);
}
int count = 0, i=0;
printf("check point\n");
while(fscanf(input, "%d", &ptr[i]) == 1){ //**Segmentation Fault**
if(count == n){
n *=2;
ptr = (int*)realloc(ptr,n* sizeof(int));
printf("Reallocated to %d integers\n", n);
}
i++;
count++;
}
fclose(input);
double avg = average(ptr, n);
printf("average of %f\n", avg);
free(ptr);
printf("Dynamic array freed\n");
return 0;
}
Searching for an answer (google or stack overflow), hasn't really helped me. Can anyone can hint/point to what I did wrong.
I'm new to this fantastic site and I found it very useful in many occasions, but now I'm dealing with a problem which I can't seem to solve.
I'm a beginner C student and I'm studying dynamic memory allocation.
I want to create a dynamic array of, let's say, integers, allocating memory for it inside a procedure, not in the main function.
This works:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int *numbers; // pointer to create a dynamic array
int *test; // pointer to test realloc function
int c;
size_t i = 0;
unsigned int dim; // array's length
// allocate memory for the 1st number
numbers = malloc(sizeof(*numbers));
if (numbers == NULL) {
fputs("Error while allocating memory!\n", stderr);
} else {
printf("Insert the 1 number: ");
scanf("%d", &numbers[0]);
++i;
/* allocate memory for the other numbers,
* until the user inputs EOF
*/
while (!feof(stdin)) {
test = realloc(numbers, (sizeof(*numbers) * (i + 1)));
if (test == NULL) {
fputs("Error while allocating memory!\n", stderr);
} else {
numbers = test;
printf("Insert the %u number: ", i + 1);
scanf("%d", &numbers[i]);
++i;
}
}
dim = --i;
// print the array, 5 numbers per line
for (i = 0; i < dim; ++i) {
if (i % 5 == 0) {
puts("");
}
printf("%d ", numbers[i]);
}
puts("");
}
getchar();
return 0;
}
But I want to do this (which doesn't work):
#include <stdio.h>
#include <stdlib.h>
void get_numbers(int **numbers, unsigned int *dim);
int main()
{
int *numbers; // pointer to create a dynamic array
size_t i = 0;
unsigned int dim; // array's length
get_numbers(&numbers, &dim);
// print the array, 5 numbers per line
for (i = 0; i < dim; ++i) {
if (i % 5 == 0) {
puts("");
}
printf("%d ", numbers[i]);
}
puts("");
getchar();
return 0;
}
void get_numbers(int **numbers, unsigned int *dim)
{
int *test; // pointer to test realloc function
int c;
size_t i = 0;
// allocate memory for the 1st number
*numbers = malloc(sizeof(*numbers));
if (*numbers == NULL) {
fputs("Error while allocating memory!\n", stderr);
} else {
printf("Insert the 1 number: ");
scanf("%d", &numbers[0]); // Maybe the error is here
++i;
/* allocate memory for the other numbers,
* until the user inputs EOF
*/
while (!feof(stdin)) {
test = realloc(*numbers, (sizeof(*numbers) * (i + 1)));
if (test == NULL) {
fputs("Error while allocating memory!\n", stderr);
} else {
*numbers = test;
printf("Insert the %u number: ", i + 1);
scanf("%d", &numbers[i]);
++i;
}
}
*dim = --i;
}
}
Do I need to use a pointer to a pointer to int, right?
I know I made some mistakes but I can't figure out how to fix them.
Thanks in advance for your replies!
Bye,
Fabio Nardelli
In the first block of code, numbers is of type int*.
In the second block of code, numbers is of type int**.
You have not fixed all the places that need to be fixed because of that change.
My suggestion:
Change the input argument to numbersPtr.
Create a local variable int* numbers.
Before you return from the function, set *numbersPtr to number.
void get_numbers(int **numbersPtr, unsigned int *dim)
{
int* numbers;
...
*numbersPtr = numbers;
}
It will be better to change get_numbers to return numbers.
int* get_numbers(unsigned int *dim)
{
int* numbers;
...
return numbers;
}
and change its usage as:
numbers = get_numbers(&dim);
#include<stdio.h>
#include <stdlib.h>
#include<fcntl.h>
main()
{
int fd, retval, i;
int ptr;
char buff[1000];
system("ps -A --no-headers -o pid>pid.txt");
fd = open("pid.txt", O_RDONLY);
retval = read(fd, buff, 1000);
buff[retval] = '\0';
int count= get_count(buff);
ptr = get_each_pid(buff, count);
for(i=0; i< count; i++)
printf("%d \n", *(ptr+i));
}
int get_each_pid(char *pids, int count)
{
int val, i, j=0, k=0,l=0;
char temp[10];
int *p= (void *)malloc(count);
for(i=0; pids[i]!='\0'; i++)
{
if(pids[i]!=' ')
{
temp[j]= pids[i];
j++;
if(pids[i+1]=='\n')
{
temp[j]='\0';
val=atoi(temp);
// printf("int: %d \n", val);
for(k=l; k<=l; k++)
*(p+k)=val;
i++;
l++;
j=0;
}
}
}
return p;
}
int get_count(char *str)
{
int i, count=0;
for(i=0; str[i]!='\0'; i++)
{
if(str[i]=='\n')
count++;
}
return count;
}
Here I want to get all the process ids in my system and want to open one by one. To acheive that I need to store all the pids in a txt file, convert each string into integer and store it in a array: Upto here the code if fine. The problem is I want to return the starting address to main function. Could anyone please check on this. Any help would be much appreciated.
You should change the get_each_pid function prototype to:
int* get_each_pid(char *pids, int count)
since you are returning a pointer
I tried to write a program which used a function to read the data, store in an array and then tried to return the array to main() for the sorting process.
Here's what I have
#include <stdio.h>
#include <stdlib.h>
#define RESERVED_ARRAY_SIZE 100
int* read_data_from_files()
{
int* arr = (int*) malloc(sizeof(int) * 50);
int arr_count;
int status;
int i,j ;
arr_count =0;
i=0;
FILE *cfPtr;
if ((cfPtr = fopen ("score.dat", "r"))== NULL)
{
printf("File cannot be opend\n");
}
else
{
fscanf(cfPtr, "%d", &arr[i]);
printf("%5d%5d\n", i, arr[i]);
while (!feof (cfPtr))
{
++i;
++arr_count;
status = fscanf(cfPtr, "%d", &arr[i]);
if (status == EOF)
{
break;
}
else if (status != 1)
{
fprintf (stderr, "Error input\n");
getchar();
}
if (arr_count >= RESERVED_ARRAY_SIZE)
{
fprintf(stderr, " The number of array is over.\n");
getchar();
}
printf("%5d%5d\n", i, arr[i]);
}
fclose (cfPtr);
}
printf("arr_count=%d\n", arr_count);
return arr;
}
int main()
{
int i;
int arr_count;
int* arr = (int*) malloc(sizeof(int) * 10);
arr = read_data_from_files();
arr_count = sizeof(arr)/sizeof(arr[0]);
printf("this check the size of array%d", arr_count);
for (i=0; i<9; i++)
{
printf("%d ", i);
printf("%d", *arr[i]);
}
selection_sort(arr, arr_count);
getchar();
return 0;
}
My questions are
1. If functions cannot return 2 values, what shuold I do to pass the array size(the arr_count in my program) in the funcution to the main()?
2. If the function only returns the pointer of the array to the main(), can I figure out the size of the array in the main? what should I do ?
Thans a lot for your assistants.
No, you cannot figure out the size automatically. The standard way to return multiple values is to pass a pointer to a variable in which you want to store the extra return value:
int* read_data_from_files(int *result_size)
{
...
*result_size = arr_count;
...
return arr;
}
int main()
{
int arr_count;
int *arr = read_data_from_files(&arr_count);
...
}
You could make a variable size in the main function, and have the function call pass the address to read_data_from_files() as an additonal argument. read_data_from_files() can then modify the value from inside the function, and you won't need to return it.
Here is my code:
#include <stdio.h>
#include <stdlib.h>
#define MAX 50
float** getdata(void);
void calculations(float* fPtr);
//void printoriginal(float* values, int inputnum, float* fPtr);
int main(void)
{
float** fPtr;
float* values;
fPtr = getdata();
calculations(*fPtr);
int element;
// printoriginal(*values, inputnum, *fPtr);
system("PAUSE");
return 0;
}
float getvalues(void)
{
float* values = (float*)calloc(*inputnum, sizeof(float));
float** getdata(void)
{
int i;
int n;
float** fPtr;
int* inputnum;
printf("How many values do you want to input into the array?");
scanf("%d", inputnum);
float* values = (float*)calloc(*inputnum, sizeof(float));
if (values == NULL)
{ printf("Memory overflow\n");
exit(101);
}
for(i = 0; i < *inputnum; i++)
{
n = i + 1;
printf("Please enter your %d number: ", n);
scanf("%f",(values+i));
}
fPtr = (float**)calloc(*inputnum+1, sizeof(float*));
if (fPtr == NULL)
{ printf("Memory overflow\n");
exit(101);
}
for(int c=0; c < *inputnum; c++)
{
*(fPtr+i) = (values+i);
}
printf("%f", values+2);
return fPtr;
}
I scanf the values in getdata, but I am scanning in garbage. Im pretty certain my scanf is off. Also, how would I be able to pass back my values array through reference?? I am having a very hard time with that as well. Thanks everyone.
Instead of
int * inputnum;
scanf( ..., inputnum );
you want:
int inputnum;
scanf( ..., &inputnum );
Either that, or you need to insert an allocation of inputnum:
/* Very non-C-worthy code sample */
int * inputnum;
inputnum = malloc( sizeof *inputnum );
if( inputnum == NULL ) {
perror( "malloc" );
exit( EXIT_FAILURE );
}
scanf( ..., inputnum );
but that will look very strange to anyone familiar with C
(Unless there is some other reason for it, and in this
case there does not appear to be any reason.)
The problem you are experiencing is that the scanf is
storing the received value in the location pointed to
by inputnum, which is a bogus location since inputnum
is uninitialized.
I like to have objects "assigned" to one single function. In your program, your values are created in the function getdata(), used in calculations() and never released.
If the main() function was responsible for them, it would make coding easier, in my opinion. Something like
int main(void) {
int inputnum, innum;
double *fPtr;
printf("How many values do you want to input into the array?");
fflush(stdout);
if (scanf("%d", &inputnum) != 1) {
fprintf(stderr, "Error in input. Program aborted.\n");
exit(EXIT_FAILURE);
}
if (inputnum > MAX) { /* ... nothing yet ... */ }
fPtr = calloc(inputnum, sizeof *fPtr);
if (fPtr == NULL) {
fprintf(stderr, "Not enough memory. Program aborted.\n");
exit(EXIT_FAILURE);
}
/* use fPtr in other functions */
innum = data_get(fPtr, inputnum);
data_print(fPtr, innum);
free(fPtr);
return 0;
}
In the snippet above, I used the functions data_get() and data_print() with a somewhat different prototype than you have. These functions take a pointer and a number of elements.
int data_get(double *data, int num);
void data_print(double *data, int num);
The first one reads up to num doubles into the memory pointed to by data and returns the number of doubles that was effectively entered.
The second takes number of doubles to print.
Oh! Unless you have a very good reason to use floats, don't use them. Always prefer doubles.
Also Instead of
printf("%f", values+2);
use
printf("%f", *(values+2));
There is so many errors, I didn't know where to start :)
Code completely rewritten below. Please study this.
#include <stdio.h>
#include <stdlib.h>
#define MAX 50
int get_data (float** array); /* must be pointer-to-pointer to return through parameter */
void print_data (const float* array, int size); /* print data */
void do_weird_things (float* array, int size); /* do weird things with the data */
void clear_data (float* array); /* clean up */
int main(void)
{
float* array;
int size;
size = get_data (&array);
printf("Before weird things:\n");
print_data (array, size);
do_weird_things (array, size);
printf("After weird things:\n");
print_data (array, size);
clear_data (array);
system("PAUSE");
return 0;
}
int get_data (float** array)
{
int i;
int items;
printf("How many values do you want to input into the array? ");
scanf("%d", &items);
getchar(); /* remove \n from stdin */
*array = calloc(items, sizeof(float));
if (*array == NULL)
{
printf("Memory overflow\n");
exit(EXIT_FAILURE);
}
for(i = 0; i < items; i++)
{
printf("Please enter your %d number: ", i+1);
scanf("%f", (*array) + i);
getchar(); /* remove \n from stdin */
}
return items;
}
void do_weird_things (float* array, int size) /* do whatever data manipulation you wish here */
{
int i;
for(i=0; i<size; i++)
{
array[i] += i;
}
}
void print_data (const float* array, int size)
{
int i;
for(i=0; i<size; i++)
{
printf("%f\t", array[i]);
}
printf("\n");
}
void clear_data (float* array)
{
free(array);
}