Hey I'm trying to write a program to carry out newtons method and find the roots of the equation exp(-x)-(x^2)+3. It works in so far as finding the root, but I also want it to print out the root after each iteration but I can't get it to work, Could anyone point out my mistake I think its something to do with my indexing?
Thanks a million :)
#include <stdio.h>
#include <math.h>
#include <malloc.h>
//Define Functions:
double evalf(double x)
{
double answer=exp(-x)-(x*x)+3;
return(answer);
}
double evalfprime(double x)
{
double answer=-exp(-x)-2*x;
return(answer);
}
double *newton(double initialrt,double accuracy,double *data)
{
double root[102];
data=root;
int maxit = 0;
root[0] = initialrt;
for (int i=1;i<102;i++)
{
*(data+i)=*(data+i-1)-evalf(*(data+i-1))/evalfprime(*(data+i-1));
if(fabs(*(data+i)-*(data+i-1))<accuracy)
{
maxit=i;
break;
}
maxit=i;
}
if((maxit+1==102)&&(fabs(*(data+maxit)-*(data+maxit-1))>accuracy))
{
printf("\nMax iteration reached, method terminated");
}
else
{
printf("\nMethod successful");
printf("\nNumber of iterations: %d\nRoot Estimate: %lf\n",maxit+1,*(data+maxit));
}
return(data);
}
int main()
{
double root,accuracy;
double *data=(double*)malloc(sizeof(double)*102);
printf("NEWTONS METHOD PROGRAMME:\nEquation: f(x)=exp(-x)-x^2+3=0\nMax No iterations=100\n\nEnter initial root estimate\n>> ");
scanf("%lf",&root);
_flushall();
printf("\nEnter accuracy required:\n>>");
scanf("%lf",&accuracy);
*data= *newton(root,accuracy,data);
printf("Iteration Root Error\n ");
printf("%d %lf \n", 0,*(data));
for(int i=1;i<102;i++)
{
printf("%d %5.5lf %5.5lf\n", i,*(data+i),*(data+i)-*(data+i-1));
if(*(data+i*sizeof(double))-*(data+i*sizeof(double)-1)==0)
{
break;
}
}
getchar();
getchar();
free(data);
return(0);
}
No offenses, but your question is highly seductive to downvoting. Unrelated question title, ridiculous coding style (I mean tabulation).
Also within your newton function there's no actual need to store all the intermediate results, the Newton-Raphson should not use extra memory (i.e. it's O(1)).
Just add printf within your newton inside the iteration loop. Is this a problem?
In newton, you are returning the address of a local variable that doesn't exist anymore after the function returns. Accessing it afterwards is undefined behaviour.
In main you have
if(*(data+i*sizeof(double))-*(data+i*sizeof(double)-1)==0)
data is a double*, so data + i addresses the i-th double from the start. By multiplying the offset with sizeof(double), you access beyond the end of the array if i > number_of_elements/sizeof(double), yet more undefined behaviour.
And, thanks to JeremyP for finding it, in main you call newton
*data= *newton(root,accuracy,data);
which dereferences the pointer returned by newton (undefined behaviour, but at that point likely to do what you want) and stores that value in the first slot of the data allocated in main. Sot that probably gives you the initial element of the root array from newton, but doesn't change anything else in the memory block allocated to data in main.
void newton(double initialrt,double accuracy,double *data)
{
double root[102];
data=root;
// at this moment the values in the original argument data[]
// are no longer accessible to this function.
int maxit = 0;
root[0] = initialrt;
for (int i=1; i < 102; i++)
{
data[i] = data[i-1]
- evalf(data[i-1]) / evalfprime( data[i-1] );
if ( fabs(data[i] - data[i-1]) < accuracy )
{
maxit=i;
break;
}
maxit=i;
}
if ( maxit+1 == 102 && fabs(data[maxit] - data[maxit-1] ) > accuracy )
{
printf("\nMax iteration reached, method terminated");
}
else
{
printf("\nMethod successful");
printf("\nNumber of iterations: %d\nRoot Estimate: %lf\n",maxit+1
,data[maxit);
}
return;
}
(this is merely a stylistic comment, since the real issues have already been addressed)
pointer dereferencing and array indexing are equivalent in C. Your *(data+i) = ... is equivalent to data[i] = ...
the return value is useless, the function could return instead something usefull (eg accuracy)
return is not a function. No need to return(something); just return something; will do.
you return a pointer to the local array root, which is out of scope when the caller sees it.
whitespace makes a difference in reading experience
UPDATE: on second thought, I think in the inner loop the OP intended something like:
root[i] = root[i-1]
- evalf(data[i-1]) / evalfprime( data[i-1] );
if ( fabs(data[i] - data[i-1]) < accuracy )
{
maxit=i;
break;
}
maxit=i;
Related
I want to write a function where I have a given array and number N. The last occurrence of this number I want to return address. If said number cannot be found I want to use a NULL-pointer
Start of the code I've made:
int main(void) {
int n = 3;
int ary[6] = { 1,3,7,8,3,9 };
for (int i = 0; i <= 6; i++) {
if (ary[i] == 3) {
printf("%u\n", ary[i]);
}
}
return 0;
}
result in command prompt:
3
3
The biggest trouble I'm having is:
it prints all occurrences, but not the last occurrence as I want
I haven't used pointers much, so I don't understand how to use the NULL-pointer
I see many minor problems in your program:
If you want to make a function, make a function so your parameters and return types are explicit, instead of coding directly in the main.
C arrays, like in most languages, start the indexing at 0 so if there are N element the first has index 0, then the second has 1, etc... So the very last element (the Nth) has index N-1, so in your for loops, always have condition "i < size", not "i <= size" or ( "i <= size-1" if y'r a weirdo)
If you want to act only on the last occurence of something, don't act on every. Just save every new occurence to the same variable and then, when you're sure it was the last, act on it.
A final version of the function you describe would be:
int* lastOccurence(int n, int* arr, int size){
int* pos = NULL;
for(int i = 0; i < size; i++){
if(arr[i] == n){
pos = &arr[i]; //Should be equal to arr + i*sizeof(int)
}
}
return pos;
}
int main(void){
int n = 3;
int ary[6] = { 1,3,7,8,3,9 };
printf("%p\n", lastOccurence(3, ary, 6);
return 0;
}
Then I'll add that the NULL pointer is just 0, I mean there is literally the line "#define NULL 0" inside the runtime headers. It is just a convention that the memory address 0 doesn't exist and we use NULL instead of 0 for clarity, but it's exactly the same.
Bugs:
i <= 6 accesses the array out of bounds, change to i < 6.
printf("%u\n", ary[i]); prints the value, not the index.
You don't actually compare the value against n but against a hard-coded 3.
I think that you are looking for something like this:
#include <stdio.h>
int main(void)
{
int n = 3;
int ary[6] = { 1,3,7,8,3,9 };
int* last_index = NULL;
for (int i = 0; i < 6; i++) {
if (ary[i] == n) {
last_index = &ary[i];
}
}
if(last_index == NULL) {
printf("Number not found\n");
}
else {
printf("Last index: %d\n", (int)(last_index - ary));
}
return 0;
}
The pointer last_index points at the last found item, if any. By subtracting the array's base address last_index - ary we do pointer arithmetic and get the array item.
The cast to int is necessary to avoid a quirk where subtracting pointers in C actually gives the result in a large integer type called ptrdiff_t - beginners need not worry about that one, so just cast.
First of all, you will read from out of array range, since your array last element is 5, and you read up to 6, which can lead in segmentation faults. #Ludin is right saying that you should change
for (int i = 0; i <= 6; i++) // reads from 0 to 6 range! It is roughly equal to for (int i = 0; i == 6; i++)
to:
for (int i = 0; i < 6; i++) // reads from 0 to 5
The last occurrence of this number I want to return as address.
You are printing only value of 3, not address. To do so, you need to use & operator.
If said number cannot be found I want to use a NULL-pointer
I don't understand, where do you want to return nullpointer? Main function can't return nullpointer, it is contradictory to its definition. To do so, you need to place it in separate function, and then return NULL.
If you want to return last occurence, then I would iterate from the end of this array:
for (int i = 5; i > -1; i--) {
if (ary[i] == 3) {
printf("place in array: %u\n", i); // to print iterator
printf("place in memory: %p\n", &(ary[i])); // to print pointer
break; // if you want to print only last occurence in array and don't read ruther
}
else if (i == 0) {
printf("None occurences found");
}
}
If you want to return an address you need yo use a function instead of writing code in main
As you want to return the address of the last occurence, you should iterate the array from last element towards the first element instead of iterating from first towards last elements.
Below are 2 different implementations of such a function.
#include <stdio.h>
#include <assert.h>
int* f(int n, size_t sz, int a[])
{
assert(sz > 0 && a != NULL);
// Iterate the array from last element towards first element
int* p = a + sz;
do
{
--p;
if (*p == n) return p;
} while(p != a);
return NULL;
}
int* g(int n, size_t sz, int a[])
{
assert(sz > 0 && a != NULL);
// Iterate the array from last element towards first element
size_t i = sz;
do
{
--i;
if (a[i] == n) return &a[i];
} while (i > 0);
return NULL;
}
int main(void)
{
int n = 3;
int ary[] = { 1,3,7,8,3,9 };
size_t elements = sizeof ary / sizeof ary[0];
int* p;
p = g(n, elements, ary); // or p = f(n, elements, ary);
if (p != NULL)
{
printf("Found at address %p - value %d\n", (void*)p, *p);
}
else
{
printf("Not found. The function returned %p\n", (void*)p);
}
return 0;
}
Working on the specified requirements in your question (i.e. a function that searches for the number and returns the address of its last occurrence, or NULL), the code below gives one way of fulfilling those. The comments included are intended to be self-explanatory.
#include <stdio.h>
// Note that an array, passed as an argument, is converted to a pointer (to the
// first element). We can change this in our function, because that pointer is
// passed BY VALUE (i.e. it's a copy), so it won't change the original
int* FindLast(int* arr, size_t length, int find)
{
int* answer = NULL; // The result pointer: set to NULL to start off with
for (size_t i = 0; i < length; ++i) { // Note the use of < rather than <=
if (*arr == find) {
answer = arr; // Found, so set our pointer to the ADDRESS of this element
// Note that, if multiple occurrences exist, the LAST one will be the answer
}
++arr; // Move on to the next element's address
}
return answer;
}
int main(void)
{
int num = 3; // Number to find
int ary[6] = { 1,3,7,8,3,9 }; // array to search
size_t arrlen = sizeof(ary) / sizeof(ary[0]); // Classic way to get length of an array
int* result = FindLast(ary, arrlen, num); // Call the function!
if (result == NULL) { // No match was found ...
printf("No match was found in the array!\n");
}
else {
printf("The address of the last match found is %p.\n", (void*)result); // Show the address
printf("The element at that address is: %d\n", *result); // Just for a verification/check!
}
return 0;
}
Lots of answers so far. All very good answers, too, so I won't repeat the same commentary about array bounds, etc.
I will, however, take a different approach and state, "I want to use a NULL-pointer" is a silly prerequisite for this task serving only to muddle and complicate a very simple problem. "I want to use ..." is chopping off your nose to spite your face.
The KISS principle is to "Keep It Simple, St....!!" Those who will read/modify your code will appreciate your efforts far more than admiring you for making wrong decisions that makes their day worse.
Arrays are easy to conceive of in terms of indexing to reach each element. If you want to train in the use of pointers and NULL pointers, I suggest you explore "linked lists" and/or "binary trees". Those data structures are founded on the utility of pointers.
int main( void ) {
const int n = 3, ary[] = { 1, 3, 7, 8, 3, 9 };
size_t sz = sizeof ary/sizeof ary[0];
// search for the LAST match by starting at the end, not the beginning.
while( sz-- )
if( ary[ sz ] == n ) {
printf( "ary[ %sz ] = %d\n", sz, n );
return 0;
}
puts( "not found" );
return 1; // failed to find it.
}
Consider that the array to be searched is many megabytes. To find the LAST match, it makes sense to start at the tail, not the head of the array.
Simple...
So im currently trying to get my program to read a user input ( a double), and store said input in the heap using pointers in C. I allocate 40 bytes to the heap, and the program runs fine up until the program prompts me to enter an input to be stored, At which point after providing the first input, I get the segmentation fault. I know it may come as an out of bounds error, or an error with improper dereferencing, but I can't quite find where I did that. Any help would be greatly appreciated.
Edit:
It's become clear my question was a bit confusing, so some clarifications:
The goal of the program is to take an unspecified number of grades, starting with an initial heap size 40 bytes (project requirement), and whenever the heap is full, it is copied into a new one of size 80 bytes, with the old 40 bytes being freed. This continues until all grades have been entered.
Placing count as a parameter to defAlloc was a mistake, not quite sure why I put that there to begin with but that his since been removed.
The allocation aspect of this has been fixed and now works properly, im mainly having an issue with accessing elements within the heap and altering them ( grade Scanner Method)
Sorry for the messy code or confusing wordings, im new to both pointer usage and arithmetic as well as posting on stack overflow. Thank you for the responses.
an example of input and output:
Input:
81.0
43.0
25.0
73.5
Output:
Allocated 40 Bytes to the heap at 0x8d8010
stored 81 in the heap at 0x8d8010
This Repeats for each value until full heap or reaching a sentinel value.
I don't want to give away a whole bunch of information regarding input/output and the project as this is a school assignment (For academic dishonesty purposes) but essentially the issue im having is coming up in the gradeScanner method where im trying to read input and assign it to ptr, ptr+1, etc. Whatever it may be something is causing a segmentation fault
void defAllocator(double **grades);
void gradeScanner(int gradeCount, int allocCount, double *grades, double myGrade);
int main() {
int allocCount;
int gradeCount;
double myGrade;
double *grades;
printf("Enter a list of grades below where each grade is seperated by a newline Character");
printf("After the last grade is entered, enter a negative value to end the list");
defAllocator(&grades);
if(grades == NULL) {
printf("null");
}
else
printf("hello");
gradeScanner(gradeCount, allocCount, grades, myGrade);
}
void defAllocator(double **grades) {
double *arr = (double*)malloc(40);
if(arr != NULL) {
printf("Allocated 40 bytes at the heap at %p\n", grades);
}
else
printf("failed to allocate array");
*grades = arr;
}
void gradeScanner(int gradeCount, int allocCount, double *grades, double myGrade) {
int i =0;
while(i != 5){
if(scanf("%f", myGrade) > 0 && gradeCount == 0) {
*grades = myGrade;
gradeCount++;
printf("%p\n", grades);
printf("%p\n", gradeCount);
i++;
}
else if(scanf("%f", myGrade) < 0) {
i = 5;
}
else if(scanf("%f", myGrade) > 0 && gradeCount > 0) {
*(grades + gradeCount) = myGrade;
}
}
}
Lets get some simple bits going first. The allocation of the grades array
You have
void defAllocator();
then
double myGrade;
double *grades = &myGrade;
defAllocator(grades);
and finally
void defAllocator(double *grades, int count) {
grades = (double*)malloc(40);
printf("Allocated 40 bytes at the heap at %p\n", grades);
}
there is almost nothing correct about any of these lines.
the function declaration (first line) does not match the actual function
I think you expect the function to update the 'grades' pointer passed to it somehow. Setting 'grades' to point to a random double beforehand is not useful. Just init it to NULL if you want to be neat
you then call allocate with only one argument even though its supposed to take 2. Its clear you intended to work out how many you needed by asking the user and passing that in, but for some reason you gave up on that plan
the allocate function at the moment does not check that malloc worked
the allocate function discards the returned pointer. It places it in the grades argument but thats a local copy.
the allocator chooses 40 bytes , with no relationship to the size of what it it allocating
first - what should the allocation function look like. I would make it return the pointer to the allocated memory
double *defAllocator(int count) {
double *arr = (double*)malloc(sizeof(double)*count);
if(arr != NULL)
printf("Allocated 40 bytes at the heap at %p\n", arr);
else
printf("failed to alllocate array");
return arr;
}
Still keeping the hard coded max size. But make it a constant so that you can use it elsewhere , for example to check that not too many results have been entered.
So now we get
const int GRADE_ARRAY_SIZE = 40;
double *defAllocator(int count);
....
double *gradeArray = defAllocate(GRADE_ARRAY_SIZE);
If you want, as an exercise say, to pass the pointer in and have it updated by the allocater, then you need this (its an example of c-style 'pass by reference')
void defAllocator(double **gradeArrayPtr, int count) {
double *arr = (double*)malloc(sizeof(double)*count);
if(arr != NULL)
printf("Allocated 40 bytes at the heap at %p\n", arr);
else
printf("failed to alllocate array");
*gradeArrayPtr = arr;
}
now do
const int GRADE_ARRAY_SIZE = 40;
void defAllocator(double **gradeArrayPtr, int count);
....
double *gradeArray = NULL;
defAllocate(&gradeArray, GRADE_ARRAY_SIZE);
others have pointed out errors in the scanner code, but without the allocater working nothing else will work either
OK now the allocator is fixed lets look at the scanner code. We have
int allocCount;
int gradeCount;
double myGrade;
double *grades;
gradeScanner(gradeCount, allocCount, grades, myGrade);
and the actual function.
void gradeScanner(int gradeCount, int allocCount, double *grades, double myGrade) {
int i =0;
while(i != 5){
if(scanf("%f", myGrade) > 0 && gradeCount == 0) {
*grades = myGrade;
gradeCount++;
printf("%p\n", grades);
printf("%p\n", gradeCount);
i++;
}
else if(scanf("%f", myGrade) < 0) {
i = 5;
}
else if(scanf("%f", myGrade) > 0 && gradeCount > 0) {
*(grades + gradeCount) = myGrade;
}
}
}
Note, you code invokes multiple lots of Undefined Behavior so its hard to know exactly what is happening, I am guessing, But in fact tryi\ing to reason about UB is a big mistake.
Lets look at this piece
if(scanf("%f", myGrade) > 0 && gradeCount == 0)
gradeCount is not initialized so its almost certainly not 0 (UB)
scanf returns the number of things it scanned not the value it found. So here its either one (%f) or 0 if there was invalid input. I suspect you are seeing if a value > 0 was entered. Maybe not, but its not clear
you must pass a pointer to the value you want to read into, you are only passing in the value (myGrade) (UB - very strong likelyhood of dying here)
OK so thats always false (gradeCount != 0) so we move onto the next
else if(scanf("%f", myGrade) < 0) {
i = 5;
}
this reads the next value from input, its not looking again at the same input, not clear if that what you want.
scanf only returns 0,1 or EOF in the case. Maybe you are trying to detect EOF (that is usually -1)
you must pass a pointer to the value you want to read into, you are only passing in the value (myGrade) (UB, very string likely hood of death again)
Anyway this is false because of the test for < 0 that only happens at EOF
So now we get to
else if(scanf("%f", myGrade) > 0 && gradeCount > 0) {
*(grades + gradeCount) = myGrade;
}
this reads the next value from the input, did you mean that?
same errror with 'myGrade' instead of '&myGrade' (very bad UB)
but scanf might return 1 and gradeCount is almost certainly > 0 (50/50 chance given that its unitialized) .If this did test to true we do
*(grades + gradeCount) = myGrade;
more normally this is written
grades[gradeCount] = myGrade;
well gradeCount is uninitialized so this is very bad UB. Note that if this had worked myGrade will be unitialized too (also UB)
So
Initialize all you variables.
pass gradeCount in by reference so that it will get updated
read the manual page on scanf https://man7.org/linux/man-pages/man3/scanf.3.html
Plus
why the 5
do you intend to keep reareading when an input misses a test
I don't know why I keep on getting errors in my code when I'm trying to do pass-by-reference, for finding the largest number of an integer using recursion.
My code works when it's pass-by-value, but I fail to do it correctly in pass-by-reference.
My main:
#include <stdio.h>
#include <math.h>
void largest_digit(int* digit);
int main() {
int num;
printf("\nPlease enter a number ");
scanf("%d", &num);
largest_digit(&num);
printf("The largest digit = %d\n", num);
return 0;
}
My function:
void largest_digit(int* digit) {
int hold, hold1;
if(*digit == 0 || *digit < 0) {
*digit = 0;
*digit;
return;
}
// If-statement with Recursion.
if(*digit > 0){
hold = *digit % 10;
hold1 = largest_digit(*digit/10);
if(hold > hold1) {
hold = *digit;
*digit;
return;
} else {
hold1 = *digit;
*digit;
return;
}
}
}
As someone said before, the largest_digit function is void, so it can't be assinged to a variable when is called. What you can do instead, is modifying *digit before the call, and then assign the value of *digit to what you want, in this case hold1.
Other thing is that you need to save the value into *digit before returning, for example, instead of doing hold = *digit, you should do *digit = hold.
Here are the suggested modifications:
void largest_digit(int* digit) {
int hold, hold1;
if(*digit == 0 || *digit < 0) {
*digit = 0;
return;
}
// If-statement with Recursion.
if(*digit > 0){
hold = (*digit) % 10;
(*digit) /= 10;
largest_digit(digit);
hold1 = *digit;
if(hold > hold1) {
*digit = hold;
return;
} else {
*digit = hold1;
return;
}
}
}
With this main,
int main() {
int a=123, b=652, c=3274;
largest_digit(&a);
largest_digit(&b);
largest_digit(&c);
printf("%d\n",a);
printf("%d\n",b);
printf("%d\n",c);
return 0;
}
the output is
3
6
7
You said you were passing it by reference, but you just tried to pass it by value here
hold1 = largest_digit(*digit/10);
Create a new int with *digit/10 and pass the address to largest_digit
int hold1Temp = *digit/10;
hold1 = largest_digit(&hold1Temp);
EDIT: Your function should be something like this:
void largest_digit (int* digit)
{
if (*digit <= 0) return; // if there's no more digit to compare, stop
int currentDigit = *digit % 10; // if you receive 982, it gets the 2
int nextDigit = *digit/10; // if you receive 982, it turns into 98
largest_digit(&nextDigit); // does the same thing again
*digit = currentDigit > nextDigit ? currentDigit : nextDigit; // chooses the biggest digit
}
A couple of things first:
The unary indirection operator (*) used on a pointer means "look at what is this pointing to". Therefore, the statement *digit; alone is not useful to anything. You can very well remove it from your code (I see you use it multiple times), perhaps you meant to do an assignment? The statement *digit = X; is an assignment and modifies the data pointed by the pointer.
"Passing by reference" does not exist in C. You can only pass by value. That value though can be a pointer to another value, that is how you "simulate" passing something by reference.
A function declared as void f(...) does not return any value. Therefore, assigning the "return value" of such a function to a variable does not make sense.
Now, considered the above:
Your call largest_digit(*digit/10) is not passing a pointer, but dereferencing the pointer digit, dividing the value by 10, and then passing that as parameter. As you already figured, this is wrong. To correctly pass by reference in your case, you would need to either modify the original value pointed to by digit, or create a new one and pass its address.
In any case, passing a pointer around (instead of the value directly) for this kind of recursive function does not make much sense and is only a complicated twist that does not accomplish much other than making your life harder. Use a plain value as argument.
int largest_digit(int num) {
if (num < 0)
return largest_digit(-num);
if (num == 0)
return 0;
int cur = num % 10;
int next = largest_digit(num / 10);
if (cur > next)
return cur;
return next;
}
int main(void) {
printf("%d\n", largest_digit(1923)); // 9
printf("%d\n", largest_digit(4478)); // 8
printf("%d\n", largest_digit(-123)); // 3
}
NOTE: for simplicity, the above function also handles negative numbers by calling largest_digit(-num) if the number is negative, therefore it only supports negative digits down to INT_MIN+1 (that is, it does not correctly handle INT_MIN).
Your trouble is that other than the case where *digit is negative, you never actually set *digit. Each time you do this:
*digit;
The above only dereferences the pointer and looks up the value, but it doesn't actually change it. What you need to do on each of your return routes is to actually set the value to something:
*digit = ...something...;
Without setting this value anywhere, the value of num in your main() function is never actually going to change.
In addition, you are treating largest_digit as if it has a return value, which it does not:
hold1 = largest_digit(*digit/10); // <- assigning the return value does not make sense
I have a problem in C where I'm supposed to recursively read user input (integers), and print them back in the reverse order with the total number of integers that were read added to every number.
E.g. if I were to enter 1,1,2,1 the output should be 4,5,4,4
I have the recursion+reverse printing part done but the value of i in my code that is being added to each number is from the local scope. How do I do it such that it uses the last value of i without using static or global ints?
void reverse_and_add(int i) {
int n = read_int();
if (n != ERR_READ) {
i++;
reverse_and_add(i);
printf("%d\n", n + i);
}
}
Edit: I know this can be solved using static int i, but this problem is not supposed to use static ints
Have reverse_and_add() return the value of i after the processing is done:
int reverse_and_add(int i) {
int n = read_int();
if (n != ERR_READ) {
i = reverse_and_add(i+1);
printf("%d\n", n + i);
}
return i;
}
So while doing this assignment i encountered a problem where i tried to save some set of values(float) in an Array so that i can use them later on producing a graph, but the problem which i face here is that i read the values and i can print them but later which i checked the array the numbers which were stored there were not the same.
Im trying to save in in avg[].
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
float maximum(float array[])
{
float max=0;
for(int i=0;i<100;i++)
{
if (array[i]>max)
max=array[i];
}
return max;
}
float minimum(float array[])
{
float min=0;
for(int i=0;i<100;i++)
{
if (array[i]<min)
min=array[i];
}
return min;
}
char * read(char *filename)
{
FILE * sample;
sample = fopen(filename,"r"); //like file open in notepad ,which file? and what to do?
int count = 0;
static char singleline[100];
int cnt = 0;
int sum = 0;
int oldyear = -1;
float avg[82];
while(!feof(sample)) //read that until end.
{
count++;
fgets(singleline,150,sample);
if (count>21 && singleline[33]!='9')
{
char y[5], t[6];
for (int i = 14; i < 18; i++)
{
y[i - 14] = singleline[i];
}
y[4]='\0';
for (int i= 24;i <29;i++)
{
t[i-24]=singleline[i];
}
t[5]='\0';
int year = atoi(y);
int temp = atoi(t);
//printf("year : %i ,temp: %i\n",year, temp);
if (year == oldyear)
{
cnt++;
sum += temp;
}
else
{
int l=0;
l++;
avg[l] = 0.1 * sum / cnt;
if (cnt != 0)
{
printf("Fuer %i - %i Werte - Durchschnitt %.2f °C\n", oldyear, cnt, avg[l]);
cnt = 1;
sum = temp;
//save[l]=avg;
}
oldyear = year;
}
}
}
float last = 0.1 * sum / cnt;
printf("Fuer %i - %i Werte - Durchschnitt %.2f °C\n", oldyear, cnt-1, last);
fclose(sample);
//for(int i=0;i<)
for(int i=0;i<125;i++)
{
printf("%f\n",avg[i]);
}
printf("\nMax Temp= %f",maximum(avg));
printf("\nMax Temp= %f",minimum(avg));
return singleline;
}
int main()
{
char * file1 = "TG_STAID000476.txt";
read(file1);
//char * file2 = "TG_STAID000179.txt";
//read(file2);
return 0;
}
So yea, the problem was to read the year and the corresponding values and form an Average value for that particular year and then represent it in a graph.
I can do the first part where it takes the Average, but when i tried using it later,it had wrong values stored in it, you can see that where i tried to print all the values of avg[], can anyne please help me figure out how to correct the mistake, i want them to be saved as float.
The assignment datasheet is here. https://www.scribd.com/document/333844245/TG-STAID000179
I tried reading the values and used atoi to save them, and then used them to get the Average, i used Count>21 because the text before them are not required and when it reads a '9' on 34th column,it ignores since its not a valid data(in data sheet)
The variable l, intended to count the computed year temperature averages, is defined and initialized in the block where a year change is handled, thus always reset to zero. Correct this by moving the definition outside of the line read loop, perhaps even at global scope (see 2.).
The maximum() and minimum() functions operate on array elements 0 to 99, irrespective of the fact that the passed argument is defined as avg[82] and some elements at the end are not initialized. Correct this by using the actual number l of stored elements, either as a global scope variable or an additional function argument.
The singleline buffer is too short and thus overflows.
The while(!feof(sample)) loop cycles one extra time after the last line has been read, because EOF is not recognized before the next fgets(). Correct this by using the return value of fgets() to test EOF.
avg[l] = 0.1 * sum / cnt is evaluated even if cnt is zero. Correct this by moving this expression inside the if (cnt != 0) { … } block, also the l++, but behind the printf().
cnt = 1 is not executed if cnt is zero. This causes the very first data point to not be counted. Correct this by moving this expression behind the if (cnt != 0) { … } block.
The extra loop cycle (cf. 4.) may have led to use cnt-1 in the final printf("Fuer %i - %i Werte - Durchschnitt %.2f °C\n", oldyear, cnt-1, last);, but correct is just cnt.
The loop for(int i=0;i<125;i++) should also use the actual number l of stored elements, not 125.
To be noted is that the final year's average is (maybe intentionally) not stored in avg[].