Re: Help a beginner - function with pointer ...
- From: Eric Sosman <esosman@xxxxxxxxxxxxxxxxxxxx>
- Date: Tue, 14 Jul 2009 09:31:11 -0400
bpascal123@xxxxxxxxxxxxxx wrote:
Hi all,
Sorry for not following this post i have initiated. Here is the full
code so you can see where I was confused.
When i sent this post, i thought (float *) T would be appealing to
some C expert programmer like some inside c convention such as a
+=1 ... i didn't even try to compil the code before sending it to you
let say for validation ; my fault
#include <stdio.h>
main()
{
float Sum(float *A, int N, int M);
float T[3][4] = {{1, 2, 3, 4},
{5, 6, 7, 8},
{9,10,11,12}};
printf("Sum des éléments : %f \n",
Sum((float*)T, 3, 4) ); // Is this (float*) a type
casting for T ???
return 0;
}
float Sum(float *A, int N, int M)
{
int I;
float S;
for (I=0; I<N*M; I++)
S += A[I];
return S;
}
It looks like there are two substantive questions here:
(1) What does the cast mean? and (2) Why is it used?
The cast is an operator taking one operand and producing
a value. The result is the value obtained by converting the
operand value to a different (usually) type. For example,
`(int) 3.14159' takes a `double' value approximately equal
to pi and converts it to an `int'; the result is the `int'
value three. `(float) 3.14159' takes the same `double' value
and converts it to a `float'; the result is again approximately
equal to pi but probably slightly different from the original.
The cast `(float*) T' is slightly subtler, mostly because
the values of pointers are harder to "see" -- It's easy to
notice that converting a `double' to an `int' discards the
fractional part, and it's not much harder to see that
converting a `double' to a `float' may yield a slightly
coarser approximation, but pointer values are a little harder
to observe because they are usually described not in their
own terms but in terms of the things they point at. Still,
`(float*) T' operates just like the other casts: It takes the
value of `T' as an operand, converts the value to a `float*',
and yields the converted value as a result.
... which leads to two subordinate questions: (1a) What
is the value of `T'? and (1b) What value results from converting
it to a `float*'?
The identifier `T' refers to a two-dimensional array whose
elements are `float' values. Well, sort of: To be more exact,
`T' refers to a one-dimensional array whose elements are also
one-dimensional arrays, and those "inner" arrays have elements
that are `float' values. So `T' refers to an array of arrays
of `float'.
Now we encounter "The Rule:" In all but a few contexts,
using the name of an array in an expression is the same as
using a pointer to the array's first element. That is, when
you write `T' as the operand of the cast, it is just as if you
had written `&T[0]'. What is `T[0]'? It is the first element
of the array `T', namely, an "inner" array of four `float'.
So, what is `&T[0]'? A pointer to that four-element array.
What is the type of the implied expression `&T[0]'? Is it
`float*'? No, because `T[0]' is an array, not a `float'.
So the type of `&T[0]' is "pointer to array of four `float'
values."
So, writing `T' is equivalent to writing `&T[0]', and
that in turn is a pointer value that refers to four values
in adjacent memory locations. The `(float*)' cast converts
this value to a pointer of a different type: A pointer that
refers to just one `float' value, the first of the four in
the array `T[0]'. The converted value points to the same
memory location as the original (which is another reason the
change is hard to discern), but the extent of the thing it
points at is smaller: One value instead of four. As the
programmer you happen to know that three more values follow
this one, but the converted pointer addresses them one at a
time instead of all together.
(All that writing, and we're only now getting around to
Question 2! It's said that brevity is the soul of wit, so
I must be either witless or soulless ...)
Why convert the pointer value from one type to another?
Look at the Sum() function: It's first parameter is a `float*',
a pointer to a single `float' value. If you had tried to use
plain `T' as the corresponding argument, the compiler would
have protested: Writing `T' is the same as writing `&T[0]',
the type of that expression is "pointer to array of four
`float' values," and that is not the same as "pointer to a
single `float'." Since the argument type does not match the
parameter type and can't be converted automatically, the
compiler complains that you have provided an unusable argument.
This is usually a Good Thing: Try `fprintf("Hello, world!\n")'
and see how helpful it is when the compiler spots the error
for you.
But in this case, Sum() wants a pointer to the first
`float' in an array of `M*N' values. Writing `(float*)T'
supplies the needed conversion from "pointer to array" to
"pointer to `float'," and all is well. The Sum() function
treats its parameter as a pointer to the start of an array
of `M*N' values, adds them, and returns their sum. (In truth,
there's an error: The variable `S' is never initialized, so
it "holds garbage," and there's no telling what you'll get
when you start adding the `float' values to that garbage.
Inserting `S = 0;' will fix it.)
Finally, the un-asked question: Is this pointer-punning
a good idea? Technically, no: When Sum() steps smoothly from
the last element of `T[0]' to the first of `T[1]', it invokes
undefined behavior. It was given a pointer to the first value
in `T[0]', and it is free to use that pointer to access the
elements of `T[0]', but as soon as it attempts to access the
non-existent element `T[0][4]' it is using an index value that
is outside the given array. In principle, anything can happen.
... except that nothing (bad) ever does. There is no
`T[0][4]', but the memory slot it would occupy if it existed
is in fact present, and occupied by `T[1][0]', the first
`float' in `T[1]'. Technically, Sum() has walked off the
end of `T[0]' and fallen into uncharted waters, but in actual
practice it glides smoothly through the elements of `T[1]'
and `T[2]' without even a ripple. Treating an array that has
"internal structure" as if it were just a big undifferentiated
one-dimensional array is Technically Wrong, but is always done
and always works. Philosophers of programming languages might
trace the necessity for this sort of subterfuge to C's weak
support for arrays; I'm not that much of a philosopher. So go
ahead and use the suspect technique, remembering always to say
"Nudge, nudge, wink, wink" when you do.
--
Eric Sosman
esosman@xxxxxxxxxxxxxxxxxxxx
.
- References:
- Help a beginner - function with pointer ...
- From: bpascal123@xxxxxxxxxxxxxx
- Re: Help a beginner - function with pointer ...
- From: Nick Keighley
- Re: Help a beginner - function with pointer ...
- From: Keith Thompson
- Re: Help a beginner - function with pointer ...
- From: Eric Sosman
- Re: Help a beginner - function with pointer ...
- From: Keith Thompson
- [OT] Re: Help a beginner - function with pointer ...
- From: Eric Sosman
- Re: Help a beginner - function with pointer ...
- From: bpascal123@xxxxxxxxxxxxxx
- Help a beginner - function with pointer ...
- Prev by Date: Re: tutorials
- Next by Date: Re: tutorials
- Previous by thread: Re: Help a beginner - function with pointer ...
- Next by thread: Re: Help a beginner - function with pointer ...
- Index(es):
Relevant Pages
|