passing char arrays by reference

K

Kenny McCormack

(KeithyWeithy burped up)
That is a simply ridiculous thing to say.

Yes, but that's what we expect from KeithyWeithy. He rarely disappoints.
I know loads of people who think of a string as primarily a pointer. OK,
to a nul terminated character array but there you go.

Of course. In the real world.
 
R

Richard

(KeithyWeithy burped up)

Yes, but that's what we expect from KeithyWeithy. He rarely disappoints.


Of course. In the real world.

I'll let you into a little secret. I am still bemused, confused and
shocked at the reaction from SOME c.l.c regs when I suggested I knew
what was meant by a pointer referencing something in C - or rather a
pointer being used to pass by reference. The extremes some of the
posters here will go to feign confusion because of some deep inner
desire to appear so hard core they can not understand mere mortals
suggests to me that a global culling is not far off. Darwin will out.
 
K

Kaz Kylheku

I don't want to comment on the sociology, but there is technical
matter that I find very useful. C has very simple function calling
semantics: formal parameters behave like objects that are initialised
with values, as if by assignment, at the point of call. Talking about
"passing by reference" may help some people understand (and if so
that's great) but I think it complicates something that is simple.

If it's so simple, why is it impossible a piece of software that parses a
header containing C function declarations, and generates, say, remote procedure
client and server stubs? Or cross-language foreign function calling glue?

That program would have to guess what the real semantics is, which is not
evident from the simple C semantics.

That's one reason why there exist interface definition languages in which
the semantics can be properly annotated. XDR, IDL, SWIG, ....

Maybe /people/ sometimes don't find the simple descriptions adequate for the
same reasons that a /machine/ cannot find them adequate. The information just
isn't there.

When we are discussing the interface, we must sometimes describe to each other
all that extra kind of stuff that gets annotated in interface description
languages.
 
B

Ben Bacarisse

Kaz Kylheku said:
If it's so simple, why is it impossible a piece of software that
parses a header containing C function declarations, and generates,
say, remote procedure client and server stubs? Or cross-language
foreign function calling glue?

It this a trick question? I was going to explain, but I see you know
perfectly well because you answer your own question later: "the
information just isn't there".
That program would have to guess what the real semantics is, which is not
evident from the simple C semantics.

That's one reason why there exist interface definition languages in which
the semantics can be properly annotated. XDR, IDL, SWIG, ....

Maybe /people/ sometimes don't find the simple descriptions adequate for the
same reasons that a /machine/ cannot find them adequate. The information just
isn't there.

When we are discussing the interface, we must sometimes describe to each other
all that extra kind of stuff that gets annotated in interface description
languages.

Yes, and since the language is so simple, we need extra annotations.
This is why, when you see an API with a struct xyz *, you hope there
will be a comment that explains if this points to an array or a single
item and if it is there to receive a result in the pointed to struct
or of that struct must be filled out prior to the call.

Since the call semantics are simple, I like to keep the explanation
simple. There is still a lot to be said about all the myriad uses to
which this simple mechanism can be put, but that is not reason, in my
option to complicate the description of the function call mechanism.
 
M

Mark Wooding

Kaz Kylheku said:
But you know what, I bet you I can find a slip-up in the C standard
where a char * object is informally referred to a string.

[And, indeed, you do.]
Maybe it's simply a very difficult task to produce a document written in
perfectly crisp, flawless standardese, from cover to cover.

Probably true. In this case, I think that, having made the distinction
perfectly clear, I'd just note that it's a convenient abuse of
terminology to describe a value of type pointer-to-character as if it
were actually a string rather than a pointer to the first character of
one, and then continue with the text unchanged.

This emphasizes the distinction, and that we understand it, while
allowing us the convenient shorthand that the terminology-abuse gives
us. Of course, if there is actually any confusion, we can retreat to
the more pedantic terms.

-- [mdw]
 
B

Barry Schwarz

You've already seen it thousands of times, I'm sure.

Here's a small C++ program which uses pass-by-reference at the
language level. (I use this only to illustrate the concept more
concretely than I could in English.)

#include <iostream>

void func(int& x) {
++x;
}

int main() {
int obj = 42;
std::cout << obj << "\n"; /* output is 42 */
func(obj);
std::cout << obj << "\n"; /* output is 43 */
return 0;
}

Here's an equivalent C program:

#include <stdio.h>

void func(int *x) {
++*x;
}

int main(void) {
int obj = 42;
printf("%d\n", obj); /* output is 42 */
func(&obj);
printf("%d\n", obj); /* output is 43 */
return 0;
}

Obviously the C language doesn't directly provide pass-by-reference.
But this program implements pass-by-reference *semantics* using C
pointers. The pointer is passed by value, of course, but obj is, in a
very real sense, passed by reference.

If you limit the term "pass-by-reference" to use of a built-in
language feature that provides it directly, then the C program doesn't
use pass-by-reference. And it's important to keep in mind that the
code is actually passing a pointer by value.

You could as easily say that a struct containing two doubles in a C90
program isn't really a complex number, or that a struct containing two
pointers isn't really a cons cell, as that a program that passes (by
value) a pointer to an object isn't really passing the object by
reference. And in all these cases, you'd be right, in a sense. But
I'd say that whether a feature is implemented by the compiler or in
user code can be less important than the fact that the feature is
implemented and used.

But you chose an example that works mainly because of its simplicity.
Let x and obj have type int[10], change the argument in C (or change
the type of x int(*)[10]) and set x[0] (or x[0][0] if necessary) to
the sizeof *x in C++ and C. While x will obviously refer to obj, it
won't be a reference in C.
 
B

Barry Schwarz

Compile and run

I'll play. Let's add just a little more code.
#include <stdio.h>
#include <string.h>
char a[] = "STD C";
char b[] = "FUBAR";
char c[] = "HEHAW";

void bar(char *w)
{
w = b;
printf("in bar *w =%s\n", w);

printf("in bar sizeof w is %d, sizeof *w is %d, "
"sizeof b is %d, sizeof *b is %d\n",
(int)sizeof w, (int)sizeof *w,
(int)sizeof b, (int)sizeof *b);
}

void normal(char *w)
{
strcpy(w, c);
printf("in normal *w =%s\n", w);

printf("in normal sizeof w is %d, sizeof *w is %d, "
"sizeof b is %c, sizeof *c is %d\n",
(int)sizeof w, (int)sizeof *w,
(int)sizeof c, (int)sizeof *c);
}

void foo(void)
{
char *ptr;
ptr = a;
bar(ptr);

Replace the above line with
bar(a);
printf("in foo sizeof a is %d, sizeof *a is %d, "
"sizeof ptr is %c, sizeof *ptr is %d\n",
(int)sizeof a, (int)sizeof *a,
(int)sizeof ptr, (int)sizeof *ptr);
/* what is ptr pointing at? */
/* if C is pass by value it is a */
/* if C is pass by reference it is b */
printf("in foo *ptr =%s\n", ptr);
/* bar can't change *ptr, but it could change its object */
normal(ptr);

Replace the above line with
normal(a);
printf("in foo sizeof a is %d, sizeof *a is %d, "
"sizeof ptr is %c, sizeof *ptr is %d\n",
(int)sizeof a, (int)sizeof *a,
(int)sizeof ptr, (int)sizeof *ptr);
printf("in foo *ptr =%s\n", ptr);
/* end of lesson */
}

int main(void)
{
foo();
return 0;
}

Since the same value gets passed to normal and bar (namely &a[0]), my
code changes shouldn't alter the validity of your conclusions.
 
K

Keith Thompson

Barry Schwarz said:
Here's a small C++ program which uses pass-by-reference at the
language level. (I use this only to illustrate the concept more
concretely than I could in English.) [snip]

Here's an equivalent C program:
[snip]

But you chose an example that works mainly because of its simplicity.

Of course.
Let x and obj have type int[10], change the argument in C (or change
the type of x int(*)[10]) and set x[0] (or x[0][0] if necessary) to
the sizeof *x in C++ and C. While x will obviously refer to obj, it
won't be a reference in C.

I was asked for an example. It would have been silly to pick one that
wouldn't work.
 
G

Guest

Keith Thompson said:


I suppose it depends on what you mean by "parameter", really. To a
simple soul such as myself, the parameter is the thing in the
parentheses - i.e. &obj. I read this as a pointer parameter, passed
by value.

I know you can look at it more metaishlier, but I actually think
it's useful to keep in the forefront of one's mind that pointers,
*like anything else*, are passed by value. When people "learn" that
pointers are C's way of passing by reference, very often (in my
experience) they see the * as a magic star that makes it possible
to modify the pointer itself:

void foo(char *p)
{
  p = malloc(n);

}

and code like this you should be wary of

void bar (void)
{
Some_type *pippo;
process_thingy(pippo);
}

it might be ok, but it looks scarey
 
J

John Bode

That's ridiculous. Of course you are passing the array. That's the true
/semantics/ of what you are doing. The program design, as it were.

See, you have this array up here in this parent function, and then
later down here in the child function, surprise, you are working with
that very same object!

Except that child function doesn't see the "array-ness" of the object
passed to it (modulo wrapping it in a struct or some similar
workaround), and that's where we disagree on the *semantics" of what
we're doing. To me, the *semantics* of passing an array (by value
*or* by reference) means that both the caller and the called function
see the same array *type*, and that both the caller and the called
function can perform the exact same operations on the array object and
get the exact same results.
If it wasn't passed, how is it being operated upon in two places of the
program at the same time?

What's getting passed isn't an array object, but an address to an
array object. For some purposes (such as subscripting), I can treat
it as though it were an array and get the same result. But for other
purposes (such as using sizeof to determine the array size), I can't.
That's why we always have to pass the array size as a separate
parameter, because the child function doesn't see an array type.

At the end of the day, what we're doing is *faking* pass-by-reference
semantics (sometimes well, sometimes poorly), and I don't think it's
being overly nit-picky to point that out.
 
K

Kaz Kylheku

Phil Carmody said:

typedef struct { char a[5]; char b[6]; } twoArrays;
void foo(twoArrays x);
twoArrays ta={"asdf","qwert"};
foo(ta);

Et voila - not just one, but two arrays being passed by value.

Yes, yes, very good - except that what you're really passing by
value in a struct.
Sure, they aren't naked arrays, but the arrays in the struct
are being passed as much by value as the struct itself.

C&V, please.

The first three uses of ``pass'' occur in non-normative footnotes and examples.
It is not defined anywhere. One example uses it to talk about passing
functions!

6.9.1 Function definitions
[ ... ]
EXAMPLE 2 To pass one function to another, one might say [ ... ]

Then there is this curiosity:

7.1.4 [ ... ] If a function argument is described as being an array, the
pointer actually passed to the function shall have a value such that all
address computations and accesses to objects (that would be valid if the
pointer did point to the first element of such an array) are in fact valid.

Hmm, so library function arguments may be described as arrays, when it's
convenient to do, even though there is no such thing! There is to be a blanket
understanding that if, like the C programmers that we, we slip up in this
International Standard and write array, we mean pointer, damn it!

7.11.1.1 [ ... ] Other implementation-defined strings may be passed as the
second argument to setlocale.

No comment.

7.15.1.4 The va_start macro
[ ... ]
6 EXAMPLE The function f1 gathers ... then passes the array as a single
argument.

Is this excused by 7.1.4?

Also, I have found a large number of occurences (in normative text) of
language like ``the array pointed at by s1'', when in fact s1 points to the
first element of the array.

Like fishing in a barrel with a shotgun.
 
P

Phil Carmody

Richard Heathfield said:
Phil Carmody said:

typedef struct { char a[5]; char b[6]; } twoArrays;
void foo(twoArrays x);
twoArrays ta={"asdf","qwert"};
foo(ta);

Et voila - not just one, but two arrays being passed by value.

Yes, yes, very good - except that what you're really passing by
value in a struct.
Sure, they aren't naked arrays, but the arrays in the struct
are being passed as much by value as the struct itself.

C&V, please.

I refer you to the honourable, and infallable, Richard Heathfield
who has recently claimed that they were indeed being passed by
value. You want a more precice reference? About 10 lines up - look
for the words "passing by value".

You really can be a dick sometimes, Richard.

Phil
 
R

Richard

Richard Heathfield said:
Phil Carmody said:
Richard Heathfield said:
Phil Carmody said:

<snip>

typedef struct { char a[5]; char b[6]; } twoArrays;
void foo(twoArrays x);
twoArrays ta={"asdf","qwert"};
foo(ta);

Et voila - not just one, but two arrays being passed by value.

Yes, yes, very good - except that what you're really passing by
value in a struct.

Sure, they aren't naked arrays, but the arrays in the struct
are being passed as much by value as the struct itself.

C&V, please.

I refer you to the honourable, and infallable, Richard Heathfield
who has recently claimed that they were indeed being passed by
value. You want a more precice reference? About 10 lines up - look
for the words "passing by value".

It is perhaps inevitable, given the few typographical errors I make,
that when I *do* make such an error it is not actually noticed. I
meant to say: "what you're really passing by value *is* a struct".
Arrays are not structs, and structs are not arrays.
You really can be a dick sometimes, Richard.

I think that's an over-reaction. My position has been consistent,
even if my typing hasn't been.

And good programmers don't do buffer over runs, and good programmers are
still right even when they type the opposite of what they meant on a
subject they maintained was really clear cut and "obvious".

One could not make this up.
 
K

Kaz Kylheku

Richard Heathfield said:
Phil Carmody said:

typedef struct { char a[5]; char b[6]; } twoArrays;
void foo(twoArrays x);
twoArrays ta={"asdf","qwert"};
foo(ta);

Et voila - not just one, but two arrays being passed by value.

Yes, yes, very good - except that what you're really passing by
value in a struct.
Sure, they aren't naked arrays, but the arrays in the struct
are being passed as much by value as the struct itself.

C&V, please.

I refer you to the honourable, and infallable, Richard Heathfield
who has recently claimed that they were indeed being passed by
value. You want a more precice reference? About 10 lines up - look
for the words "passing by value".

Ah, but then, you see, you are not passing the array, just the struct!

....

And now ladies and gentleman, we present the winner of the Biggest Pedant of
comp.lang.c for 2008. Pass the envelope please.
...
What's this? The envelope was passed, and it contains a piece of paper
with a name, but, [chuckle], that name was not passed to me!

Asking for the envelope to be passed rather than the name was a trick
of showmanship, which demonstrates who truly deserves this award.

I, your host for tonight's annual Mental Inflexibility Awards 2008, am in
fact the winner.

[ standing ovation ]

:)
 
P

Phil Carmody

Richard Heathfield said:
Phil Carmody said:
Richard Heathfield said:
Phil Carmody said:

<snip>

typedef struct { char a[5]; char b[6]; } twoArrays;
void foo(twoArrays x);
twoArrays ta={"asdf","qwert"};
foo(ta);

Et voila - not just one, but two arrays being passed by value.

Yes, yes, very good - except that what you're really passing by
value in a struct.

Sure, they aren't naked arrays, but the arrays in the struct
are being passed as much by value as the struct itself.

C&V, please.

I refer you to the honourable, and infallable, Richard Heathfield
who has recently claimed that they were indeed being passed by
value. You want a more precice reference? About 10 lines up - look
for the words "passing by value".

It is perhaps inevitable, given the few typographical errors I make,
that when I *do* make such an error it is not actually noticed. I
meant to say: "what you're really passing by value *is* a struct".
Arrays are not structs, and structs are not arrays.

And what is passed in that struct?
I think that's an over-reaction. My position has been consistent,
even if my typing hasn't been.

Maybe you ought to reconsider your position.

Phil
 
C

CBFalconer

.... snip ...

and code like this you should be wary of

void bar(void) {
Some_type *pippo;
process_thingy(pippo);
}

it might be ok, but it looks scarey

I see no way in which it could be 'ok'.
 
C

CBFalconer

John said:
.... snip ...


What's getting passed isn't an array object, but an address to an
array object. For some purposes (such as subscripting), I can
treat it as though it were an array and get the same result. But
for other purposes (such as using sizeof to determine the array
size), I can't. That's why we always have to pass the array size
as a separate parameter, because the child function doesn't see
an array type.

To me, a 'pass by reference' (in systems that implement this)
simply implies that the called function can modify that argument.
Not 'what that argument points to'. While there really is a
pointer in the argument, it can't be modified, as can a passed
pointer.

This leads to confusion, as when attempting to pass a constant.
The user has to put that constant in a variable, then pass that.
It is largely cleared up in such languages as Pascal, by using the
VAR attribute on the parameter.
 
G

Guest

(e-mail address removed) wrote:

... snip ...




I see no way in which it could be 'ok'.


well I have to bend the definition of 'ok'
a bit :)

void process_thingy (Some_type *pippo)
{
pippo = malloc(sizeof(*pippo));
process (pippo);
free(pippo);
}

well that's not really 'ok', but it doesn't
actually break!

Some_type *pippo;

void bar(void)
{
pippo = process_thingy(pippo);
}


Some_thing *process_thingy (Some_type *pippo)
{
if (pippo == NULL)
pippo = malloc(sizeof(*pippo));
process (pippo);
}

which is a bit of a rewrite of the original code!
 
T

Tim Rentsch

Kaz Kylheku said:
Phil Carmody said:

typedef struct { char a[5]; char b[6]; } twoArrays;
void foo(twoArrays x);
twoArrays ta={"asdf","qwert"};
foo(ta);

Et voila - not just one, but two arrays being passed by value.

Yes, yes, very good - except that what you're really passing by
value in a struct.
Sure, they aren't naked arrays, but the arrays in the struct
are being passed as much by value as the struct itself.

C&V, please.

The first three uses of ``pass'' occur in non-normative footnotes and examples.
It is not defined anywhere. One example uses it to talk about passing
functions!

6.9.1 Function definitions
[ ... ]
EXAMPLE 2 To pass one function to another, one might say [ ... ]

Surely this usage can be understood in this informal context, in
much the same way that might speak of "calling a function" instead
of the more technically accurate "call through a pointer to function."

Then there is this curiosity:

7.1.4 [ ... ] If a function argument is described as being an array, the
pointer actually passed to the function shall have a value such that all
address computations and accesses to objects (that would be valid if the
pointer did point to the first element of such an array) are in fact valid.

Hmm, so library function arguments may be described as arrays, when it's
convenient to do, even though there is no such thing! There is to be a blanket
understanding that if, like the C programmers that we, we slip up in this
International Standard and write array, we mean pointer, damn it!

Parameters for library functions are specified as arrays by using
the [] syntax in the prototypes of their respective functions.
The usage here is no different than that for ordinary function
parameters and arguments. Since there is a specific technical
basis for the usage (ie, the semantics of how parameters
specified with array type are handled), I would expect most
readers familiar with this aspect of C to understand both the
usage and the basis for it.

7.15.1.4 The va_start macro
[ ... ]
6 EXAMPLE The function f1 gathers ... then passes the array as a single
argument.

Is this excused by 7.1.4?

Also, I have found a large number of occurences (in normative text) of
language like ``the array pointed at by s1'', when in fact s1 points to the
first element of the array.

Like fishing in a barrel with a shotgun.

Some people enjoy being deliberately obtuse -- I admit, I do
myself, on occasion. In my own case, I like to think that when I
do, some compensating advantage (eg, humor value) is offered in
exchange for the obtuseness.
 

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

Forum statistics

Threads
474,432
Messages
2,571,682
Members
48,796
Latest member
Greg L.

Latest Threads

Top