I'm currently learning to program in C. In one of the tasks in my assignment, I have to make a histogram (drawn by basic console output, like this: http://img703.imageshack.us/img703/448/histogram.jpg) to measure the number of characters in a text file (standard for this assignment is 1.3 MB). I did make a function like this:
int *yAxisAverageMethod(int average, int max, int min)
{
int *yAxis;
int i=0;
for (i=0;i<20;i++)
{
*(yAxis+i)=0;
}
/*
int length=sizeof(data)/sizeof(int);
*/
int lower_half_interval=average/10;
int upper_half_interval=(max-average)/10;
int current_y_value=min;
for (i=0;i<11;i++)
{
if (i==10){
*(yAxis+10)=average;
break;
}
*(yAxis+i)=current_y_value;
current_y_value+=lower_half_interval;
}
current_y_value+=average+upper_half_interval;
printf("Current y value:%d\n",current_y_value);
printf("Current max value:%d\n",max);
for (i=11;i<20;i++)
{
*(yAxis+i)=current_y_value;
current_y_value+=upper_half_interval;
}
return yAxis;
}
In this function, I intend to return an array of 20 integers, in order to make a y axis. I find the average of all characters, then used 20 lines of the console to display it. The lower 10 lines are used to display the lower than average values of the total amount of characters, and 10 lines are used to display the upper part. Each step in the y axis of the lower half is calculated by (average - min)/10, and each step in the y axis of the upper part is calculated by (max - average)/10. This is my method to draw the histogram, because I want to display the variants between values.
In the main method, I have this function call:
int *yAxis;
yAxis=yAxisAverageMethod(average,max,min);
I got a segmentation fault when I ran the function. In netbean GCC++ compiler, it works fine. Howerver, when I ran it on the university machines (which I have to compile it on command line and edit in Vi), I got the error. I guess it is because Netbean has its own memory manager? I don't understand.
Edited: I will ask about merge sort in anothe question.
*yAxis is a wild pointer. You never allocate memory for the int array you want to use.
int *yAxis = malloc(sizeof(int) * 20);
You are returning a pointer to nothing.
Where inside the function do you tell the computer to reserve some memory for *yAxis?
yAxis is a point, and you did not initialize it. it will point to unknown space what depends on the compiler. you should apply some memory for it firstly.
yAxis = malloc(sizeof(int)*20);
Don't forget to free() it in the caller.
Related
I want to get a variable from user and set it for my array size. But in C I cannot use variable for array size. Also I cannot use pointers and * signs for my project because i'm learning C and my teacher said it's forbidden.
Can someone tell me a way to take array size from user?
At last, I want to do this two projects:
1- Take n from user and get int numbers from user then reverse print entries.
2- Take n from user and get float numbers from user and calculate average.
The lone way is using array with variable size.
<3
EDIT (ANSWER THIS):
Let me tell full of story.
First Question of my teacher is:
Get entries (int) from user until user entered '-1', then type entry numbers from last to first. ( Teacher asked me to solve this project with recursive functions and with NO any array )
Second Question is:
Get n entries (float) from user and calculate their average. ( For this I must use arrays and functions or simple codes with NO any pointer )
Modern C has variable size arrays, as follows:
void example(int size)
{
int myArray[size];
//...
}
The size shouldn't be too large because the aray is allocated on the stack. If it is too large, the stack will overflow. Also, this aray only exists in the function (here: funtion example) and you cannot return it to a caller.
I think your task is to come up with a solution that does not use arrays.
For task 2 that is pretty simple. Just accumulate the input and divide by the number of inputs before printing. Like:
#include <stdio.h>
#include <stdlib.h>
int main()
{
float result = 0;
float f;
int n = 0;
printf("How many numbers?\n");
if (scanf("%d", &n) != 1) exit(1);
for (int i=0; i < n; ++i)
{
if (scanf("%f", &f) != 1) exit(1);
result += f;
}
result /= n;
printf("average is %f\n", result);
return 0;
}
The first task is a bit more complicated but can be solved using recursion. Here is an algorithm in pseudo code.
void foo(int n) // where n is the number of inputs remaining
{
if (n == 0) return; // no input remaining so just return
int input = getInput; // get next user input
foo(n - 1); // call recursive
print input; // print the input received above
}
and call it like
foo(5); // To get 5 inputs and print them in reverse order
I'll leave for OP to turn this pseudo code into real code.
You can actually use variable sized arrays. They are allowed when compiling with -std=c99
Otherwise, you can over-allocate the array with an arbitrary size (like an upper bound of your actual size) then use it the actual n provided by the user.
I don't know if this helps you, if not please provide more info and possibly what you have already achieved.
I'm trying to write a function that when given an array and a value, it checks if the value is in that array. If it is there then keep finding a new unique random value before adding it to the array. This is what I have done so far but I think the problem is my lack of understanding of pointers. Here is what I have so far:
#include <stdio.h>
#include <stdlib.h>
int getNewIndex(int index, int *visitedPixels, int *visitedPixelsIndex);
int main() {
int *visitedPixels = malloc(2 * sizeof(int));
int *visitedPixelsIndex = 0;
srand(1);
int randIndex = rand() % 16, i;
printf("Initial randIndex = %d\n", randIndex);
for(i = 0; i < 16; i++) {
randIndex = getNewIndex(randIndex, visitedPixels, visitedPixelsIndex);
printf("randIndex[%d] = %d\n", i, visitedPixels[i]);
}
return 0;
}
int getNewIndex(int index, int *visitedPixels, int *visitedPixelsIndex) {
int i = 0;
while (i < *visitedPixelsIndex) {
(index == visitedPixels[i]) ? index = rand() % 16, i = 0 : i++;
}
visitedPixels[*visitedPixelsIndex] = index;
(*visitedPixelsIndex)++;
//(*visitedPixels) = realloc(visitedPixels, (*visitedPixelsIndex+1) * sizeof(int));
return index;
}
Any help would be appreciated.
Okay, so. I'm going to try to explain with a metaphor. Hopefully it helps rather than confusing more.
Imagine memory is a long board you can write numbers on. It takes an inch of board to write a small number. Bigger numbers can be represented by writing across more slots.
An array, in our metaphor, is just a contiguous length of board you can write stuff into. If you want an array of 5 integers, and each integer takes 4 inches, you'll need 20 inches of board for it. If you wanted to pass all these integers to a function, instead of copying them all across, you would instead write down how many inches from the end of the board your array is. That's what a pointer is. It's a number telling where something is.
When you called malloc( 2 * sizeof( int ) ), you requested for a segment of the board big enough for two integers, and you received how many inches from the end of the board that new segment is. So we've got 8 inches of board X inches from the end, with X being our pointer.
Incrementing a pointer says "increase this value to point at the next element of the underlying array". A int* will increase by 4, a pointer to a structure by the size of the structure plus any alignment offset the compiler has decided for it.
It does not increase the amount of storage.
If I have a pointer to two 8 inches of board, write a 4 inch number, increment the pointer to point 4 inches more in, write another 4 inch number and increment again, my pointer is now right after the last element of the array. If I write here, all bets are off. What was on the board after the array? Who knows. It could be anything. Maybe it was a different array. Maybe it was information for keeping track of what parts of the board have been handed out to the program. Maybe it was the end of my board and I'll write off the end. Writing to memory you haven't received permission to from the operating system is where signals for "segment violations", SIGSEGV, program failures come from.
You need to request more space up front, or bigger arrays as you need them. There's also a realloc that will do this too. And for all of them, you have to check if the call failed and terminate or otherwise recover appropriately.
Hopefully this is more helpful than confusing. Good luck :)
I am following the following function to calculate factorials of big numbers link, and I would like to understand a bit more why some things are happening...
#include<stdio.h>
#define MAX 10000
void factorialof(int);
void multiply(int);
int length = 0;
int fact[MAX];
int main(){
int num;
int i;
printf("Enter any integer number : ");
scanf("%d",&num);
fact[0]=1;
factorialof(num);
printf("Factorial is : ");
for(i=length;i>=0;i--){
printf("%d",fact[i]);
}
return 0;
}
void factorialof(int num){
int i;
for(i=2;i<=num;i++){
multiply(i);
}
}
void multiply(int num){
long i,r=0;
int arr[MAX];
for(i=0;i<=length;i++){
arr[i]=fact[i];
}
for(i=0;i<=length;i++){
fact[i] = (arr[i]*num + r)%10;
r = (arr[i]*num + r)/10;
//printf("%d ",r);
}
if(r!=0){
while(r!=0){
fact[i]=r%10;
r= r/10;
i++;
}
}
length = i-1;
}
My questions are:
What is the real meaning of the MAX constant? What does it mean if it's bigger or smaller?
I have found out that if I have a MAX = 10000 (as in the example), I can calculate up to 3250! If I try with 3251! I get a 'Abort trap: 6' message. Why is that number? Where does it come from?
Which would be the difference if I compile this code for a 32-bit machine with the flag -m32? Would it run he same as in 64-bit?
Thanks!
As Scott Hunter points out, MAX is the maximum number of elements in the fact and arr arrays, which means it's the maximum number of digits that can occur in the result before the program runs out of space.
Note that the code only uses MAX in its array declarations. Nowhere does it use MAX to determine whether or not it's trying to read from or write to memory beyond the end of those arrays. This is a Bad Thing™. Your "Abort trap: 6" error is almost certainly occurring because trying to compute 3251! is doing exactly that: using a too-large index with arr and fact.
To see the number of digits required for a given factorial, you can increase MAX (say, to 20,000) and replace the existing printf calls in main with something like this:
printf("Factorial requires %d digits.\n", length + 1);
Note that I use length + 1 because length isn't the number of digits by itself: rather, it's the index of the array position in fact that contains the most-significant digit of the result. If I try to compute 3251!, the output is:
Factorial requires 10008 digits.
This is eight digits more than you have available in fact with the default MAX value of 10,000. Once the program logic goes beyond the allocated space in the array, its behavior is undefined. You happen to be seeing the error "Abort trap: 6."
Interestingly, here's the output when I try to compute 3250!:
Factorial requires 10005 digits.
That's still too many for the program to behave reliably when MAX is set to 10,000, so the fact that your program calculates 3250! successfully might be surprising, but that's the nature of undefined behavior: maybe your program will produce the correct result, maybe it will crash, maybe it will become self-aware and launch its missiles against the targets in Russia (because it knows that the Russian counterattack will eliminate its enemies over here). Coding like this is not a good idea. If your program requires more space than it has available in order to complete the calculation, it should stop and display an appropriate error message rather than trying to continue what it's doing.
MAX is the number of elements in fact and arr; trying to access an element with an index >= MAX would be bad.
Error messages are often specific to the environment you are using, which you have provided no details for.
They are not the same, but the differences (for example, the size of pointers) should not affect this code in any discernible way.
the average is not correct for this code. How to solve the average with this code. I try all of things but every time its same. It shows last number average only.
#include<stdio.h>
void compute(int anumber,int *max,int *min,float *average,int count);
int main ()
{
int max=0,min=100;
float average=0;
int number,i=0;
printf("\nenter a number:");
scanf("%d",&number);
while(number>0){
i++;
compute(number,&max,&min,&average,i);
printf("\nenter a number:");
scanf("%d",&number);
}
printf("\naverage %.2f",average);
printf("\ncount %d",i);
printf("\nmin %d",min);
printf("\nmax %d",max);
return 0;
}
void compute(int anumber,int *max,int *min,float *average,int count)
{
float total;
total=total+anumber;
*average=total/count;
++count;
if(anumber>*max)
*max=anumber;
else if(anumber<*min)
*min=anumber;
}
Issue #1: Total and number are uninitialized.
In C no initialization of variables is done for you. What is the value of total after:
float total;
The answer: Whatever was in memory at the location it was allocated. It could 0, 20, 94, 15, 7, or -2.3 billion, unless you give it a value it has an arbitrary one. It's value is indeterminate.
total=total+anumber;
By adding anumber to an unknown number you have no idea what total will become.
Issue #2: You don't calculate total.
The total is calculated by taking all the numbers in a set and summing them.
I.E. With the numbers 2,4,6 the total is 2 + 4 + 6 which equals 12. The first thing you should note is the presence of repetition. The addition is a common aspect that can be abstracted. We normally abstract repetition into a loop i.e.
int i;
float total = 0;
for(i = 0; i <= 6; i+=2)
{
total += i;
}
You need a similar loop in your program.
Your compute function is void, it cannot return a value. There are a handful of ways to fix total so that you may calculate the average.
Define total in the global scope for example, this is done by moving it outside of any function body. You'll have to remove the definition of total from within your function, as the variable in the closest outer scope will be used.
Make total static, it will not be automatically disposed of between each function call. This allows you to pass in values and allow the total to remain.
Regardless of your choice you'll have to make some changes, as of now you are not actually calculating the average. Further details on the assignment or task you were given would benefit everyone. C has few keywords but many ways of using them, in order to fully answer your question we must know:
What is the program supposed to do? Anticipated input/output helps a lot. In order to come up with a solution you must first fully understand the problem. It can be a challenge to extract intended functionality even from well written and working code, it can be near impossible to do so with broken code.
Were you given specifications? Do you understand them? I see from your comment that you are not allowed to change function headers/prototypes, what other restrictions do you have?
One final note. I'm assuming this is a homework assignment, as someone who has taken many classes based around C programming and who has taught some myself I can guarantee you - You will get the most out of the exercise by receiving only the help that is necessary, strive to think about the problem as much as you can on your own as well.
Your variable "total" is local to the compute() function, so it does not contain the total of all the input numbers - it is as new variable each time compute() is called, which is every time through the loop.
If you want to process each number one at a time, you can find the total within the compute function, if you make total a global variable. Then the correct approach would be find the average once, by dividing that total by the number of values.
I have been attempting to wrap my head around an idea that I am certain is possible, I just am not sure if I am going about it in the right way. My intention is to create an array and then fill it with as many values as the user wants. However my goal is to not use any defined value per se. I would like to be able to continue increasing it the amount of values it can contain indefinitely.
This is the test code I have been using to try and figure this out:
#include <stdio.h>
#include <stdlib.h>
int main(void)
{
int i;
int Up;
int Ary[0];
printf("Please enter the number of integers you want to input: ");
scanf("%d", &Up);
for(i = 0; i < Up; i++)
{
printf("Please enter a number: ");
Ary[i] = (int) malloc(sizeof(int));
scanf("%d", &Ary[i]);
}
for(i = 0; i < Up; i++)
{
printf("%d ", Ary[i]);
if(i % 10 == 0)
{
printf("\n");
}
}
return 0;
}
This may be a poor way of attempting to figure this out and I may also be doing this is a completely wrong way; However I get a segmentation fault sometimes. If I use small values such as only entering 4 or 5 values it works fine, however if I enter 10 values it gives me a segmentation fault. If I enter 50 values, it lets me enter all 50 but gives me a segmentation fault after printing out the 41st value.
The code itself is simply a means to an end. Ultimately what I would like to know is how I can set up an array of anything that can have values added to it indefinitely while retaining previous values using dynamic memory allocation?
PS. I hope this defines my question well enough, however if it does not I would like to refine my question so it is more clear. Please make a comment if this is unclear and why.
This isn't going to work:
int Ary[0];
You've made an array with no elements; the only valid use of such an array is to take its address, but you can't index into it as you have done.
Instead, you should make a pointer to what will later be allocated as an array:
int *Ary;
Then when you know how many integers you want:
Ary = malloc(Up * sizeof(int));
Now you can do Ary[index] for any index from 0 to (Up-1). If you later want to enlarge the array, you can use realloc() (many tutorials online for that).
You need to use dynamic allocation, what you are doing right now is static allocation, you need to learn how to use malloc and free.
So keep in mind that what you want to do is not "efficient" but can definitely be done as a learning exercise to learn how to make such a container.
What you need to do is allocate the amount of memory needed to contain the amount of values currently in your array +1 more value every time you want to "add" a new value to your array, for example: malloc(sizeof(int)*(<current_number_of_values>+1)).
I say "add" in quotes because what you will have to do is actually allocate memory for a brand new array every time and copy over your old values plus the new value the user enters and then free your old array to avoid memory leaks.
There are STL containers that do this internally but much more efficiently but I assume you are doing this to learn and not use your own containers for anything serious.