Creating a int * with malloc and then use realloc when full - c

In a function I created am I trying to allocate a int array dynamically to store some index values.
First I create the int * with the malloc function and then let the loop store som values in it and increament the pointer each time.
The problem I run in to starts when I try to use the realloc to increase the memory allocation.
When I do this VS tells me it runs in to undefined behaviour and breaks the program.
The code looks like this
void showAvailable(CabinHolder *holder, Booking *booking)
{
system("cls");
printf("Choose cabin number \n");
printf("Start week: &d \t End week: %d", booking->rentPeriod[0], booking->rentPeriod[1]);
printf("------------------------------------------\n");
int memory = 5;
int *indexOfCabin = (int *)malloc(sizeof(int)*memory);
int counter = 1;
for (int i = 0; i < CABINS; i++)
{
if (counter == memory)
{
memory *= 2;
int *expanded = realloc(indexOfCabin, (memory * sizeof(int)));
indexOfCabin = expanded;
expanded = NULL;
}
if (booking->cabin->typeOfCabin == holder->arrofCabin[i].typeOfCabin)
{
printf("%d. \t Cabin with number %d \t cost: %d per week\n", counter, holder->arrofCabin[i].nr, holder->arrofCabin[i].cost);
counter++;
indexOfCabin = &i;
indexOfCabin++;
}
}
free(indexOfCabin);
system("pause");
}
When I debugg in VS i also se that my pointer indexOfCabin seems to be undefined inside the if statement, which I don't understand.
What have I missed here?

Okay after some help in the comment section I solved the problem with this edited code segment.
void showAvailable(CabinHolder *holder, Booking *booking)
{
system("cls");
printf("Choose cabin number \n");
printf("Start week: %d \t End week: %d\n", booking->rentPeriod[0], booking->rentPeriod[1]);
printf("------------------------------------------\n");
int memory = 5;
int *indexOfCabin = malloc(sizeof(int)*memory);
int counter = 1;
int items = 0;
int choice = 0;
for (int i = 0; i < CABINS; i++)
{
if (counter-1 == memory)
{
memory *= 2;
indexOfCabin = realloc(indexOfCabin, (memory * sizeof(int)));
}
if (booking->cabin->typeOfCabin == holder->arrofCabin[i].typeOfCabin)
{
printf("%d. \t Cabin with number %d \t cost: %d per week\n", counter, holder->arrofCabin[i].nr, holder->arrofCabin[i].cost);
counter++;
indexOfCabin[items++] = i;
}
}
free(indexOfCabin);
system("pause");
}
First: Problem was indexOfCabin = &i throws away the memory you allocated, and puts the address of i into the pointer instead of what I wanted to do. Now we store the index in i in the pointer.
Second: indexOfCabin can be used like an array, e.g. indexOfCabin[counter] = i;. But counter needs to start at 0, and should be incremented after being used. And indexOfCabin should not be incremented

Related

Pointer in C gives all zero values

I made a number guessing game and want to print out all of the numbers that the user guessed while playing the game. However, when I run the program, it always prints out zero for all the values.
Your Tries: 0, 0, 0, 0, 0, %
It may be something wrong with the way I assigned the pointer value? Any help would be appreciated
#include <time.h>
#include <stdlib.h>
#include <stdio.h>
int arr_size = 0;
int main()
{
// Initialize random number with seed 2021.
// Do not change this line, and do not call srand again.
srand(2022);
// the next line generate a random number between 1 to 100
int n = (rand() % 100) + 1;
int *p = malloc(sizeof(int) * arr_size);
while(1){
int guess;
scanf("%d", &guess);
arr_size ++;
p = realloc(p, sizeof(int) * arr_size);
p[arr_size-1] = guess;
if(n > guess){
printf("The Number is greater than %d\n", guess);
}else if(n < guess){
printf("The Number is less than %d\n", guess);
}else{
printf("You win. The Number is %d\n", guess);
break;
}
if(guess == -1){
printf("You input wrong number\nYou lose. The Number is %d", n);
break;
}
}
printf("Your Tries: ");
for(int i = 0; i < arr_size; i ++){
printf("%d, ", p[arr_size]);
}
return 0;
}
int *p = malloc(sizeof(int) * arr_size);
Allocating zero bytes isn't safe, the compiler can either return a null pointer or a pointer pointing at weird stuff, which may or may not be reallocatable(?). Replace this with int *p = NULL; to get deterministic, portable behavior instead.
p = realloc(p, sizeof(int) * arr_size); There is no guarantee that p is pointing at the reallocated data after this. Correct use of realloc is:
int* tmp = realloc(p, sizeof(int) * arr_size);
if(tmp == NULL) { /* handle errors */ }
p = tmp;
You never free(p).
There is no need to use dynamic allocation to begin with here, all you achieve with it is needless complexity, bloat and a much slower program. Just use int p[100]; and watch all your problems go away, while at the same time massively improving execution speed.
printf("%d, ", p[arr_size]); is nonsense and out of bounds, use p[i].

Passing struct array to function and calculating average in C?

Beginner here, I've been trying this for hours and can't get it to work, searched online too and couldn't find an answer.
I'm trying to write a program where you input people by putting their age and height then calculate the average of each, and the average ratio of age to height. Whenever I pass the struct to my getAverage function, it returns the address (I think) instead of the averages.
#include <stdio.h>
#include <stdlib.h>
typedef struct person
{
int age;
double height;
} Person;
double getAv (Person people[50], int max)
{
int i;
double total, retval;
total = 0;
for (i=0; i<=max; i++)
{
total = total + people[i].age;
}
retval = total / max;
return retval;
}
int main (void)
{
Person people[50];
int i;
while (i++, people[i].age>=0)
{
printf ("Person #%d\n", i);
printf ("enter an age: ");
scanf ("%d", &people[i].age);
if (people[i].age<0)
break;
printf ("enter a height: ");
scanf ("%lf", &people[i].height);
printf ("\n");
}
double averageAge;
averageAge = getAv (&people[50], i);
printf ("%.1lf\n", averageAge);
}
Haven't implemented average height or ratio yet, just trying to get average of ages to work for now. When I try taking the & out of averageAge = getAv(&people[50], I); I get a compile error that tells me it needs the &. Any help would be appreciated.
There are serveral issues in you code, the first one:
Person people[50];
int i;
while (i++, people[i].age>=0)
You are using i uninitialized, thus, incrementing a variable containing garbage (or 0 as intended, but it is impossible to guarantee)
To avoid such problems in the future enable warnings on your compiler, the compiler would have told you something like:
ā€˜iā€™ is used uninitialized in this function [-Wuninitialized]
So switch to
Person people[50] = {0};
int i = 0;
It seems (based on the pre-increment operator ++i) that you want to use arrays with base 1, there is nothing wrong with that, but in your average function you are starting from 0, so use a for:
for (i = 0; ; i++)
{
...
if (people[i].age <= 0) break;
...
}
Another issue:
double averageAge;
averageAge = getAv (&people[50], i);
In this way you are passing only element 50 which is not part of your array (remember arrays are base 0 in C), to pass the entire array:
averageAge = getAv (people, i);
or
averageAge = getAv (&people[0], i);
The last one:
for (i=0; i<=max; i++)
You are including the element discarded when you was checking for age > 0, switch to:
for (i=0; i<max; i++)
A minor issue:
Iif the user enters 0 for the first element of people you end up dividing by 0
double averageAge;
averageAge = getAv (&people[50], i);
printf ("%.1lf\n", averageAge);
should be
if (i > 0)
{
double averageAge;
averageAge = getAv (people, i);
printf ("%.1f\n", averageAge); // No need to use lf (long double)
}
If you do it this way, you need to receive in your function (Person& people[], int n)
Where n is the length of the array.
We use the '&' to not do copies of the array and also you are passing only the element with index 50 in the function, simply do only (people, n)
there are mistakes in this code ,first you should initialize int i to int i=0 in mian function.
how are using this condition while (i++, people[i].age>=0) when you haven't scanned any input it's like using an uninitialized variable. you need a do-while like this
do
{
printf("Person #%d\n", i);
printf("enter an age: ");
scanf("%d", &people[i].age);
if (people[i].age < 0)
break;
printf("enter a height: ");
scanf("%lf", &people[i].height);
printf("\n");
i++;
} while (people[i-1].age >= 0);
also you are sending wrong arguments to your getAv function you should use averageAge = getAv (people, i);.
and in your function you have to remove = in this loop for (i=0; i<=max; i++) .this should be for (i=0; i<max; i++) ,otherwise the negative entered age will also be add to total and will affect the average.

How to properly free dynamically allocated memory for an array of pointers to int's

I need to know if I have used free() correctly while attempting to free dynamically allocated memory for an array of pointers to int's.
My code is modified from a code snippet out of one of my books and is the beginning of a program which requests temperature readings for three cities.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int ctr, num, num2 = 0, ctr2 = 0;
int* temps[3];
for(ctr = 0; ctr < 3; ctr++)
{
puts("how many readings for the city?");
scanf(" %d", &num);
temps[ctr] = (int*)malloc(num * sizeof(int));
num2 += num;
while(ctr2 < num2)
{
puts(" what is reading? ");
scanf(" %d", &temps[ctr][ctr2]);
printf("echo: %d ", temps[ctr][ctr2]);
ctr2++;
}
}
for(ctr = 0; ctr < 3; ctr++)
{
free(temps[ctr]);
}
getchar();
getchar();
return (0);
}
I know that a pointer which is assigned memory using malloc() may have values assigned and accessed through a combination of a loop and array indexes. Hence I have assigned values from user input using the indexes of a two dimensional array, and need to know if I used free correctly. I know this is extremely sloppy coding and I am merely seeking to understand free correctly to prevent any potential memory leaks.
it's okay since you respect the same number of loops for allocation and deallocation with the same statement:
for(ctr = 0; ctr < 3; ctr++)
Just make sure that temps can hold at least 3 elements, which is the case, and that num is not zero or undefined (test return value of scanf & value of num). You can use a sizeof formula in your case to avoid hardcoding the value, only because you have an array of pointers, not pointers on pointers.
also avoid casting return value of malloc. And use the size of the element, instead of hardcoding as int (so if type of the pointer changes, your sizes are still right). Improvement suggestion for allocation:
for(ctr = 0; ctr < (int)(sizeof(temps)/sizeof(*temps)); ctr++)
{
puts("how many readings for the city?");
if (!scanf(" %d", &num) || num <= 0) { printf("wrong number\n"); exit(1); } // or better error handling
temps[ctr] = malloc(num * sizeof(*temps[ctr]));
You may still get a segmentation fault when calling free if you corrupt the memory when filling your arrays (a comment suggests it does, since num2 grows and grows). If you get such errors, run your code with valgrind, or just perform allocations/deallocations (and not the rest) to find which part of the code causes the problem.
The proper way of freeing the dynamically allocated memory is to free it after you check if it has been allocated at the very first place or not. As your loop structure is same for allocating and freeing, there wont be any problem here as such if all the allocations are successful. Therefore I suggest you check at all the places if the allocation is successful after allocating and also check if the memory is allocated before freeing.
Following code will make sure all the cases:
scanf(" %d", &num);
/*
* check here if the value of ctr in non-negative and in the appropriate range
*/
temps[ctr] = (int*)malloc(num * sizeof(int));
if (temps[ctr] == NULL) {
printf ("Memory allocation failed\n");
/*
* appropriate error handling
*/
}
Also, check when you are freeing the memory to be on the safer side.
for(ctr = 0; ctr < 3; ctr++)
{
if(temps[ctr]) {
free(temps[ctr]);
}
}
Also there is a bug in your code where after the first iteration itself you will get memory out of bound error, as the variable ctr2 in never reinitialized.
num2 += num;
while(ctr2 < num2)
{
puts(" what is reading? ");
scanf(" %d", &temps[ctr][ctr2]);
printf("echo: %d ", temps[ctr][ctr2]);
ctr2++;
}
Here if the value of num was 20 in the first iteration, then in the second iteration you will end up taking the input starting from temps[1][20], and assuming the value of num in the second iteration to be 5, you have allocated just 5 * sizeof(int)), so obviously you are going out of bounds when you try to access temps[1][20].
Please let me know if the following code would be considered acceptable:
#include <stdio.h>
#include <stdlib.h>
int main()
{
int ctr, num, ctr2 = 0;
int * temps[3];
for(ctr = 0; ctr < (int)(sizeof(temps)/sizeof(*temps)); ctr++)
{
puts("how many readings for the city?");
if (!scanf(" %d", &num) || num <= 0) { printf("wrong number\n"); exit(1); }
temps[ctr] = (int *) malloc(num * sizeof(*temps[ctr]));
while(ctr2 < num)
{
puts(" what is reading? ");
scanf(" %d", &temps[ctr][ctr2]);
printf("echo: %d ", temps[ctr][ctr2]);
ctr2++;
}
ctr2 = 0;
}
for(ctr = 0; ctr < (int)(sizeof(temps)/sizeof(*temps)); ctr++)
{
free(temps[ctr]);
}
getchar();
getchar();
return (0);
}

Printing out dynamically allocated memory in C

I'm a total beginner in programming and got an assignment about dynamically allocated memory. One of the expected outputs was a printf statement where all the entered inputs(integers) are printed in a single line, in a row. I have managed to printf in a for-loop, but thats not enought. How do I printf them in a single code-line? Here's the code:
int main()
{
int how_many_integers, count, entered_integers, i, *pSize;
printf("\nHow many integers are you going to type?\n");
scanf("%i", &how_many_integers);
getchar();
// Allocates memory for the integers.
pSize = malloc (how_many_integers * sizeof(int));
// Checks if the integer is 0, and/or reads in all the integers.
if (how_many_integers == 0)
{
printf("No numbers were given.\n");
exit(0);
}
printf("Please enter your integers.\n");
for (int i = 0; i < how_many_integers; i++)
{
scanf("%i", &entered_integers);
count++;
pSize[i] = entered_integers;
}
for (int i = 0; i < how_many_integers; i++)
{
printf("Number: %i\n", *(pSize+i));
}
free(pSize);
printf("Count: %i", count);
return 0;
}
Try this:
printf("Numbers:");
for (int i = 0; i < how_many_integers; i++)
{
printf(" %i", *(pSize+i)); // No \n
}
printf("\n"); // if you want a new line at the end
This should result in an output like
Numbers: 1 2 3 4 5
And as others mentioned, your count variable is never initialized. Initialize it to 0.

uninitialized variable in function

for the function below i have to sort an array of employees by age in descending order and need the size but cant put it in the function variables, my teacher told me to compute the size by doing this in main but for the loop with j in it it tells me elementSize may be used unitialized in this function. In main it says the int elementSize = " " elementSize is an unused variable.
int elementSize = sizeof(employeeList)/sizeof(Employee);//getting the size of the list
main
#include "lab10.h"
int main() {
Employee employeeList[10000];
readfile(employeeList);
clock_t start,end;
double cpu_time_used;
start = clock();
int elementSize = sizeof(employeeList)/sizeof(Employee);//getting the size of the list
bubbleSort(employeeList);//call bubble sort function to sort list in descending order
printList(employeeList, 25);
end = clock();
cpu_time_used = (double)(end-start)/CLOCKS_PER_SEC*1000;
printf("Time used to compute sorting was %f ms.\n",cpu_time_used);
int bin30=binSearch(employeeList, 0, 9999, 30);//binary search for people of the age of 30
if(bin30== -1){
printf("employees not found!\n");//if employee of age 30 arent found
} else {
printf("%s %s %d %d\n", employeeList[bin30].fname, employeeList[bin30].lname, employeeList[bin30].age, employeeList[bin30].salary); //print out employees info
printf("element present at index %d", bin30);
printf("time used is %f ms\n\n",cpu_time_used);//record time
}
int bin130=binSearch(employeeList, 0, 9999, 130);//binary search for people of the age of 30
if(bin130== -1){
printf("employees not found!\n");//if employee of age 130 arent found
} else {
printf("%s %s %d %d\n", employeeList[bin130].fname, employeeList[bin130].lname, employeeList[bin130].age, employeeList[bin130].salary); //print out employees info
printf("element present at index %d", bin130);
printf("time used is %f ms\n\n",cpu_time_used);//record time
}
return 0;
}
void bubbleSort(Employee employeeList[]) {
int swap;
int i=0;
int j=0;
for(i=0; elementSize > i; i++) {//for loop to sort
for(j=0; elementSize > j ;j++) {
if(employeeList[j+1].age > employeeList[j].age) {//comparing the two values
swap = employeeList[j].age;//swapping the temp variable with the employee
employeeList[j].age= employeeList[j+1].age;//setting the lower employeee to [j]
employeeList[j+1].age = swap;//setting the higher employee to [j+1]
}//end of if statement
}//end of second for loop
}//end of first for loop
}
#include "lab10.h"
//This function reads from a file and creates an array of Employee structure containing their information.
void readfile(Employee employeeList[]){
FILE *fp;
fp = fopen("employeeData.csv", "r");
int i = 0;
if (fp) {
while (i<10000){
fscanf(fp, "%[^,],%[^,],%d,%d\n",employeeList[i].fname,employeeList[i].lname,&employeeList[i].age,&employeeList[i].salary);
i++;
}
}
fclose(fp);
}
void printList(Employee employeeList[], int size)
{
int i=0;
for(i=0; i<size; i++)//going through the first 25 elements of the array
{
printf("%d ", employeeList[i].age);//printing off the elements
}
}
int binSearch(Employee employeeList[], int first, int last, int age)
{
if(first > last){
return -1;//base case
}
int mid= (first + last)/2;//finding middle of the array
if(age > employeeList[mid].age)
return binSearch(employeeList, mid+1, last, age);//searching for high in
binary search through recursion
else if(age < employeeList[mid].age)
return binSearch(employeeList, first, mid-1, age);//searching for low in binary search through recursion
else
return mid;//return the expected value
}
You actually have two variables named elementSize in this code, one global and one local to bubbleSort. The local variable is shadowing the global variable, meaning that the global is not visible. Only the local is visible, and that local was never initialized.
Remove the local elementSize variable and the global one will become visible and will be used.

Resources