I am having some trouble with pointers.
The gist of it is, I am trying to define pointers in one function and call that function in my main to use those pointers.
The exact instructions for my assignment are as follows:
Write two functions, one that reads three numbers from the keyboard
and one that prints some information about these three numbers.
Input Function
Write a function that has three integer pointer parameters, and that
asks the user to enter three whole numbers. The values entered at the
keyboard should be read into the addresses stored in the pointer
parameters.
Note: recall that scanf requires the address of a variable and that
pointers store addresses.
Printing Values
Write a second function called a2question2, with no return value and
no parameters. The function should declare three integer variables
and then use your input function to read values into these variables.
The function should then print the sum, the average, the product, and
the smallest and largest of these numbers.
Here is what I have so far:
int pntloc (int *x, int *y, int *z){
int a = 0;
int b = 0;
int c = 0;
printf("Please enter integer #1: ");
scanf ("%d", & a);
printf ("Please enter integer #2: ");
scanf ("%d", & b);
printf("Please enter integer #3: ");
scanf ("%d", & c);
*x = &a;
*y = &b;
*z = &c;
return *x, *y, *z;
}
// Fourth function
main (){
int x, y, z;
pntloc(x, y, z);
int sum = 0;
int average = 0;
int product = 0;
int smallest = 0;
int largest = 0;
printf ("%d", x);
}
However, after the program asks me for the three integers, it crashes without doing anything.
The first function works fine by its self (tested it by making it the main function without parameters and printed the pointer values) ie:
printf ("%d", *x);
So I guess the values are just not passing from one function to the next. I've tried various ways of writing the first and second function but nothing seems to work.
The best I got was getting the program not to crash but the printed value was nowhere to what I inputted before.
Any ideas how to do this?
Your program is probably crashing because of two errors:
1) You are returning the local address of the variables a, b and c:
*x = &a; // This line says follow the 'x' pointer, and set the value there to
// the address of 'a'
Since a is defined locally (i.e. inside the function), that address is invalid once the function returns.
What you probably meant is:
*x = a; // Follow the 'x' pointer, and set the value there to the value of 'a'
2) You're not passing pointers to pntloc() (your compiler should be warning you about this one)
int x, y, z;
pntloc(x, y, z); // The passes the VALUES of x, y and z
You probably meant:
pntloc(&x, &y, &z); // Pass the ADDRESSES of x, y and z
Some other improvements that aren't causing your crash:
You can massively shorten pntloc() by not using the local variables:
void pntloc (int *x, int *y, int *z){
printf("Please enter integer #1: ");
scanf ("%d", x);
printf ("Please enter integer #2: ");
scanf ("%d", y);
printf("Please enter integer #3: ");
scanf ("%d", z);
}
Note that the & has been removed inside the scanf() call. You asked about it in comments, so here's a bit more explanation: &x says "the address of x", but when you have a pointer, you already have an address. A quick example:
int a; // 'a' is an integer variable
int *b = &a; // 'b' is a pointer to the integer variable 'a'
scanf("%d",&a); // This statement reads an integer into 'a'.
// We pass it the address of 'a', which is written &a
scanf("%d",b); // This statement also reads an integer into 'a'.
// We pass it the address of 'a', which is stored
// in the pointer 'b'.
Since we have pointers passed in to the function:
void pntloc (int *x, int *y, int *z){ // Three pointers to ints
we can pass them straight in to scanf(), and don't need to (and shouldn't) use & when we do.
Note that I also removed the return statement:
return *x, *y, *z;
I don't think this return statement is doing what you think it is. Remember that C only allows one return value from a function.
But why does it compile, you ask? Well, here's what's happening - but feel free to ignore this bit if it is confusing: The comma operator evaluates left to right, discarding the left hand result as it goes. So, your return statement is equivalent to:
*x;
*y;
return *z;
The comma operator is useful when the left hand statement has a side effect, and you want to write everything on one line. In my opinion, it makes code much harder to read, but there are one or two situations where it makes things cleaner. For a beginner, I recommend the following rule: Only use commas inside the round brackets of functions.
Since you weren't using the return value from the function when you called it:
pntloc(&x,&y,&z);
I removed the return entirely, and set the return type to void.
*x = &a;
*y = &b;
*z = &c;
Will cause mayhem and death! a b and c are local variables, so you are setting the contents of x y and z to addresses that will be invalid once you return from the function where a b and c are defined.
Perhaps you mean:
*x = a;
*y = b;
*z = c;
in main(),
pntloc(&x, &y, &z);
and
*x = a;
...
printf ("%d", x);
while you pass the *x as a parameter in pntloc(), you can't change *x 's value after calling the function.
and pntloc() don't need to return them, returning 0 or 1 is enough.
Related
I've tried to use the for loop for calculating x to power y. The program is running but giving errors.
To my knowledge, the error must be in "z" statements but I cannot figure it out.
Help me if you encounter my mistakes.
#include<stdio.h>
#include<conio.h>
void main()
{
int x,y,i;
long int z=x;
printf("Enter the values of x and y: ");
scanf("%d %d",&x,&y);
for(i=2;i<=y;i++)
z*=x; ```
/*e.g- Let x=2, y=3, then as per intialization z=x=2
since,from the for condition, (i=2)<=3, which is true
z= z*x =>2*2 => 4 now z=4
now i++ => i=3
(i=3)<=3,which is true
z= z*x =>4*2 => 8
therefore, 2 to power 3 is 8 */
printf("%d to power %d is %ld",x,y,z);
getch();
}
You are assigning z to x before x is assigned a value. z then has an indeterminate value, which messes up calculation of the power.
You have to wait until x is assigned from user input before using its value to initialize z.
Also, when reading input from scanf, it's a best practice to check its return value to ensure that all intended values were read successfully:
if(scanf("%d %d", &x, &y) != 2)
{
// x and y were not properly read - handle error
}
z = x;
EDIT: #chux - Reinstate Monica pointed out in the comments that if y == 0 the code still has a problem. Anything to the power of zero (except zero itself, since xy is not continuous at the origin) is 1. You have to handle that special case as well.
You are initializing your z variable (to be equal to x) before you have assigned a value to x! To fix this, move the declaration/initialization of z to after your scanf call:
//..
int x,y,i;
// long int z=x; // Means nothing: as "x" is here undefined, so "z" will also be!
printf("Enter the values of x and y: ");
scanf("%d %d",&x,&y);
long int z = x; // Here, we have (probably) a value for "x" so we can copy it to "z"
//..
EDIT: Maybe I'm drifting a bit 'off-topic' here, but you may have a background in programming languages that use reference variables (C++ or C#)? In such languages, what you are trying to do may work! For example, in C++, you could have int& z = x; (where you have your current declaration), and that could work in some circumstances (although, in your code, it actually won't, as pointed out in the comments). However, in "plain old C," code is executed where you put it, and there's no such thing as a "reference variable."
First you might want to initialize those variables
long int x = 0, y = 0;
long int z = 0;
Here you should check if scanf was successful
printf("Enter the values of x and y: ");
scanf("%ld %ld",&x,&y);
About scanf return value. From cppreference
Return value 1-3) Number of receiving arguments successfully assigned
(which may be zero in case a matching failure occurred before the
first receiving argument was assigned), or EOF if input failure occurs
before the first receiving argument was assigned. 4-6) Same as (1-3),
except that EOF is also returned if there is a runtime constraint
violation.
Now the problem is you're assigning z the value of x before either is initialized properly. So that is an undefined behavior.
This is what you want
long int x = 0, y = 0;
long int z = 0;
printf("Enter the values of x and y: ");
scanf("%ld %ld",&x,&y);
z = x;
Also you can define a new int variable inside the loop. I personally find this method better.
for(int i = 2; i <= y; i++)
z *= x;
For the print statement, you might want to use %ld format for long int
printf("%ld to power %ld is %ld",x,y,z);
The objective here is to print the student's average grade as a letter (A for Aprooved, R for Reprooved, or F for Miss, or Falta, in Portuguese), with the average grade value itself, and the student's total presence in classes, using pointers to avg and misses. But after compilation, only the char return value is printed, with 0 on the others.
I tried to print the stored values in the pointers *avg and *presence, but the program takes the student grade values and present values before crashing.
#include <stdio.h>
char situation(float n1,float n2,float n3,int misses, int classes, float
*avg, float *presence);
int main()
{
float *avg, *presence, vet[3];
int f, a, x;
printf("Write the value of your notes \n");
for(x=0;x<=2;x++)
{
printf("Note %d:",x+1);
scanf("%f",&vet[x]);
}
printf("Misses: ");
scanf("%d",&f);
printf("Given: ");
scanf("%d",&a);
char outcome=situation(vet[0], vet[1], vet[2], f, a, &avg, &presence);
printf("With an average of %f and presence of %f percent, your situation is %c",avg,presence,outcome);
return 0;
}
char situation(float n1,float n2,float n3,int misses, int classes, float
*avg, float *presence)
{
char result;
*presence=((classes-misses)/classes)*100;
*avg=(n1+n2+n3)/3;
if(*presence>=0 && *presence<75)
{
result='F';
}
if(*presence>=75 && *presence <=100)
{
if(*avg>=0 && *avg<6);
{
result='R';
}
if(*avg>=6 && *avg<=10)
{
result='A';
}
if(*avg<0 || *avg>10)
{
result='x';
}
}
if(*presence<0 || *presence>100)
{
result='x';
}
return result;
}
I expected the student's total presence and the average grade as a value and letter (A, R, or F), printed on the terminal to the user, but it only returned the char result value.
Your code has one main problem:
float *avg,*presence,
When you a calling
char outcome=situation(vet[0],vet[1],vet[2],f,a,&avg,&presence);
You are passing the address to the pointer you just declared. By changing the value in the function outcome, you are changing the address that avg and presence are pointing to, not the value of the variable.
Try changing to
float avg,presence
This way, when you change the value (using the * operator) you will change the actual variable value.
You may find this that presence still be showing as 0 on the printf. This is because how C works with types in arithmetics operations. Your division has only ints on it, so the result will be a int. Given the result will always be >= 1, the result will be rounded to the int value, which is 0.
To fix that just put a float value in the division and the result will be a float.
Something like:
*presence=((classes-misses)/(classes*1.0))*100;
avg is a float pointer, you are sending it by pointer (&avg) so your function needs to be (int n1,....,float **avg,...)
Try to send avg without the &.
Give him a value before (it is better)
The compiler warning pointed you directly to the problem. You should examine the warning and come to understand what it means and why it was issued.
Your error is here:
float *avg,*presence
These should be declared as float, not float *.
#include <stdio.h>
void print_binary(int n);
void test();
int main(){
test();
return 0;
}
void print_binary (int n){
unsigned int mask = 0;
mask = ~mask^(~mask >> 1);
for (; mask != 0; mask >>= 1){
putchar ((n & mask) ? '1' : '0');
}
}
void test(){
int x;
float *p;
p = (float *) &x;
printf ("x init value :%d\n", x);
printf ("addr x and p are %p %p\n", &x, p);
printf ("print x in bit ");
print_binary(x);
printf ("\n");//00000000000000000000000000000000
*p = 6.35;
printf ("print x in bit ");
print_binary(x);
printf ("\n");//01000000110010110011001100110011
printf ("x after 6.35 value :%d\n", x);//1087058739
printf ("call1 x:%.100f\n", x);//0.0000000.....
printf ("x:%d\n", x);//1087058739
printf ("call2 x:%f\n", x);//0.000000
printf ("p:%f\n", *p);//6.350000
printf ("call3 x:%f\n", x);//6.350000
}
Results:
x init value :0
addr x and p are 0x7ffc37d5ba8c 0x7ffc37d5ba8c
print x in bit 00000000000000000000000000000000
print x in bit 01000000110010110011001100110011
x after 6.35 value :1087058739
call1 x:0.0000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000000
x:1087058739
call2 x:0.000000
p:6.350000
call3 x:6.350000
I print my x after *p = 6.35;, and
in the memory, we get 01000000110010110011001100110011, this is the right number according to the IEEE754,
could someone explain why my first printf ("call1 x:%.100f\n", x) print me 0.00...,
but after I printf ("p:%f\n", *p), it can print the 6.35 ?
Dereferencing p is undefined behavior, since p is not pointing to a float, but to an int (ref. eg. What is the strict aliasing rule?).
Also, trying to print an int with the "%f" format specifier is undefined behavior, since that format specifier expects a double (ref. eg. Why does printf("%f",0); give undefined behavior?).
So, you can't rely on any behavior of this code - anything is possible.
In practice, what's probably happening, is that the compiler decided to move *p = 6.35; to right before printf ("p:%f\n", *p);.
From your tags (type-conversion and implicit conversion) you seem to expect some type conversion to happen.
This is not the case.
Accessing memory with ill-typed pointer does not trigger any conversion to happen. It simply interpretes the memory in a different way. This includes violating the strict aliasing rules causing undefined behaviour.
And when you use
printf ("call1 x:%.100f\n", x);//0.0000000.....
you are cheating your compiler.
You promise to pass a double value (%f format specifier) which typically holds 8 bytes but then you only pass 4 bytes of an integer.
Mismatch in type specifier and parameter type causes undefined bahaviour and all expectations are worhless.
Then again you use
printf ("p:%f\n", *p);//6.350000
which works fine as you provide the proper double parameter. (here is the only implicit type conversion)
Your compiler should print some warnings when you try to compile this code.
And you should always listen to the compiler and resolve the warnings.
#include<stdio.h>
float func (float t, float y){
return y ;
}
int main (){
float t0,y0,t,y;
printf ("the value of t: ");
scanf ("%f",&t0);
printf ("the value of y: ");
scanf ("%f",&y0);
t=t0;
y=y0;
static int n=0;
// t[0]=t0;
// y[0]=y0;
for (n=0;n<=3;n++){
y[1]=y[0];
printf ("value of y %f %f \n",t,y);
}
return 0;
}
The error is:
Building prog.obj.
D:\master\c language\ch3\prog.c(166): warning #2117: Old-style function definition for 'main'.
D:\master\c language\ch3\prog.c(182): error #2144: Type error: pointer expected.
D:\master\c language\ch3\prog.c(182): error #2144: Type error: pointer expected.
*** Error code: 1 ***
You cannot array index something that is not an array, or a pointer into an array.
Your y and t floats are not pointers into arrays in your program.
You should make them float *y, *t into pointers so you can point them into array.
Change float t0,y0,t,y; to float t0,y0,*t,*y;
and
t=&t0; //assign address of t0 to t
y=&y0;
Change printf ("value of y %f %f \n",t,y); to
printf ("value of y %f %f \n",*t,*y); //note to dereference t and y here, to get their values
Here's a example of your program I fixed to work
The 'Old-style function definition for main()' message means that you've not given a prototype definition. The correct forms are:
int main(void) { ... }
int main(int argc, char **argv) { ... }
The version int main() is fine in C++, but not strictly a prototype in C, and hence gets the 'old-style' tag.
The other messages are more inscrutable; the line numbers do not correspond to the code you show. However, as Tony The Lion notes in his answer, the line
y[1] = y[0];
is erroneous since y is not an array. There is room to think that should be:
y = y0;
and you'd need a companion:
t = t0;
in order to have defined values printed in the printf() statement.
Even with these changes, the code does not make a lot of sense. However, given that you removed 150-odd lines, we can suppose that the missing code would make more sense.
There is no need to make n into a static variable; it is better not to do so.
Please make sure, in future, that your error messages correspond to the source code you post, not to some variant version of the code you post. The line numbers should not be as large as 166 or 182; they should be single digit numbers or small double digit numbers. But even more importantly, they should match the code!
I have to separate a program I created into 1 main function and 3 user defined functions.
The instructions for my work is as follows:
// gets an integer from the user and returns it // make 3 calls to
this function: // get the length of the rectangle from the user and
return it to main // get the width of the rectangle from the user and
return it to main // get the radius of the circle from the user and
return it to main int GetNum(void);
// takes two arguments, the length and width of the rectangle and
returns the area int CalculateAreaR(int length, int width);
// takes one argument, the radius of the circle and returns the area
double CalculateAreaC(int radius);
I am pretty stuck though. I've written the functions but can't correctly call them to the main function. I know it may be simple but there is just something im not seeing right. the code I have written is as follows:
#include <stdio.h>
#include <math.h>
#define PI 3.14
int GetNum(void)
{
int length;
int width;
int radius;
printf( " Please enter the length of a rectangle \n");
scanf(" %d", &length);
printf(" Please enter the width of a rectangle \n");
scanf(" %d", &width);
printf(" Please enter the radius of a circle \n");
scanf(" %d", &radius);
return length, width, radius;
}
int CalculateAreaR(int length, int width)
{
return length*width;
}
double CalculateAreaC(int radius)
{
return PI*radius*radius;
}
int main(void)
{
int length;
int width;
int radius;
int areaR;
double areaC;
GetNum();
printf("\nThe area of the rectangle is %d\n", CalculateAreaR);
printf("\nThe length is %d, the width is, %d and thus the area of the rectangle is %d\n\n", length, width, areaR);
areaC = CalculateAreaC();
printf("\nThe area of the circle is %.3f\n", CalculateAreaC);
printf("\n\n The radius of the circle is %d and the area of the circle is %.3f\n\n", radius, areaC);
return 0;
}
Can anyone please help me? I'd be very thankful. Im trying my best to learn.
In C, a function can only return a single value via the return statement.
For a simple program, you could make your GetNum() function modify global variables.
// variables placed outside any function have global scope
int length;
int width;
int radius;
int GetNum(void)
{
printf( " Please enter the length of a rectangle \n");
scanf(" %d", &length);
printf(" Please enter the width of a rectangle \n");
scanf(" %d", &width);
printf(" Please enter the radius of a circle \n");
scanf(" %d", &radius);
return 0;
}
This shows declaring the variables at global scope, then using them in the function.
A more advanced, but usually better, way to return multiple values is for the caller to pass a pointer to a variable, and the function to use the pointer to set the variable. #bash0r showed this technique in his/her answer.
Now, to call a function, you must always put parentheses after the function name. Always always always. If you put the name without the parentheses, you are not calling the function; you are just referring to the function (you are referencing the address of the function). You have a couple of places where you wanted to call functions but you didn't put the parentheses.
Some functions take arguments. When you call a function that takes arguments, you need to pass the arguments in. Here is an example of a function that multiplies a number by a factor and then adds a term.
float adjust_num(float x, float factor, float term)
{
return x * factor + term;
}
// example of calling the above:
float adjusted;
adjusted = adjust_num(input_value, scale_factor, 0.0f);
In the example, we pass in input_value and scale_factor. We don't have a constant or variable with a term to add, so we just pass in a literal 0.0 value. So for this example, we are passing all the required arguments. Then the function returns a value, and we collect that output value in the variable adjusted.
If you do try the global variables as I suggested, you will need to delete the lines that declare the variables inside the main() function. Otherwise you will declare two sets of variables, the ones private inside of main() and the other, global ones. The ones in main() will sort of hide the global ones; we call that "shadowing", as in "the local variables inside of main() are shadowing the global variables."
Good luck.
int GetNum(void)
{
...
return length, width, radius;
}
You can't do that, C functions can only return 1 return value. You can basically follow three approaches to solve this problem:
store length, width, radius in variables that are outside of the function (ie, global)
package the elements to be returned in a struct ure
pass pointers to variables containing length, width, radius to that function
Working with global variables is the easiest of these three, and probably sufficient in this case, but in real programs we tend to avoid global variables.
printf("\nThe area of the rectangle is %d\n", CalculateAreaR);
You can call a function inside a call to another function (in this case printf) you have to call the function, what you're doing here is giving a pointer to the function to printf. Also, if you declare a function as taking parameters, you have to give these parameters to the function, like this:
printf("\nThe area of the rectangle is %d\n", CalculateAreaR(length,width));
A comparable issue can be found here:
areaC = CalculateAreaC();
printf("\nThe area of the circle is %.3f\n", CalculateAreaC);
Same remarks as above (parameters should be given), however here you already store the result in areaC so you can just say
printf("\nThe area of the circle is %.3f\n", areaC);
You can't return 3 values at the same time. If you need more than 1 return value you must do it like this:
int x = 0, y = 0, z = 0;
myFunction( &x, &y, &z );
Where myFunction must be declared like this:
void myFunction( int *x, int *y, int *z ) { }
You can read from/write to x, y and y via the * operator. You can use it like this:
*x = 10; // write 10 to the variable behind x.
*y = *x; // write to variable behind y and read from variable behind x.
int *x is called a pointer variable/parameter. It stores an address instead of a value. With pointers you can 'point' to another variable and modify it's value from somewhere else (for example in a function which you call). The size of a pointer depends on the operating system (32-bit systems have 4 byte addresses and 64-bit systems have 8 byte adresses).
Inside of the main function, you should receive the input from your input function: getNum();
I usually like to encapsulate input data into separate functions so I specifically know that this function only does one thing. The whole point of declaring length, width, and radius inside the main is to actually be able use those values when I need them. The simplest approach can be done like so:
Function:
int get_length()
{
int length = 0;
printf("Enter length of rectangle: ");
scanf("%d", &length);
return length;
}
Main Function:
int main()
{
int length = 0;
length = get_length();
// collect additional input...
return 0;
}