Using pointers, GCD and LCM are solved using a single function and pointer. I'm not used to pointers yet. Anyway, I wrote the code below. However, errors such as terminated with exit code: 3221225477 continue to appear. According to a search on the Internet, the exit code above is due to incorrect memory references. But I don't know which part is wrong.
#include <stdio.h>
void gcdlcm(int a, int b, int* p_gcd, int* p_lcm){
int tmp, n, result_gcd, result_lcm;
int gcd_a, gcd_b;
p_gcd = &result_gcd;
p_lcm = &result_lcm;
if(a < b){
tmp = a;
a = b;
b = tmp;
}
gcd_a = a;
gcd_b = b;
if(gcd_b == 0){
result_gcd = 0;
}
while (gcd_b != 0)
{
n = gcd_a % gcd_b;
gcd_a = gcd_b;
gcd_b = n;
}
result_gcd = gcd_a;
printf("result_gcd = %d\n", result_gcd);
result_lcm = a * b / result_gcd;
printf("result_lcm = %d\n", result_lcm);
}
int main(){
int x, y;
int *p_gcd, *p_lcm;
scanf("%d %d", &x, &y);
gcdlcm(x, y, p_gcd, p_lcm);
printf("%d %d", *p_gcd, *p_lcm);
return 0;
}
Here:
p_gcd = &result_gcd;
you change the local variable p_gcd. This wil not affect the p_gcd in main, which after returning from gcdlcm has the same undefined value as before. Dereferencing it leads to your exception.
I you want to pass arguments as pointers so that your function can fill in the correct data, you must create variables to hold the data, then pass pointers to them with the address-of operator &:
int gcd, lcm;
scanf("%d %d", &x, &y);
gcdlcm(x, y, &gcd, &lcm);
(By the way, that's exactly the same how the scanf function one line above your call works.)
In your function, assign the result to what the pointer points to:
*p_gcd = gcd_a;
This modifies the variable gcd in main via the pointer p_gcd. Now, after returning from gcdlcm, gcd has the desired value.
the error is in this line printf("%d %d", *p_gcd, *p_lcm);. and the reason is that both will point to some random data.
This happens because your function will copy these values. p_gcd and p_lcm from your function are copies of the values in main. so when you set them, just the copies are modified to point to the variable, not the actual values. you should add a & or another * there, but even doing that will give you an error. because you try to return addresses of result_gcd and result_lcm which are local to your function.. and their addresses are invalid after the function ends
the best way around this would be (in my opinion) to return both values in a struct:
struct Result {
int gdc;
int lcm
};
struct Result gcdlcm(int a, int b){
//...
struct Result r;
r.gdc = result_gcd;
r.lcm = result_lcm;
return r;
}
if you dont like the solution, you can use pass pointers to variables in main and set them up in the function:
void gcdlcm(int a, int b, int* p_gcd, int* p_lcm){
int tmp, n, result_gcd, result_lcm;
int gcd_a, gcd_b;
if(a < b){
tmp = a;
a = b;
b = tmp;
}
gcd_a = a;
gcd_b = b;
if(gcd_b == 0){
result_gcd = 0;
}
while (gcd_b != 0)
{
n = gcd_a % gcd_b;
gcd_a = gcd_b;
gcd_b = n;
}
result_gcd = gcd_a;
printf("result_gcd = %d\n", result_gcd);
result_lcm = a * b / result_gcd;
printf("result_lcm = %d\n", result_lcm);
*p_gcd = result_gcd;
*p_lcm = result_lcm;
}
int main(){
int x, y;
int p_gcd, p_lcm;
scanf("%d %d", &x, &y);
gcdlcm(x, y, &p_gcd, &p_lcm);
printf("%d %d", p_gcd, p_lcm);
return 0;
}
You declared uninitialized pointers:
int *p_gcd, *p_lcm;
that have indeterminate values.
These pointers are passed by you to a function by value:
gcdlcm(x, y, p_gcd, p_lcm);
That is the function deals with copies of the values of the pointers p_gcd and p_lcm. So changing the copies do not affect the original pointers.
As a result dereferencing these initializing pointers in the statement:
printf("%d %d", *p_gcd, *p_lcm);
results in undefined behavior.
If you want to change the original pointers in the function you need to pass them by reference.
In C passing by reference means passing objects indirectly through pointers to them. So dereferencing the pointers you will get a direct access to the objects.
For example:
void gcdlcm(int a, int b, int **p_gcd, int **p_lcm){
int tmp, n, result_gcd, result_lcm;
int gcd_a, gcd_b;
*p_gcd = &result_gcd;
*p_lcm = &result_lcm;
//...
and in main:
gcdlcm(x, y, &p_gcd, &p_lcm);
Related
I am solving the problem of swapping the value of two variables. I need to do it using a helper function. Now I've been studying the call-by-value and call-by-reference stuff.
My only confusion is when I'm passing the arguments to the swap function, why am I sending the address(&a, &b)? What actually happens when I'm sending the address instead of the value itself?
Here's the code
#include <stdio.h>
void swap(int a, int b) {
int temp;
temp = a;
a = b;
b = temp;
printf("After swapping values in function(using call by value) a = %d, b = %d\n",a,b);
}
void swapref(int *a, int *b) {
int temp2;
temp2 = *a;
*a=*b;
*b=temp2;
printf("After swapping values in function(using call by reference) a = %d, b = %d\n",*a,*b);
}
int main() {
int a = 10, b = 20;
printf("Before swapping the values in main a = %d, b = %d\n",a,b);
swap(a,b);
printf("After swapping values in main(using call by value) a = %d, b = %d\n",a,b);
swapref(&a,&b); // <-- This is the line I'm talking about
printf("After swapping values in main(using call by reference) a = %d, b = %d\n",a,b);
return 0;
}
In the above code, what actually happens in the swapref(&a, &b) line?
Passing the address is different than giving the value since you passe the exact memory case where your original variable (a and b) are stored. Like :
void swapref(int *a, int *b)
So when in the function you modify those value, you change the original ones.
Whereas passing variables values like :
void swap(int a, int b)
You're passing a copy of each variable, so the originals won't be touched.
swap() parameters are passed by copy, while swapref() ones are passed by reference (i.e. you pass the variable memory address, instead of its content).
* operator returns the value-pointed-to of a variable
& operator returns the address-of a variable
To better understand what happens, I suggest you to print their addresses
void swap(int a, int b) {
int temp;
temp = a;
a = b;
b = temp;
printf("After swapping values in function (using call by value) [%p]a = %d, [%p]b = %d\n", &a, a, &b, b);
}
void swapref(int* a, int* b) {
int temp;
temp = *a;
*a = *b;
*b = temp;
printf("After swapping values in function (using call by reference) [%p]a = %d, [%p]b = %d\n", &(*a), *a, &(*b), *b);
}
int main()
{
int a = 10, b = 20;
printf("Before swapping the values in main [%p]a = %d, [%p]b = %d\n", &a, a, &b, b);
swap(a, b);
printf("After swapping values in main (using call by value) [%p]a = %d, [%p]b = %d\n", &a, a, &b, b);
swapref(&a, &b); // <-- This is the line I'm talking about
printf("After swapping values in main (using call by reference) [%p]a = %d, [%p]b = %d\n", &a, a, &b, b);
return 0;
}
Output:
Before swapping the values in main [000000A6B03BF834]a = 10, [000000A6B03BF854]b = 20
After swapping values in function(using call by value) [000000A6B03BF800]a = 20, [000000A6B03BF808]b = 10
After swapping values in main(using call by value) [000000A6B03BF834]a = 10, [000000A6B03BF854]b = 20
After swapping values in function(using call by reference) [000000A6B03BF834]a = 20, [000000A6B03BF854]b = 10
After swapping values in main(using call by reference) [000000A6B03BF834]a = 20, [000000A6B03BF854]b = 10
As you can notice, the variables used in swapref() present the same addresses as the ones that are passed to the function.
As you can see by the output of your program:
After swapping values in function(using call by value) a = 20, b = 10
After swapping values in main(using call by value) a = 10, b = 20
After swapping values in function(using call by reference) a = 20, b = 10
After swapping values in main(using call by reference) a = 20, b = 10
The variables are not actually swapped. Whenever passing a something as a parameter, its value is copied into the argument.
void by_val(int i) {
i = 2;
// the variable i in main will NOT be changed,
// because this one is a copy
}
void by_ptr(int* i) {
// This will change the i in main, because we didn't copy its value,
// but copied the memory address of i variable in main.
*i = 2;
// Now we can make i point to an other variable than the main function i.
// This will not update i, but it will update num.
int num = 2;
i = #
*i = 3;
}
int main() {
int i = 1;
by_val(i);
printf("%d\n", i); // "1"
by_ptr(&i);
printf("%d\n", i); // "2"
}
So in your first swap function, the values of the copies of (main) a and b are being swapped, not the values of (main) a and b. But in your second function, the values of (main) a and b are swapped, because you passed the memory addresses of the (main). The * operator makes the program use the values in the variables, the memory address is pointing to.
It doesn't help that you're using the same names for different things. For the purpose of this answer, we're going to assume the variables in main are named x and y instead:
int main( void )
{
int x = 10, y = 20;
...
swap(x, y);
...
swapref(&x, &y);
...
}
That will make the following discussion easier to follow.
The formal parameters a and b in swap are different objects in memory from the local variables x and y in main.
When you call
swap(x, y);
in main, the expressions x and y are fully evaluated and the results of those evaluations (10 and 20, respectively) are passed to swap and copied into its formal arguments.
Since a and b are different objects from x and y, exchanging the values of a and b has no effect on the values of x and y.
Just like with swap, the formal parameters a and b in swapref are different objects in memory from the local variables x and y. When you call
swapref(&x, &y);
the expressions &x and &y are fully evaluated, and the results of those evaluations (the addresses of x and y) are passed to swapref and copied into the formal arguments a and b.
This means the following relationships are true:
a == &x // int * == int *
*a == x // int == int
b == &y // int * == int *
*b == y // int == int
Again, since a and b in swapref are different objects in memory from x and y in main, changing the values of a and b in swapref has no effect on x and y. However, when you write new values to the expressions *a and *b in swapref, you're not changing the values of a and b but rather what a and b point to, which in this case is x and y.
You can kinda-sorta think of *a and *b as aliases for x and y - they're alternate names for the same objects. Writing
temp = *a;
*a = *b;
*b = temp;
is equivalent to writing
temp = x;
x = y;
y = temp;
I have a function which returns an integer pointer type:
int* f(int a, int b){
int *result;
result = &a;
*result += b;
return result;
}
and when I call this on main:
int main(){
int a = 5;
int b = 2;
int *result = f(a,b);
printf("The result is: %d \n", *result);
return 0;
}
It gives me the correct output(in this case 7). I was under the impression that by assigning the address of the parameter a to result I would get a segmentation fault when I ran this function.
My assumption is that C treats function parameters as local in scope to the function definition. But, I see that this is not the case so why is this specific program working ?
I'm using Code::Blocks 16.01 with gcc compiler.
Just because it works on your machine doesn't mean it isn't undefined behaviour. This works by fluke, but it's invalid.
It may produce the correct result because that stack is not overwitten or otherwise mangled by the time you do something later on.
For example, if you make another function call:
#include <stdio.h>
#include <stdlib.h>
int noop(int x, int y) {
return x + y;
}
int* f(int a, int b){
int *result;
result = &a;
*result += b;
return result;
}
int main(){
int a = 5;
int b = 2;
// Do something with undefined behaviour
int *result = f(a,b);
// Do something else which uses the stack and/or the same memory
int x = 10;
int y = 11;
int z = noop(x, y);
printf("The result is: %d \n", *result);
return 0;
}
Now the output gets stomped with the definition of x which coincidentally takes the same piece of memory so the output is 10. As this is undefined behaviour, though, anything could happen, including a crash.
I thought that calling function by value will never work, and I should always use call by reference, but trying this code...
// call by value
#include<stdio.h>
int Add(int a, int b)
{
int c = a + b ;
return c ;
}
int main()
{
int x = 2 , y = 4 ;
int z = Add(x,y);
printf("%d\n",z);
}
output will be: 6
it works fine in both ways (call by value & call by reference),
// call by reference
#include<stdio.h>
int Add(int* a, int* b)
{
int c = *a + *b ;
return c ;
}
int main()
{
int x = 2 , y = 4 ;
int z = Add(&x,&y);
printf("%d\n",z);
}
output will be: 6
not like the famous swap function example - when calling by value it doesn't swap -
// call by value
#include <stdio.h>
void swap(int a, int b)
{
int temp;
temp = b;
b = a;
a = temp;
}
int main()
{
int x = 1 , y = 2;
printf("x = %d , y = %d\n", x,y);
swap(x, y);
printf("after swapping\n");
printf("x = %d , y = %d\n", x,y);
return 0;
}
.. it only worked calling by reference
// call by reference
#include <stdio.h>
void swap(int *a, int *b)
{
int temp;
temp = *b;
*b = *a;
*a = temp;
}
int main()
{
int x = 1 , y = 2;
printf("x = %d , y = %d\n", x,y);
swap(&x, &y);
printf("after swapping\n");
printf("x = %d , y = %d\n", x,y);
return 0;
}
So How can I judge if "calling by value" going to work or not ?!
So How can I judge that call by value method is valid or not ?!
Well, it depends on what your function is about to do.
In your above example, you only need the values of (x,y) for computing, but you never plan to change their value during your function. While call-by-reference will work in this case, it is unneccessary.
In the other (indirectly given) example you obviously want to change two variable's content (that is - swap it). You can access these variables from the main-function in your Swap-function, but how can you make the change persistent? That's only possible by call-by-reference, because you have to write the changed content into a variable that survives the function.
The following will not work:
// call by value
#include<stdio.h>
void Swap(int a, int b)
{
int c = a;
a = b;
b = c;
// from here on a, b, c will be destroyed
// therefore the change cannot be seen outside the function
}
int main()
{
int x = 2 , y = 4 ;
Swap(x,y);
printf("x: %d --- y: %d\n",x,y);
}
So as a rule to keep in mind:
If you want to make a change that's supposed to survive the function's end, use call-by-reference. If you just work with some data but do not want to (or must not) change their value, use call-by-value.
A few lessons ago I learned about variables, and got a question in my homework about swapping two numbers - I used a third variable to solve this question.
The solution looked somewhat like this:
#include <stdio.h>
int main(void) {
int x, y;
scanf("%d %d", &x, &y);
// swappring the values
int temp = x;
x = y;
y = temp;
printf("X is now %d and Y is now %d", x, y);
}
Now I'm learning about functions, and I wanted to try and solve the previous question with a helper swap function.
This is the code I've written:
#include <stdio.h>
void swap(int x, int y) {
int temp = x;
x = y;
y = temp;
}
int main(void) {
int a = 3, b = 4;
swap(a, b);
printf("%d %d\n", a, b);
}
I don't know why, but the output is still 3 4 even though I changed the value inside the swap() function.
Why is this happening?
Pass address of x and y as arguments to function. Right now they are local variables, changes are not made to original variables .
Do as follows-
void swap(int *x,int *y){
/* dereference pointers and swap */
int temp = *x;
*x = *y;
*y = temp;
}
And call in main like this -
swap(&x,&y);
What you are doing is passing parameter by value. It means that during the function call, copies of parameters are created. So inside the function you are working on copies of actual variables.
Instead you need to pass it as a reference. Please read more about pass-by-value vs pass-by-reference.
#include <stdio.h>
void swap(int& x,int& y) //Instead of passing by value just pass by reference
{
int temp=x;
x=y;
t=yemp;
}
int main() {
int a=3,b=4;
swap(a,b);
printf("%d %d\n",a,b);
return 0;
}
EDIT:
C does not have references. Above code will work in c++ instead. To make in work in C, just use pointers and de-reference it inside the function.
Complete C newb here. Trying to learn/understand pointers by messing with simple code fragments.
#include <stdio.h>
void swap(int *px, int *py)
{
int tmp;
tmp = *px;
*px = *py;
*py = tmp;
}
main()
{
int *a, *b;
*a = 1;
*b = 2;
swap(&a,&b);
printf("%d %d\n", *a, *b);
}
Why is this not valid? The code works when I remove the dereferencing operator * from main.
Conceptually, this seems like it should work. I initialize a and b as pointers which point to int 1 and int 2, respectively. I then send their addresses to swap(), which should switch what they point to.
There are a couple of problems. First, the pointers a and b are not pointing to valid memory. So the assignment of the integer values is undefined (possible crash). Secondly, the call to swap (assuming a and b are pointing to valid memory) should not include the address (it is currently sending the address of the pointer variable).
The following changes would make it work:
int a, b;
a = 1;
b = 2;
swap(&a,&b);
printf("%d %d\n", a, b);
The swap() function is OK but inside main you are taking the addresses of pointers, so you're passing int** arguments to int* parameters.
int *a, *b;
swap(&a,&b);
To fix it, replace the code in main() with :
int a = 1, b = 2;
swap(&a,&b);
printf("%d %d\n", a, b);
Pointers point to data. A pointer itself doesn't comprise memory for storage, it just points to existing memory. So when you declare int *a; , you just have a garbage pointer with no useable value, and you mustn't dereference it.
The only sensible way to use pointers is to assign them the address-of something (or the result of some allocation function):
int i;
int *a = &i; // now a points to i
Therefore, the right way to use your swap function is to pass it addresses of integers:
int i = 10;
int j = -2;
swap(&i, &j);
a and b are uninitialized pointers, dereferencing them induces undefined behavior. You want:
int main() {
int a, b;
a = 1;
b = 2;
swap(&a,&b);
printf("%d %d\n", a, b);
return 0;
}
Your method signature is wrong. You ask for two pointers to int, yet you pass in two pointers to pointers to int.
When you say, " I then send their addresses to swap(), which should switch what they point to." Are you trying to change the address values within the pointer variables in main, to switch which bit of memory they are pointing to? In that case you will need another step of redirection:
#include <stdio.h>
void swap(int **px, int **py) {
int *tmp;
tmp = *px;
*px = *py;
*py = tmp;
}
int main (void) {
int x, y; /* storage to point to */
int *a, *b;
a = &x;
b = &y;
*a = 1;
*b = 2;
printf("(*a, *b, x, y) == (%d, %d, %d, %d)\n", *a, *b, x, y);
swap(&a, &b);
printf("(*a, *b, x, y) == (%d, %d, %d, %d)\n", *a, *b, x, y);
}
$ ./a.out
(*a, *b, x, y) == (1, 2, 1, 2)
(*a, *b, x, y) == (2, 1, 1, 2)
The x & y values have not changed, but a was pointing to x and now points to y and vice versa for b.