I've written a program for a class and am having a problem. The purpose of the program is to read a set of values into an array, calculate the average, and then find how many elements in that array are larger than that average. The function prototypes were provided so that cannot be changed. Also, we were instructed to initialize the array to size 10 and double the size whenever the number of read elements exceeds the current size, so that cannot be changed.
The problem I'm running into is returning a value from the aboveaverage function. It works properly within itself (I can put a printf to display count before return, but in the main function, the value being returned is 0. Is there anyone that can help with this please? It's getting frustrating.
Also, the commented printf line was to check the value being returned by the function. I commented it out instead of deleting it so I wouldn't have to retype it every time.
#include <stdio.h>
#include <stdlib.h>
double average(double *ptr, int size);
int aboveaverage(double *ptr, int size, double average);
int main(int argc, char* argv[])
{
double *ptr, avg, above, temp;
int size = 10, i, j;
void *tmp;
FILE *fp;
avg = above = 0;
if (argc != 2)
{
printf("Invalid number of arguments, 2 required\n");
return 1;
}
fp = fopen(argv[1], "r");
ptr = (double *)calloc(10, sizeof(double));
printf("Allocated 10 doubles\n");
for (i = 0;fscanf(fp, "%lf", &temp) != EOF; i++)
{
if (i >= size - 1)
{
size*=2;
tmp = realloc(ptr, size);
if (tmp == NULL)
{
printf("Error with realloc, exiting\n");
return 1;
}
printf("Reallocated to %d doubles\n", size);
}
ptr[i] = temp;
j = i;
}
size = j + 1;
avg = average(ptr, size);
above = aboveaverage(ptr, size, avg);
//printf("%d\n", above);
printf("%d elements are above average of %lf\n", above, avg);
free(ptr);
return 0;
}
double average(double *ptr, int size)
{
double sum;
int i;
while (i < size)
{
sum+=ptr[i];
i++;
}
return (sum / size);
}
int aboveaverage(double *ptr, int size, double avg)
{
int count=0, temp;
for (int i = 0; i < size; i++)
{
temp = (int)ptr[i];
if (temp > avg)
count++;
}
return count;
}
So other answers have already pointed out where the problem is and how exactly can it be fixed.
printf("%d elements are above average of %lf\n", above, avg);
You pass %d as the format string and then you pass a double.
This can be fixed by declaring above as int (since that is what your function returns too).
But I would like to add as to why it is wrong and why are you getting a zero.
So this is the issue with var args functions. Since the prototype says nothing about the types of the arguments, you call to printf assumes that the second argument is of type double.
Now the calling convention says that the second argument (if it is float or double) should be passed in the SSE register (on windows in the XMM1 register). But since the printf function sees that the format string is %d so it expects for the second argument to be int. Now int arguments are passed in the general purpose registers (on windows second is passed in rdx).
As a result it gets a garbage value.
I hope this helps you better understand the problem.
1 Important Mistake
You never use the value returned by realloc().
You need
ptr = tmp;
right after checking that realloc() did not return NULL.
The program above looks fine.
printf("%d elements are above average of %lf\n", above, avg);
Above line you are printing a double value with %d may be wrong. Otherwise I see everything fine.
Related
I am currently trying to take a sum from two different subroutine and pass it back to the main function, but every time I do this, it just comes up with a zero value and I am unsure why. I have tried putting my print statements in the main function and just doing calculations in the subroutines and that still didn't work, so I know that my variables aren't returning right and my sum is an actual number. How do I pass my variable sum back to my main function correctly?
Here is my code:
#include<stdio.h>
int X[2000];
int Y[2000];
int main()
{
FILE*fpdata1= NULL;
FILE*fpdata2 = NULL;
fpdata1=fopen("DataSet1.txt","r");
fpdata2=fopen("DataSet2.txt","r");
if(fpdata1==NULL || fpdata2 == NULL)
{
printf("file couldn't be found");
}
int i=0;
while(i<2000)
{
fscanf(fpdata1,"%d!",&X[i]);
fscanf(fpdata2,"%d!",&Y[i]);
// printf("This is X: %d\n",X[i]);
// printf("This is Y: %d\n",Y[i]);
i++;
}
fclose(fpdata1);
fclose(fpdata2);
avgX(X);
avgY(Y);
float sum;
float sumY;
float totalsum;
float totalavg;
totalsum= sum + sumY;
totalavg= totalsum/4000;
printf("Sum X: %f\n\n",sum);
printf("Total sum: %f\n\n",totalsum);
printf("The total average is: %0.3f\n\n",totalavg);
return 0;
}
int avgX(int X[])
{
int i=0;
float averageX;
float sum;
sum = 0;
while (i<2000)
{
sum += X[i];
i++;
}
averageX = sum/2000;
printf("Sum of X: %f\n\n",sum);
printf("The sum of Data Set 1 is: %0.3f\n\n",averageX);
return(sum);
}
int avgY(int Y[])
{
int i=0;
float averageY;
float sumY;
sumY = 0;
while (i<2000)
{
sumY += Y[i];
i++;
}
averageY = sumY/2000;
printf("Sum of Y: %f\n\n",sumY);
printf("The sum of Data Set 2 is: %0.3f\n\n",averageY);
return (sumY);
}
Firstly, it would appear you are expecting the lines
avgX(X);
avgY(Y);
to somehow update the sum and sumY variables in the main function. This is a fundamental misunderstanding of how memory is accessed.
Local variable declarations with the same identifier are not shared between functions. They can be accessed only from within the function in which they are declared (and only for the duration of the function call).
In this example, the apples variables in each of the functions have absolutely no correlation to one another. Expecting this program to print 15 is wrong. This program has undefined behavior because foo and bar read values from uninitialized variables.
void foo(void) {
int apples;
/* This is undefined behaviour,
* as apples was never initialized. Do not do this. */
apples += 5;
}
void bar(void) {
int apples;
/* This is undefined behaviour,
* as apples was never initialized. Do not do this. */
printf("%d\n", apples);
}
int main(void) {
int apples = 10;
foo();
bar();
return 0;
}
Instead of this, you'll want to utilize the arguments and return values of your functions. In this example, in main we pass the value of apples as an argument to foo, which adds 5 to this value and returns the result. We assign this return value, overwriting our previous value.
int foo(int val) {
return value + 5;
}
void bar(int val) {
printf("%d\n", val);
}
int main(void) {
int apples = 10;
apples = foo(apples);
bar(apples);
return 0;
}
Again note that the val parameters do not refer some "shared variable", they are local to both foo and bar individually.
As for the specifics of your program:
The functions avgX and avgY do the exact same thing, just with different identifiers.
It would be better to write a more generic summation function with an additional length parameter so that you are not hard-coding data sizes everywhere.
int sum_ints(int *values, size_t length) {
int result = 0;
for (size_t i = 0; i < length; i++)
result += values[i];
return result;
}
You can then easily write averaging logic utilizing this function.
You do check that your file pointers are not invalid, which is good, but you don't halt the program or otherwise remedy the issue.
It is potentially naive to assume a file will always contain exactly 2000 entries. You can use the return value of fscanf, which is the number of conversions that took place, to test if you've failed to read data. Its also used to signify errors.
Though the fact that global variables are zeroed-out saves you from potentially operating on unpopulated data (in the event the files contain less than 2000 entries), it would be best to avoid global variables when there is an alternative option.
It might be better to separate the reading of files to its own function, so that failures can be handled per-file, and reading limits can be untethered.
int main(void) or int main(int argc, char **argv) are the correct, valid signatures for main.
With all that said, here is a substantially refactored version of your code. Note that an implicit conversion takes place when we assign the integer return value of sum_ints to our floating point variables.
#include <stdio.h>
#include <stdlib.h>
#define DATA_SIZE 2000
int sum_ints(int *values, size_t length) {
int result = 0;
for (size_t i = 0; i < length; i++)
result += values[i];
return result;
}
size_t read_int_file(int *dest, size_t sz, const char *fname) {
FILE *file;
size_t i;
if ((file = fopen(fname, "r")) == NULL) {
fprintf(stderr, "Critical: Failed to open file: %s\n", fname);
exit(EXIT_FAILURE);
}
for (i = 0; i < sz; i++)
if (fscanf(file, "%d!", dest + i) != 1)
break;
fclose(file);
return i;
}
int main(void) {
int data_x[DATA_SIZE] = { 0 },
data_y[DATA_SIZE] = { 0 };
size_t data_x_len = read_int_file(data_x, DATA_SIZE, "DataSet1.txt");
size_t data_y_len = read_int_file(data_y, DATA_SIZE, "DataSet2.txt");
float sum_x = sum_ints(data_x, data_x_len),
sum_y = sum_ints(data_y, data_y_len);
float total_sum = sum_x + sum_y;
float total_average = total_sum / (data_x_len + data_y_len);
printf("Sums: [X = %.2f] [Y = %.2f] [Total = %.2f]\n"
"The total average is: %0.3f\n",
sum_x, sum_y, total_sum,
total_average);
}
Basically I have a function called MinSubTab that is supposed to calculate the sum of the array passed and also to change the value passed in the first argument from inside the function without using return. This is done with pointers. Anyway, I think it'd be easier if I just showed you the code so here it is:
maintab.c
#include <stdio.h>
#include <stdlib.h>
#include <unistd.h>
#include "tab.h"
int main(){
int *reftab;
int min;
reftab = (int *)malloc(sizeof(int) * NMAX);
InitTab(reftab,NMAX);
printf("\n Total: %d et min: %d", MinSumTab(&min, reftab, NMAX), min);
free(reftab);
return 0;
}
tab.c
void InitTab(int *tab, int size){
srand(time(NULL));
for (int i=0; i<size; i++){
*(tab+i) = rand() % 10;
}
}
int MinSumTab(int *min, int *tab, int size){
int total=0;
int minimum = NMAX;
int temp = *min;
for (int i=0; i<size; i++){
total += *(tab+i);
}
for (int i=0; i<size; i++){
if(*(tab+i)<minimum){
minimum = *(tab+i);
}
}
*min = minimum;
return total;
}
So the expected result here is that the sum is printed (which it is) and the minimum value of the array is printed (which it is not). Every single time the min variable equals 8 and I've no idea how to actually change the value of min from within that function.
Please help as my brain has no more capacity for rational thought, it's been 1.5 hrs and no solution in sight. Thanks
Looks like a small mistake:
You initialize minimum with NMAX, which I assume is 8 (the size of the array). 99.9% of the random numbers will be bigger. So 8 is chosen as the minimum.
What you really want is to initialize it with RAND_MAX – the maximum value rand() can return.
In C order of evaluation and argument passing is undefined.
You can of course the order yourself but it only to feed your curiosity.
#include <stdio.h>
volatile char *message[] = {
"fisrt", "second", "third", "fourth"
};
int print(size_t x)
{
printf("%s\n", message[x]);
return x;
}
int main()
{
printf("%d %d %d %d\n", print(0), print(1), print(2), print(3));
return 0;
}
Note. There is one exception from this rule.
Logical operators are evaluated form the left to the right.
if( x != NULL && *x == 5)is safe because x will not be dereferenced if it is NULL
I'm trying to create a function that returns as its result the sum of the elements in the array. When I try to run the program, I get a segmentation fault. Could someone please point me in the right direction? Thank you!
int arraySum (int array[], int numberOfElements) {
int result = 0;
for (int i = 0; i < numberOfElements; i++)
{
result += array[i];
}
return result;
}
int main (void) {
int numberOfElements;
int *array = NULL;
printf("How many elements would you like in your array: ");
scanf("%i", &numberOfElements);
printf("\nPlease list the values of the elements in the array: ");
for (int i = 0; i < numberOfElements; i++)
{
scanf("%i", &array[i]);
}
int result = arraySum(array, numberOfElements);
return result;
}
The problem you have is, that in C you need to manually allocate the memory if you are using a pointer instead of say a fixed-size array.
This is usually done by calling malloc, which will return a void-pointer (void*), which you need to cast to the desired type (in your case (int*)) before assigning it.
It is also important to note, that, when using malloc, you need to specify the amount of Bytes you want to allocate. This means that you can't just call it with the number of integers you want to store inside, but rather have to multiply that number with the amount of Bytes that one integer occupies (which depends on the Hardware and Operating System you use, hence you should use sizeof(int) for that purpose, which evaluates to that size at compile time).
I modified your code with a working example of how it could be done:
#include <stdio.h>
#include <stdlib.h>
int arraySum (int array[], int numberOfElements) {
int result = 0;
int i;
for (i = 0; i < numberOfElements; i++) {
result += array[i];
}
return result;
}
int main(int argc, char **argv) {
int numberOfElements;
int *array = NULL;
printf("How many elements would you like in your array: ");
scanf("%i", &numberOfElements);
array = (int*) malloc(numberOfElements * sizeof(int));
printf("\nPlease list the values of the elements in the array: ");
int i;
for (i = 0; i < numberOfElements; i++) {
scanf("%i", &array[i]);
}
int result = arraySum(array, numberOfElements);
printf("\n\nThe result is: %d\n", result);
return 0;
}
You are also trying to return the result in your main function, but the return value of main in C is used to signal whether your program terminated without errors (signalled by a return value of 0) or didn't encounter any issues (any value other than 0).
You need to allocate memory. It is not enough to just declare a pointer. You do it like this: array=malloc(numberOfElements*sizeof(*array));
Also, although it is possible to return result from the main function, you should not do that. The return value from main is usually used for error checking. Change the end of your program to
printf("Sum: %d\n", result);
return 0;
Returning 0 usually means that no error occurred.
I have the following code
void getPariceArray(Board board, treeNode *tn, Position *dst, int **prices, int *counter, int total)
{
if (tn == NULL)
return NULL;
if (tn->position[0] == dst[0][0] && tn->position[1] == dst[0][1])
{
prices = (int **)realloc(prices, sizeof(prices) *4);
prices[*counter] = (int *)malloc(sizeof(int));
printf("%d", sizeof(prices));
*prices[*counter] = total;
*counter = *counter + 1;
}
int x = tn->position[1] - '1';
int y = tn->position[0] - 'A';
int cellPrice = board[x][y] - '0';
total += cellPrice;
getPariceArray(board, tn->up, dst, prices, counter, total);
getPariceArray(board, tn->down, dst, prices, counter, total);
getPariceArray(board, tn->right, dst, prices, counter, total);
getPariceArray(board, tn->left, dst, prices, counter, total);
}
prices is array of pointers and every step in recursion I'm casting realloc to increase the prices size.
I got many error bugs and I had a feeling it related to allocation,
I printed the sizeof(prices) and I saw that it stayed 4 and not increase
Can someone please tell me where I went wrong?
thanks in advance
P.S
Edit
I have another function that princt the **prices
void printPricesArray(int **arr, int length)
{
for (int i = 0; i < length; i++)
{
printf("place:%d Price:%d\n", i, *arr[i]);
}
}
This is the error I'm getting when prices = realloc(prices, sizeof(prices) *4);
but when I'm changing the line to this prices = realloc(prices, sizeof(prices) * 150); everything goes well without errors because I know that in my example size isn't going passed 130, but I need dynamic increasing incase in different example size will be over 150.
I suppose that during code writing and correcting (compiler) errors the code evolved into a wrong direction.
I feel that you actually do not want to handle an array of pointers to integers but a (dynamically growing) array of integer values (not pointers to them). Yet the circumstance, that the function has to rewrite the pointer to the array, which led to introduce one more '*' in the interface, took you into the dilemma, and statement prices[*counter] = (int *)malloc(sizeof(int)) indicates to me that this is the basic misunderstanding.
Let me explain what I mean it on the following short example.
Suppose that we want to have a function dynamicPriceListAlloc, which allocates an array of integers for nrOfItems integers.
Let's start with the caller, i.e. function main: Therein, as we want to have a dynamically allocated integer array, we will hold a variable of type int *, i.e. a pointer to this array. As we want to have the array allocated in a function, we have to pass a pointer to this pointer, because otherwise the function could not assign the newly allocated memory address to this pointer. Hence, dynamicPriceListAlloc must take a pointer to a pointer to ints, i.e. int **.
But - now the misleading thing - the intent of dynamicPriceListAlloc is not to allocate a pointer with 10 pointers to ints, but to allocate an array of 10 integers and assigning this memory block to the pointer passed (by reference) as argument:
int main(){
int *priceList;
dynamicPriceListAlloc(&priceList, 10);
for (int i=0; i<10; i++)
printf("%d\n", priceList[i]);
}
void dynamicPriceListAlloc(int **prices, int nrOfItems) {
*prices = (int*)malloc(nrOfItems * sizeof(int));
for (int i=0; i<nrOfItems; i++)
// *prices[i] = i; // Wrong: takes prices[i] and then dereferences it
(*prices)[i] = i; // OK: derefernces prices (yielding a pointer an int-array) and then setting the i'th element
}
I suppose that you missed to correct the dereference-precedence thing in *prices[i] = i, and instead of correcting this to (*prices)[i] = i, you "solved" the problem by actually allocating storage for the pointer you dereference. And that's what I meant with "the code evolved in the wrong direction".
If I am right with this assumption, then your code would change as follows:
void getPariceArray(Board board, treeNode *tn, Position *dst, int **prices, int *counter, int total)
{
if (tn == NULL)
return;
if (tn->position[0] == dst[0][0] && tn->position[1] == dst[0][1])
{
size_t sizeOfPrices = (*counter) * sizeof(int);
*prices = (int*)realloc(*prices, sizeOfPrices);
printf("size of prices: %ld", sizeOfPrices);
(*prices)[*counter] = total;
*counter = *counter + 1;
}
int x = tn->position[1] - '1';
int y = tn->position[0] - 'A';
int cellPrice = board[x][y] - '0';
total += cellPrice;
getPariceArray(board, tn->up, dst, prices, counter, total);
getPariceArray(board, tn->down, dst, prices, counter, total);
getPariceArray(board, tn->right, dst, prices, counter, total);
getPariceArray(board, tn->left, dst, prices, counter, total);
}
And printPricesArray would be adapted as follows:
void printPricesArray(int *arr, int length)
{
for (int i = 0; i < length; i++)
{
printf("place:%d Price:%d\n", i, arr[i]);
}
}
I have the following code in C :
#include <stdio.h>
// Global variables :
int i;
int x[10];
int Nmax;
int sum;
// Functions used :
void Summation();
int Average(float avg); // This function will return avg
int main()
{
float avg;
printf("Mention how many numbers to be added\n");
scanf("%d",&Nmax);
printf("Enter %d numbers\n",Nmax);
for (i=0; i<Nmax; i++){
scanf("%d",&x[i]);
}
Summation();
Average(avg);
printf("%d %d %f\n",Nmax,sum,avg);
printf("Average = %.2f\n",avg);
return 0;
}
// Summation :
void Summation()
{
sum=0;
for (i=0; i<Nmax; i++) {
sum=sum+x[i];
}
printf("Sum of them = %d\n",sum);
}
// Average
int Average(float avg)
{
avg=(float)sum/(float)Nmax;
return avg;
}
Somehow the function Average is not returning the expected average value.
Instead it's showing a garbage value.
A typical input/output :
Mention how many numbers to be added
4
Enter 4 numbers
1 2 3 4
Sum of them = 10
4 10 1637156136366093893632.000000
Average = 1637156136366093893632.00
What's going wrong here? Hope I don't require a pointer here or do I?
For the average function you are passing the argument as pass by value. Once you call the function your are not assigning the return value back to the avg variable inside the main function. So what you are printing is the garbage value inside the avg variable declared in main function. Change your code to
avg = Average(avg);
Also this is a very bad way of writing c programs. Please dont you use global variables if you dont need them.
You are mixing int and float and that can cause problems.
You are never initializing avg in main(), use parameters instead of global variables to avoid the confusion. You pass avg's value to Average() it has absolutely no use in this case.
In c parameters to functions are always passed by value so the value of avg is not being modified in Average(), you may think it is because you seem confused about how you can modify global variables everywhere. The truth is global variables are mean, of course they have their uses for example, a global state in a library could be stored in a global variable1 but generally they are not needed.
Try like this
#include <stdio.h>
// Functions used :
float Summation(float *data, int size);
float Average(float *data, int size); // This function will return avg
int
main(void)
{
int size;
printf("Mention how many numbers to be added\n");
if (scanf("%d", &size) == 1)
{
float data[size];
float sum;
float average;
int i;
printf("Enter %d numbers\n", size);
for (i = 0 ; ((i < size) && (scanf("%f", &data[i]) == 1)) ; i++)
;
size = i;
sum = Summation(data, size);
average = Average(data, size);
printf("%d %f %f\n", size, sum, average);
printf("Average = %.2f\n", average);
}
return 0;
}
// Summation :
float
Summation(float *data, int size)
{
float sum;
sum = 0;
for (int i = 0 ; i < size ; i++)
sum = sum + data[i];
return sum;
}
// Average
float
Average(float *data, int size)
{
return Summation(data, size) / (float) size;
}
Note that you "don't really need an Average() function.", although it could be useful to make the API clean.
1Although I don't like that either, it makes the library very limited in multithreaded environments. Still sometimes it makes senes, but you can always have a structure with all the needed data and pass it in every call to the library API. So global variables are very rarely good.