Code using variadic arguments not giving the expected output - c

I have the following example code
#include <stdlib.h>
#include <stdio.h>
#include <stdarg.h>
void myprint(char *inizio, ...);
int main(void)
{
myprint("Inizio", 2, 3.0, 4, 5.0, 'c');
return(0);
}
void myprint(char *inizio, ...)
{
va_list argPoint;
int pi;
char pc;
double pd;
va_start(argPoint, inizio);
pi=va_arg(argPoint,int);
printf("Int = %d\n", pi);
pi=va_arg(argPoint,int);
printf("Int = %d\n", pi);
pd=va_arg(argPoint,double);
printf("Int = %f\n", pd);
/* need a cast here since va_arg only takes fully promoted types
pc=va_arg(argPoint,char); */
pc=(char)va_arg(argPoint,int);
printf("Int = %c\n", pc);
pd=va_arg(argPoint,double);
printf("Int = %f\n", pd);
pi=va_arg(argPoint,int);
printf("Int = %d\n", pi);
va_start(argPoint, inizio);
pi=va_arg(argPoint,int);
printf("Int = %d\n", pi);
va_end(argPoint);
}
I am getting the following output:
Int = 2
Int = 0
Int = 0.000000
Int =
Int = 0.000000
Int = 117
Int = 2
The answer according to my handout should be:
Int = 2
Int = 4
Int = 3.000000
Int = c
Int = 5.000000
Int = 1235099264
Int = 2
Why is it not working? I am using Codeblocks by the way, just in case.
Additionally what does the comment " need a cast here since va_arg only takes fully promoted types pc=va_arg(argPoint,char); " means? va_arg(argPoint,char) is supposed to return a char, I don't see why they do pc=(char)va_arg(argPoint,int) instead, the (char) seems redundant.

Related

Output does not print the correct variable addresses

Despite using double as datatype and correct format specifiers the output does not print the correct variable addresses output consists of just zeros
#include <stdio.h>
void main() {
double a[5] = { 6.0, 7.0, 8.0, 9.0, 10.0 };
double *p;
p = a;
printf("%lf \n", p);
for (int i = 0; i < 5; i++) {
printf("%lf \n", p++);
}
}
Output:
0.000000
0.000000
0.000000
0.000000
0.000000
0.000000
I fixed it with 2 simple changes, described in the comments.
#include<stdio.h>
void main()
{
double a[5]={6.0,7.0,8.0,9.0,10.0};
double *p;
p=a;
printf("%p \n",p); // Changed formatter to %p to print addresses
for(int i=0;i<5;i++)
{
printf("%p \n",p++); // Changed formatter to %p to print addresses
}
}
Output
0x7fffdd887250
0x7fffdd887250
0x7fffdd887258
0x7fffdd887260
0x7fffdd887268
0x7fffdd887270
These calls of printf
printf("%lf \n",p);
and
printf("%lf \n",p++);
invokes undefined behavior because there is used the wrong conversion specifier "%lf" (where by the way the length modifier has no effect even when used with object of the type double) with pointers.
Either you should use the conversion specifier %p like
printf("%p \n", ( void * )p);
and
printf("%p \n", ( void * )p++);
Or if you want to output addresses as integers you can include headers <stdint.h> and <inttypes.h> (the last header already includes the first header and write
#include <stdint.h>
#include <inttypes.h>
//...
printf("%" PRIuPTR "\n", ( uintptr_t )p);
and
printf("%" PRIuPTR "\n", ( uintptr_t )p++);
Pay attention to that according to the C Standard the function main without parameters shall be declared like
int main( void )
Here is a demonstration program.
#include <stdio.h>
#include <stdint.h>
#include <inttypes.h>
int main( void )
{
double a[] = { 6.0, 7.0, 8.0, 9.0, 10.0 };
const size_t N = sizeof( a ) / sizeof( *a );
double *p = a;
printf( "%p", ( void * )p );
printf( " <-> %" PRIuPTR "\n", ( uintptr_t )p );
for ( size_t i = 0; i < N; i++ )
{
printf( "%p", ( void * )p );
printf( " <-> %" PRIuPTR "\n", ( uintptr_t )p++ );
}
}
The program output is
00AFFE40 <-> 11533888
00AFFE40 <-> 11533888
00AFFE48 <-> 11533896
00AFFE50 <-> 11533904
00AFFE58 <-> 11533912
00AFFE60 <-> 11533920
maybe make the printf of for loop like this:
for(int i=0;i<5;i++)
{
printf("%lf \n",p[i]++);
}
OUTPUT:
0.000000
6.000000
7.000000
8.000000
9.000000
10.000000

Three possible ways to read a file and assign file values to variable

I have 3 scenarios to pass information of a input file to variables in my C code. 2 of them work, and one of them, which is what I need, doesn't work, and I don't know how to fix it.
Inside the input file:
23.65
47.93
2
7
The First Scenario:
#include <stdio.h>
long double* read_input_file(long double*);
int main (){
long double par[2];
read_input_file(par);
printf("par[0] = %Lf \npar[1] = %Lf \n\n", par[0], par[1]);
getchar();
return 0;
}
long double* read_input_file(long double* p){
FILE* input;
input = fopen("input.txt","r");
fscanf(input,"%Lf\n%Lf",&p[0],&p[1]);
printf("par[0]_in = %Lf \npar[1]_in = %Lf\n", p[0], p[1]);
fclose(input);
return p;
}
The Output:
par[0]_in = 23.650000
par[1]_in = 47.930000
par[0] = 23.650000
par[1] = 47.930000
This scenario does the job, however it limits the range of variable types I can use as my function is typed as long double.
Then, I tried the Second Scenario:
#include <stdio.h>
long double par[2];
int b, a;
void read_input_file(void);
int main (){
read_input_file();
printf("par[0] = %Lf \npar[1] = %Lf \n", par[0], par[1]);
printf("a = %d \nb = %d \n", a, b);
getchar();
return 0;
}
void read_input_file(void) {
FILE* input;
input = fopen("input.txt","r");
fscanf(input,"%Lf\n%Lf",&par[0],&par[1]);
fscanf(input,"%d\n%d",&a,&b);
printf("par[0]_in = %Lf \npar[1]_in = %Lf\n", par[0], par[1]);
printf("b_in = %d \nb_in = %d\n", a, b);
fclose(input);
}
The output:
par[0]_in = 23.650000
par[1]_in = 47.930000
b_in = 2
b_in = 7
par[0] = 23.650000
par[1] = 47.930000
a = 2
b = 7
This one is more flexible and I can specify the type of variable each number of my input file is assigned, however it needs the usage of global variables, something I'm trying to avoid.
Then I tried the Third Scenario:
#include <stdio.h>
void read_variables(long double*, int, int);
int main (){
long double par[2];
int a;
int b;
read_variables(par, a, b);
printf("par[0] = %Lf \npar[1] = %Lf \n", par[0], par[1]);
printf("a = %d \nb = %d \n", a, b);
getchar();
return 0;
}
void read_variables(long double*p, int A, int B){
FILE* input;
input = fopen("input.txt","r");
fscanf(input,"%Lf\n%Lf",&p[0],&p[1]);
fscanf(input,"%d\n%d",&A,&B);
printf("par[0]_in = %Lf \npar[1]_in = %Lf\n", p[0], p[1]);
printf("a_in = %d \nb_in = %d\n\n", A, B);
fclose(input);
}
The Output:
par[0]_in = 23.650000
par[1]_in = 47.930000
a_in = 2
b_in = 7
par[0] = 23.650000
par[1] = 47.930000
a = 1
b = 1922719232
What I tried to do in this third one is to avoid global variables, and in the same time use a function that reads the input file and assign the numbers there in a group of variables that are not of the same type.
I already tried to use int* a; int* b instead and it did not work.
What am I doing wrong here?
Thanks in advance!

The value returned in this program is. . . .Queer to say the least

So, I was experimenting with assembly and pointers, so I decided to do a little extra, I made a new integer , d and assigned the function exchange to it:
#include <stdio.h>
int exchange(int *xp, int *yp, int *zp){
int x = *xp;
int y = *yp;
int z = *zp;
*xp = z;
*yp = x;
*zp = y;
}
int main(){
int a = 3;
int b = 12;
int c = 24;
exchange(&a, &b, &c);
printf("int a = %d, int b = %d, int c = %d : ", a, b, c);
int d = exchange(&a, &b, &c);
printf("\n int d = %d", d);
return 0;
}
So, when I do the exchange function , it works as intended, switching the values in the registers. Except. . . .d returned a weird number: 6356768.
I'm not sure why d returns that value, but I would be much obliged if somebody would explain how it happened.
Your problem is that you have not returned anything from exchange whose return type is int. Hence what you see is garbage for the value of d. Try returning a status flag like 1 for success.
#include <stdio.h>
int exchange(int *xp, int *yp, int *zp) {
int x = *xp;
int y = *yp;
int z = *zp;
*xp = z;
*yp = x;
*zp = y;
return 1;
}
int main(){
int a = 3;
int b = 12;
int c = 24;
exchange(&a, &b, &c);
printf("int a = %d, int b = %d, int c = %d : ", a, b, c);
int d = exchange(&a, &b, &c);
printf("\n int d = %d\n", d);
return 0;
}
You should see something like,
int a = 24, int b = 3, int c = 12 :
int d = 1
Let me know if this helps !!
Not a proper answer, just an interesting observation:
I added some printfs in your code:
#include <stdio.h>
int exchange(int *xp, int *yp, int *zp){
int x = *xp;
int y = *yp;
int z = *zp;
printf("xp = %p, yp = %p, zp = %p\n", xp, yp, zp);
*xp = z;
*yp = x;
*zp = y;
}
int main(){
int a = 3;
int b = 12;
int c = 24;
printf("&a = %p, &b = %p, &c = %p\n", &a, &b, &c);
exchange(&a, &b, &c);
int d = exchange(&a, &b, &c);
printf("int d = %x\n", d);
return 0;
}
And ran it on my computer (gcc 7.3.0 on Ubuntu 18.04), and got this output:
&a = 0x7ffca0126788, &b = 0x7ffca012678c, &c = 0x7ffca0126790
xp = 0x7ffca0126788, yp = 0x7ffca012678c, zp = 0x7ffca0126790
xp = 0x7ffca0126788, yp = 0x7ffca012678c, zp = 0x7ffca0126790
int d = a0126790
It appears that lower 32 bits of the parameter zp is being returned from exchange. But If I move the call to printf to the end of exchange, it always returns 62, which is the value returned from printf itself.
My guess is, when you don't return a value from a function, probably the register used to hold the value to be returned retains the value returned by the subsequent function call. If no more function is called, then somehow it gets the value of a parameter, which I can't explain or guess.
But all these things are specific to the gcc on my computer (maybe yours too). Actually this is undefined behavior and you never know what would happen (quoting one of my professors: "The universe might get destroyed, who knows?").
When I ran the same code on ideone (which is gcc 6.3), I found the returned value to be 0.
I can't tell where is wrong in your program, so I put your code on my IDE, and surprisingly it even can't build. And the warning shows : Control reaches end of non-void function in Line 12 (the end } of the exchange function). so i tried to fix this problem by add a sentence : return z; . And it works!
I think it's because your function exchange is an int value returned function, unlike the void kind, it has to have a return value. so add one to it. it will run very well

Getting arguments from the stack in c

I just started to learn c and I was trying to create a function that gets it's arguments from the stack when I know all the arguments are from the same type, but it worked only for int.
This is what I did:
void Test1(double first_arg, ...)
{
double *a = &first_arg;
printf("arg[0]: %f\narg[1]: %f \narg[2]: %f\n", a[0], a[1], a[2]);
}
void Test2(int first_arg, ...)
{
int *a = &first_arg;
printf("arg[0]: %d\narg[1]: %d \narg[2]: %d\n", a[0], a[1], a[2]);
}
int main()
{
printf("Test1:\n");
Test1(1.0, 2.0, 3.0);
printf("\nTest2:\n");
Test2(1, 2, 3);
return 0;
}
Console:
Test1:
arg[0]: 1.000000
arg[1]: 0.000000
arg[2]: 0.000000
Test2:
arg[0]: 1
arg[1]: 2
arg[2]: 3
What am I missing here? And what should I do to fix this.
The way arguments are passed to a function are implementation dependent. To read variable arguments in a portable way, you need to use the stdarg family of functions.
#include <stdio.h>
#include <stdarg.h>
void Test1(double first_arg, ...)
{
printf("arg[0]=%f\n", first_arg);
va_list ap;
va_start(ap, first_arg);
double arg1 = va_arg(ap, double);
printf("arg[1]=%f\n", arg1);
double arg2 = va_arg(ap, double);
printf("arg[2]=%f\n", arg2);
va_end(ap);
}
int main()
{
printf("Test1:\n");
Test1(1.0, 2.0, 3.0);
return 0;
}

Changing int to double changes my result to zero

If I leave all variables as int I get 32. The division is supposed to give me 32.5 so I thought that changing everything to double would do it, but it just gives me zero...
Here is the code (everything in int):
#include <stdio.h>
#include <stdlib.h>
void sommeTableau(int tableau[], int tailleTableau, int *x, int *average);
int main(int argc, char *argv[])
{
int tableau[4] = {30, 50, 50};
int *x = 0;
int *average = 0;
const int tailleTab = 4;
sommeTableau(tableau, tailleTab, &x, &average);
printf("The average is %d\n", average);
return 0;
}
void sommeTableau(int tableau[], int tailleTableau, int *x, int *average)
{
int i = 0;
for (i = 0 ; i < tailleTableau ; i++)
{
*x = *x + tableau[i];
}
*average = *x/tailleTableau;
}
So this works and gives me 32... Now if I change everything to double and %d to %f in the printf function, it gives me zero and I don't understand why...
There is lots of mistakes in your code. I corrected all of them
#include <stdio.h>
#include <stdlib.h>
void sommeTableau(int tableau[], int tailleTableau, int *x, double *average);
int main(int argc, char *argv[])
{
int tableau[4] = {30, 50, 50};
int x = 0;
double average = 0;
const int tailleTab = 4;
sommeTableau(tableau, tailleTab, &x, &average);
printf("The average is %lf\n", average);
return 0;
}
void sommeTableau(int tableau[], int tailleTableau, int *x, double *average)
{
int i = 0;
for (i = 0 ; i < tailleTableau ; i++)
{
*x = *x + tableau[i];
}
*average = (double)(*x)/(double)tailleTableau;
}
You are passing x and average as null pointer. Thats why your code is giving segmentation fault.
As per you describtion please check(http://codepad.org/z8fVUTe5).
#include <stdio.h>
#include <stdlib.h>
void sommeTableau(int tableau[], int tailleTableau, int *x, int *average);
int main(int argc, char *argv[])
{
int tableau[4] = {30, 50, 50};
int x = 0;
int average = 0;
const int tailleTab = 4;
sommeTableau(tableau, tailleTab, &x, &average);
printf("The average is %d\n", average);
return 0;
}
void sommeTableau(int tableau[], int tailleTableau, int *x, int *average)
{
int i = 0;
for (i = 0 ; i < tailleTableau ; i++)
{
*x = *x + tableau[i];
}
*average = *x/tailleTableau;
}
Output:-
The average is 32
One of your problems lies here:
int *x = 0;
int *average = 0;
sommeTableau(tableau, tailleTab, &x, &average);
Those first two lines should be:
int x = 0;
int average = 0;
This is evident from the warnings you should be getting, assuming you're using a decent compiler:
qq.c: In function ‘main’:
qq.c:13: warning: passing argument 3 of ‘sommeTableau’ from incompatible pointer type
qq.c:4: note: expected ‘int *’ but argument is of type ‘int **’
qq.c:13: warning: passing argument 4 of ‘sommeTableau’ from incompatible pointer type
qq.c:4: note: expected ‘int *’ but argument is of type ‘int **’
In addition, you don't need _everything to be a double, just the average, so you should only change the type of that variable and match that with the parameters passed to the function.
It will also be necessary to cast the total *x to a double before doing the division, so that it knows you don't mean integer division.
With those changes, the output changes from:
The average is 4.000000
(for me) to the correct:
The average is 32.500000
See the following program for more detail:
#include <stdio.h>
#include <stdlib.h>
void sommeTableau(int tableau[], int tailleTableau, int *x, double *average) {
int i;
for (i = 0 ; i < tailleTableau ; i++)
*x = *x + tableau[i];
*average = ((double)(*x))/tailleTableau;
}
int main (void) {
int tableau[4] = {30, 50, 50};
int x = 0;
double average = 0;
const int tailleTab = 4;
sommeTableau(tableau, tailleTab, &x, &average);
printf("The average is %lf\n", average);
return 0;
}
int *x = 0;
int *average = 0;
This is defining two pointers and setting the pointers to zero -- which, in a pointer context translates to a null pointer. So, you have to pointers to nothing.
sommeTableau(tableau, tailleTab, &x, &average);
Here, you're passing the addresses of those pointers to the function, so the function is really receiving an int **.
printf("The average is %d\n", average);
This is then taking the value of the pointer -- the address its holding -- and (probably) treating that bit pattern as an int. This is technically undefined behavior, but on many machines, a pointer it enough like an int for it to appear to work. The same will almost never be true with a floating point number though.
What you want to do here is define two ints (or two doubles) and pass their addresses to your function:
double x=0.0, average=0.0;
sommeTableau(tableau, tailleTab, &x, &average);
// ...
printf("%f, %f\n", x, average);
It doesn't actually work.
Here you define x and average as NULL pointers to int:
int *x = 0;
int *average = 0;
And here instead of pointers to int you pass pointers to pointers to int:
sommeTableau(tableau, tailleTab, &x, &average);
Which is clearly wrong. You should enable compiler warnings to see such problematic places and correct them.
Here the correction would be:
int x = 0;
int average = 0;
Now, here:
printf("The average is %d\n", average);
You are lying to printf() about what you're going to give it (an int, because of %d), but you're actually giving it a pointer to int. The above correction fixes this. If you lie to printf() about the type of some parameter, anything can happen. If your compiler is gcc and you enable warnings, you can spot this kind of problems as well.
Something is terribly wrong here -- you're defining x and average as pointer variables in main, which if you are lucky is the same size as an int, but may result in undefined behavior.
Remove the * from the local variable declarations of x and average in main and it may actually work.
Also, in sommeTableau, both operands of the division (*x and tailleTableau) are int, so integer division is performed and the remainder discarded prior to assignment to *average.

Resources