Pointer arithmetic

M

main()

Hi all,

I have three newbie questions :

1) According to my understanding, main function can be defined in any
of the following two ways,
int main(void)
int main(int argc,char *argv[])
How can the same function can have two different signatures ?

2) My second question is ,

#include<stdio.h>

int main(void)
{
int *p = (int*) 1;
int *q = (int*) 2000;
printf("%d\n",(q-1));
printf("%d\n",(q-p));
}

output:
1996
499

I can understand why the first printf outputs 1996, (because when you
decrement an integer pointer, it points to the prevoius integer which
is four bytes offset from the current location)
But i cannot understand why second printf outputs 499 ?
Can anyone throw light on this one ?

3) I want to write a function in C (this can be done easily in C++) ,
that takes variable number of arguments. When i googled for this, i
found stdarg facility.
It requires first argument as char format like "%d %d" etc..
But what i want is like,

func(1)
func(1,2)
func(1,2,3)
func(1.2,2.3)
etc..........

How can i do this using C ?

Thanks for your time,
Yugi
 
M

Morris Dovey

main() (in (e-mail address removed)) said:

| Hi all,
|
| I have three newbie questions :
|
| 1) According to my understanding, main function can be defined in
| any of the following two ways,
| int main(void)
| int main(int argc,char *argv[])
| How can the same function can have two different signatures ?
|
| 2) My second question is ,
|
| #include<stdio.h>
|
| int main(void)
| {
| int *p = (int*) 1;
| int *q = (int*) 2000;
| printf("%d\n",(q-1));
| printf("%d\n",(q-p));
| }
|
| output:
| 1996
| 499
|
| I can understand why the first printf outputs 1996, (because when
| you decrement an integer pointer, it points to the prevoius
| integer which is four bytes offset from the current location)
| But i cannot understand why second printf outputs 499 ?
| Can anyone throw light on this one ?

My results were:
1999
1999

| 3) I want to write a function in C (this can be done easily in C++)
| , that takes variable number of arguments. When i googled for this,
| i found stdarg facility.
| It requires first argument as char format like "%d %d" etc..
| But what i want is like,
|
| func(1)
| func(1,2)
| func(1,2,3)
| func(1.2,2.3)
| etc..........
|
| How can i do this using C ?

You're on the right track; but you'll need some way to regognize when
you've processed all of the arguments. If you intend to pass different
types in the same position, then you'll also need to provide some way
for func() to know the type of the argument in that position. (One way
to do both might be to pass a string as the first parameter that
specifies the types of the arguments that follow; and when func()
finds the terminating NUL, it knows that all arguments have been
processed.)
 
K

Keith Thompson

main() said:
I have three newbie questions :

1) According to my understanding, main function can be defined in any
of the following two ways,
int main(void)
int main(int argc,char *argv[])
How can the same function can have two different signatures ?

The function "main" is unique in that it can *only* have one of two
different signatures. If you define your own function called, say,
"foo", it can have any signature you like. main() is restricted
because it's invoked from the environment.

main() can only have one signature within a single program. You just
get to choose from the two possibilities. The environment needs to be
able to invoke your main() function whichever way you define it.
2) My second question is ,

#include<stdio.h>

int main(void)
{
int *p = (int*) 1;
int *q = (int*) 2000;
printf("%d\n",(q-1));
printf("%d\n",(q-p));
}

output:
1996
499

You're invoking undefined behavior. Conversion from a pointer type to
an integer type is implementation-defined. The correct way to print a
pointer value is to convert it to void* and use the "%p" format.

Pointer subtraction yields the distance, in elements (int in this
case) between the two pointers. If int is 4 bytes, and p and q are
1999 bytes apart, that's a difference of 499.75 ints -- which
obviously doesn't make sense. Presumably the implementation does
something like taking the difference in bytes between the two pointer
values and divides by 4, ignoring any remainder. That yields the
correct result for the cases where it's defined; it doesn't matter
what it does in cases like this, where it's undefined.
3) I want to write a function in C (this can be done easily in C++) ,
that takes variable number of arguments. When i googled for this, i
found stdarg facility.
It requires first argument as char format like "%d %d" etc..
But what i want is like,

func(1)
func(1,2)
func(1,2,3)
func(1.2,2.3)
etc..........

How can i do this using C ?

You can't. You have to have some way to tell the function the number
and type(s) of the arguments. printf() and friends encode this
information in the format string. You can also use some special value
to mark the last argument; this is easiest if all the arguments are of
the same type, and if there's some value that can't be a normal
argument.

If, as in your example, you just want to pass some number of integer
values, you can also pass an integer and an int*; the latter points to
an array containing the values. But this requires more setup before
the function call.
 
C

Chris Torek

1) According to my understanding, main function can be defined in any
of the following two ways,
int main(void)
int main(int argc,char *argv[])
How can the same function can have two different signatures ?

"It can't."

Really, that *is* the answer. You pick one of the two and compile
your module that contains your main(). The compiler is required
to look at your main() and, if it is one of those two forms, it
will make it work. How it makes it work is up to the compiler.

One way to "make it work" is to generate, in the actual executable
program you will run, either "2arg_main" or "0arg_main" (note that
both of these names are not something *you*, the programmer, can
enter; but your compiler can use those names behind your back, as
it were). Then, if you call your own main() recursively, or when
it comes time for the startup code to call your main(), the compiler
just has to make sure that it calls the correct one of these two.

(There are other ways to "make it work" that depend on the target
system, and most real compilers use one of those, since those are
usually easier.)
2) My second question is ,

#include<stdio.h>

int main(void)
{
int *p = (int*) 1;
int *q = (int*) 2000;
printf("%d\n",(q-1));
printf("%d\n",(q-p));
}

output:
1996
499

I can understand why the first printf outputs 1996, (because when you
decrement an integer pointer, it points to the prevoius integer which
is four bytes offset from the current location)
But i cannot understand why second printf outputs 499 ?
Can anyone throw light on this one ?

The output of these two printf() calls is undefined -- which means
that *any* output you get is correct (or, equivalently, wrong :) ).

In order to predict what you will get, on some *particular* system,
we need to know a great deal about the internals of that system.

The first problem is that (int *)1 and (int *)2000 produce
implementation-defined pointer values.

The second problem is that %d prints an "int", but (q-1) generates
a pointer value of type "int *".

If your printf() takes "int *" arguments out of pointer registers
(e.g., A0 through A5), and "int" arguments out of integer registers
(e.g., D0 through D7), the output of your first printf() statement
will be whatever was in a "D" register, even though the pointer
you supplied -- q-1 -- was passed in an "A" register. This will
make the first printf()'s output very difficult to predict.

The last printf() is actually the most predictable, provided we
know what happens with conversion of the integer constants 1 and
2000 to (int *). To find the result of subtracting two pointers of
compatible type, we first assert that they point into the same
array object. (If not, the result is undefined.) Then, we simply
find the number of elements between the two pointers -- which is
the same as the integer that, if added to the second pointer, would
have produced the first one:

distance = first - second;
assert(first + distance == second);

This "distance" number can be negative, so the resulting type of
"ptr2 - ptr1" has type "ptrdiff_t" (not type "int"). There is no
printf() format for ptrdiff_t, but we can convert the difference
to "long" and print it with %ld (in C89) or to "long long" and use
"%lld" (in C99):

/* given some array and some valid indices i and j */
ptrdiff_t distance;

ptr1 = &array;
ptr2 = &array[j];
distance = ptr2 - ptr1;
printf("%ld\n", (long)distance);
assert(distance == j - i);
3) I want to write a function in C (this can be done easily in C++) ,
that takes variable number of arguments. When i googled for this, i
found stdarg facility.
It requires first argument as char format like "%d %d" etc..

This is not the case. See, for instance, the answer to question
15.4 in the FAQ. (Consider the POSIX-specific "execl" function,
as well.)
But what i want is like,

func(1)
func(1,2)
func(1,2,3)
func(1.2,2.3)
etc..........

How can i do this using C ?

You cannot: as shown, there is no way for func() to discover how
many arguments it actually received, nor their types. The reason
printf() takes "%d", "%f", and so on is that the number of "%"s
(not counting "%%" which produces one "%" character) tell it how
many actual arguments to expect, and the letters -- "d", "f", "s",
and so on -- after the "%" tell it what types to expect.

The example in the FAQ (at 15.4) avoids the need for "type"
information by requiring that every parameter to the function
have one particular type ("const char *" every time). It avoids
the need for a count of arguments by requiring that the list of
arguments be terminated by a special marker.

If all the arguments to func() are integers, and none is ever
negative, you could mark the "stopping point" with a -1:

func(1, -1);
func(1, 2, -1);
func(1, 2, 3, -1);

but your last example suggests that sometimes some or all arguments
may have some other type(s).
 
P

pghoshjobs

"The function "main" is unique in that it can *only* have one of two
different signatures. "

Nope AFAIK, main can have 3 different signatures

1. main (void)
2. main (int argc, char *argv[])
3. main (int argc, char *argv[], char *envp[])


- Partha
 
H

Harald van =?UTF-8?B?RMSzaw==?=

"The function "main" is unique in that it can *only* have one of two
different signatures. "

Nope AFAIK, main can have 3 different signatures

1. main (void)
2. main (int argc, char *argv[])
3. main (int argc, char *argv[], char *envp[])

Your third form is non-standard.
 
S

spibou

"The function "main" is unique in that it can *only* have one of two
different signatures. "

Nope AFAIK, main can have 3 different signatures

1. main (void)
2. main (int argc, char *argv[])
3. main (int argc, char *argv[], char *envp[])

If you google for N1124 and read section 5.1.2.2.1 you'll
see that only the first 2 forms are valid although the third
may also work on many platforms. The third may appear
in some Unix standard but I'm not sure.

Spiros Bousbouras
 
H

Harald van =?UTF-8?B?RMSzaw==?=

"The function "main" is unique in that it can *only* have one of two
different signatures. "

Nope AFAIK, main can have 3 different signatures

1. main (void)
2. main (int argc, char *argv[])
3. main (int argc, char *argv[], char *envp[])

If you google for N1124 and read section 5.1.2.2.1 you'll
see that only the first 2 forms are valid although the third
may also work on many platforms. The third may appear
in some Unix standard but I'm not sure.

[OT] Technically, it does (susv3, in the rationale for environ and
exec[vl]e()), but only to mention that even when that form is permitted by
an implementation as an extension, the other two forms must be supported as
well, and that there is nothing you can do with the third form that you
can't do without it.
 
N

Nick Keighley

(e-mail address removed) wrote:

please quote in a standard manner and leave attributions in
"The function "main" is unique in that it can *only* have one of two
different signatures. "

Nope AFAIK, main can have 3 different signatures

1. main (void)
2. main (int argc, char *argv[])
3. main (int argc, char *argv[], char *envp[])

You are wrong. The 3rd version you give is non-standard (I think some
Unixen support it).
 
N

Nick Keighley

main() wrote:

3) I want to write a function in C (this can be done easily in C++) ,
that takes variable number of arguments.

really? how can this be done in C++?

[...] When i googled for this, i
found stdarg facility.
It requires first argument as char format like "%d %d" etc..

no. It needs to know the number and type of the arguments and
format strings are one way to do that. I've seen functions that took
a list of char*s the last argument had to be a null pointer. Or the
first
argument could be a count.
But what i want is like,

func(1)
func(1,2)
func(1,2,3)
func(1.2,2.3)
etc..........

How can i do this using C ?

is

func (1, 1);
func (2, 1, 2);
func (3, 1, 2, 3);

any use?
 
K

Keith Thompson

"The function "main" is unique in that it can *only* have one of two
different signatures. "

(I wrote the above.)
Nope AFAIK, main can have 3 different signatures

1. main (void)
2. main (int argc, char *argv[])
3. main (int argc, char *argv[], char *envp[])

Several others have pointed out that the third form is non-standard.

Please learn to quote properly. Quoted text is indicated by a "> "
prefix on each line, along with an attribution line indicating who
wrote what. Google Groups will do this for you.
 
G

goose

Nick said:
main() wrote:



really? how can this be done in C++?

<OT>
Function overloading? It means that you will write
more than one function, but the caller doesn't have
to know this; it'll look like one function.
</OT>


goose,
 
C

CBFalconer

goose said:
<OT>
Function overloading? It means that you will write
more than one function, but the caller doesn't have
to know this; it'll look like one function.
</OT>

What a horrible misuse of the facility. It simply defeats any
compile time checking.
 
G

goose

CBFalconer said:
What a horrible misuse of the facility. It simply defeats any
compile time checking.
<grin>Many would agree with you - C++ defeats
all the good points of C (depending on who you
talk to).

goose,
 
F

Frederick Gotham

goose posted:
<grin>Many would agree with you - C++ defeats
all the good points of C (depending on who you
talk to).


Indeed, depending on *who* you talk to.

An advocate of petrol cars will list all the bad points of diesel cars.
An advocate of diesel cars will list all the bad points of petrol cars.

With any look, after hearing both sides, you'll make your *own* decision when
buying a car.
 
K

Kenneth Brody

main() said:
Hi all,

I have three newbie questions :

1) According to my understanding, main function can be defined in any
of the following two ways,
int main(void)
int main(int argc,char *argv[])
How can the same function can have two different signatures ?

Because the Standard specifically allows this for main(). How
the compiler and runtime environment handle this is irrelevent.
However, imagine a runtime environment in which arguments are
pushed on the stack, and the caller cleans up the stack upon
return. The runtime environment could simply push the parameters
on the stack regardless. The first version would simply ignore
the values on the stack, and nothing bad would happen. It's also
possible that the compiler flags the compiled code in some manner
as to tell the linker which version was used, and the linker then
causes the corresponding startup code to be included.

Consider it "magic".
2) My second question is ,

#include<stdio.h>

int main(void)
{
int *p = (int*) 1;
int *q = (int*) 2000;
printf("%d\n",(q-1));
printf("%d\n",(q-p));
}

output:
1996
499

I can understand why the first printf outputs 1996, (because when you
decrement an integer pointer, it points to the prevoius integer which
is four bytes offset from the current location)
But i cannot understand why second printf outputs 499 ?
Can anyone throw light on this one ?

Well, there is a lot of system-dependent stuff here (ie: sizeof int,
using "%d" on a pointer, and "making up" pointers out of the blue),
but think of it this way...

You understand how subtracting 1 from the pointer causes the address
to decrease by 4. Simply extend this to "how many times would you
have to subtract 1 from the original value of 'q' to get the value
of 'p'?". In this case, the "real" answer is "499.75", which of
course isn't an integer.

However, the compiler probably implements this something along the
lines of "take the difference of the values [in this case, 1999] and
divide by sizeof int [4]", and gets 499, since it will do an integer
divide.
3) I want to write a function in C (this can be done easily in C++) ,
that takes variable number of arguments. When i googled for this, i
found stdarg facility.
It requires first argument as char format like "%d %d" etc..
But what i want is like,

func(1)
func(1,2)
func(1,2,3)
func(1.2,2.3)
etc..........

How can i do this using C ?

"varargs".

However, you need to pass something which will allow the called
function to determine the number and types of parameters. For
example, printf() gets a format string, which tells it what are
the rest of the parameters.

--
+-------------------------+--------------------+-----------------------+
| Kenneth J. Brody | www.hvcomputer.com | #include |
| kenbrody/at\spamcop.net | www.fptech.com | <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------+
Don't e-mail me at: <mailto:[email protected]>
 
K

Kenneth Brody

goose said:
<OT>
Function overloading? It means that you will write
more than one function, but the caller doesn't have
to know this; it'll look like one function.
</OT>

The OP said "variable number of arguments", not "one of a fixed set
of parameter count and type".

--
+-------------------------+--------------------+-----------------------+
| Kenneth J. Brody | www.hvcomputer.com | #include |
| kenbrody/at\spamcop.net | www.fptech.com | <std_disclaimer.h> |
+-------------------------+--------------------+-----------------------+
Don't e-mail me at: <mailto:[email protected]>
 
K

Keith Thompson

Kenneth Brody said:
"varargs".
[...]

That's a potentially confusing answer. <varargs.h> is an old,
pre-ANSI header used to handle variadic argument lists; it was
replaced by <stdarg.h>. Some systems still provide both.
 
H

Herbert Rosenau

Hi all,

I have three newbie questions :

1) According to my understanding, main function can be defined in any
of the following two ways,
int main(void)
int main(int argc,char *argv[])
How can the same function can have two different signatures ?

You'll ever use one or the other, but never both in the same program.
The former is good when you have no need to attach argc or argv, means
ignoring all parameters.
You'll use the latter whenever you've a need to access at least 1
parameter given from the callee of the program.

2) My second question is ,

#include<stdio.h>

int main(void)
{
int *p = (int*) 1;

Invokes application defined behavior, not portable.
int *q = (int*) 2000;

Same as above.
printf("%d\n",(q-1));

Invokes undefined behavior.
printf("%d\n",(q-p));
}

output:
1996
499

That is only one of endless possible results after invoking undefined
behavior.
I can understand why the first printf outputs 1996, (because when you
decrement an integer pointer, it points to the prevoius integer which
is four bytes offset from the current location)
But i cannot understand why second printf outputs 499 ?
Can anyone throw light on this one ?

Undefined behavior makes anything you can ever think on possible.
3) I want to write a function in C (this can be done easily in C++) ,
that takes variable number of arguments. When i googled for this, i
found stdarg facility.
It requires first argument as char format like "%d %d" etc..
But what i want is like,

No, not true. It requires at least 1 (one) argument with fixed type as
first parameter.
func(1)
func(1,2)
func(1,2,3)
func(1.2,2.3)
etc..........

How can i do this using C ?

You can't as a function of that type can only have a fixed number and
types of parameters.

A function with a variable number of parameters would be prototyped
like:

int funca(char *format, ...);

or

char *funcb(int a, int No_of_params, ...);

or

double funcc(ina no_of_params, int *err, ...):

and so on.


--
Tschau/Bye
Herbert

Visit http://www.ecomstation.de the home of german eComStation
eComStation 1.2 Deutsch ist da!
 
H

Herbert Rosenau

"The function "main" is unique in that it can *only* have one of two
different signatures. "

Nope AFAIK, main can have 3 different signatures

1. main (void)

int main(void);
2. main (int argc, char *argv[])

int main(int argc, char *argv[]);
equivalent to
int main(int argc, int **argv);
3. main (int argc, char *argv[], char *envp[])

int main(int argc, char*argv[], char *envp[]);
but implementation defined, not standard.


--
Tschau/Bye
Herbert

Visit http://www.ecomstation.de the home of german eComStation
eComStation 1.2 Deutsch ist da!
 

Ask a Question

Want to reply to this thread or ask your own question?

You'll need to choose a username for the site, which only take a couple of moments. After that, you can post your question and our members will help you out.

Ask a Question

Members online

No members online now.

Forum statistics

Threads
473,997
Messages
2,570,239
Members
46,827
Latest member
DMUK_Beginner

Latest Threads

Top