passing char arrays by reference

K

Kaz Kylheku

Ian Collins said:


A pointer is a reference to the object pointed to. See 3.1.2.5 of
C89 or 6.2.5 of C99.


Perhaps. And perhaps they simply don't bother to call a pointer a
reference because it's more idiomatic to call it a pointer.


To be precise, a pointer /is/ a reference.

Note that this does not mean that passing a pointer equates to pass
by reference. It doesn't. You can pass a reference in C, but you
can't pass /by/ reference!

Why not? If a pointer is a reference, we are passing the object itself by means
of that pointer. Ergo, by means of a reference. By reference, in short. In
English, we can shorten ``using'' or ``by means of'' to just ``by''.

``To die from the consequences of a wound inflicted by means of a sword'' is to
``die by sword''. See? To travel by means of an aircraft is to ``travel by
plane'', or ``fly''.

Now if I pay for something by means of a token carried on a plastic card,
connected to a credit card account of the VISA type, can I not call that
``paying by VISA?''

Or is it the case that I'm not, semantically, in fact paying? I'm just passing
a plastic card that is then returned to me, and signing some meaningless piece
of paper?

Is it the case that you can pass a credit card, but you can't pass payment /by/
credit card?

The way I see it, C pointers provide the means to implement a thorough
emulation of that which is known as pass-by-reference.

Some languages that have pass-by-reference have features in that mechanism
that we don't have in pointers. But are those key, defining features without
which it wouldn't be called pass-by-reference? Or are they refinements? E.g.
we can declare that some reference parameter is an ``out'', so that the
function will not access the value, but only store one. Therefore passing a
reference to an uninitialized variable is okay to an out parameter; and
accessing, inside the function, an out parameter without writing to it first,
is diagnosed. But can pass-by-reference exist without such a refinements?
(Moreover, could we not, in principle, add a qualifier to pointers to express
the same thing?)

Other than that, any pass-by-reference situation in a language that has
pass-by-reference can be expressed with C pointers.

Moreover, this can be done without any change in the level of abstraction, just
with a bit of syntactic sugar, like explicitly taking the address and
dereferencing, which we rather don't mind doing because it documents the shady
manipulation that is going on.

Adding some &'s and *'s doesn't change the level of abstraction.

I.e. what I'm claiming is not all like the argument that ``any behavior you get
with such and such high level feature, I feature X, I can perform in assembly
language''. This is at basically the same level.
 
R

Richard

Han from China said:
C is deceptive in its apparent simplicity.

It can be.

C *can* be a simple language in which you can write clear, maintainable
and efficient code.

The key is NOT to try to impress ISO C heads at the first step or listen
to half the nonsense spouted about pointers not being "values" and not
necessarily pointing to an area of memory.

Fire up a good debugger. Visual Studio maybe? gdb is excellent but
Google up a good tutorial - there are many out there.

Set a pointer to point to a block of memory from malloc or a block of
memory holding an array of integers.

Examine the pointer. Examine the contents of the memory at which the
pointer "points" (or references ....).

Create another pointer which is declared as pointing to some other type
of object like chars. Cast your original pointer to it. Now look at
the same mememory in the debugger. Get a feeling for what is happening.

Do NOT go too abstract too early.

A pointer is a simple tool to reference memory. You can dereference
(ha!) the pointer to get values from that memory.

Post increment the pointer. Watch it point to the next element
depenending on the type of the pointer (char* ? int *? double*?).

Simply do not not get bogged down - Think of WHY its there and what it
does on the general machine type. It saves you copying huge heaps of
memory around for a start and provides a convenient and efficient method
of accessing elements in memory.

The main advice I would give from seeing people struggle with pointers
for years is USE A DEBUGGER. Look a the values. Look at the memory. It
will become apparent in no time at all.
 
B

Ben Bacarisse

Kaz Kylheku said:
String passing has ``reference semantics'' in C, (understood by everyone to be
achieved by the use of pointers). Everyone with a reasonable background in
computing languages understands what this means.

Reference semantics means that you are passing around the object itself (by
means of the address which identifies/locates it) rather than copies.

The behavior in other newsgroups is different. The Lisp language has neither
pointers nor references. When some newbie is confused about passing semantics
in comp.lang.lisp, sometimes people explain it that his function is really
getting a pointer (or reference) to the object, so changing the object changes
the original, so that although strictly speaking, argument passing has value
semantics, the value acts as a reference, giving rise to reference semantics.

Nobody flames this with retarded comments like ``Oh yeah, well cite
the chapter and verse of the ANSI standard where references and
pointers are defined''. This is appears to be a uniquely c.l.c
disease.

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.
 
B

Bart

(e-mail address removed) said:
Firstly, your subject line suggests that you wish to pass by
reference. In C, however, all argument expressions are passed by
value.
Fortunately, this doesn't amount to a problem

Probably because in C it's impossible to pass an array by value, only
by reference.
 
R

Richard

Ben Bacarisse said:
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.

Your comments are fair enough.

But the term "de-reference" is very common. And when limiting to C I
dont see how saying "ptr references a block of memory" is anyway
confusing. Yes, you can convince yourself it is confusing if one wishes
to think of C++ etc, but even then I never really had the problem. It
seems, well, obvious to me in context.

My main grudge here is that people like to overly complicate
explanations to beginners frequently to show how much they know rather
than to impart knowledge.

To say a string ptr is a pass by value is one such thing that still has
me scratching my head despite 20 years of professional SW
development. Yes, yes, I know what is meant. I just dont see the need to
push it. But no one is interested in the parameter itself as a
value. The point is that it POINTS to (or references) something
elsewhere.
 
K

Keith Thompson

Richard Heathfield said:
Keith Thompson said:

Right. I was referring to clc::reference, not c++->reference.

Of course. My point is that the common use of the term "reference" in
a different context means that referring to C pointers as references,
even though the standard does so, is more likely to cause confusion
than referring to them as pointers.
Linked lists, I'll grant you - but pass-by-reference in C? This I
have to see. :)

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.
 
K

Kaz Kylheku

In C, yes. There are other contexts in which "pointer" and
"reference" mean different things. (I'm thinking of C++.)


Agreed. But another way to look at it is that passing by reference is
an abstract concept that C doesn't support directly, but you can
*implement* pass-by-reference in C by careful use of pointers.
Similarly, C doesn't directly support linked lists, but you can
implement linked lists by careful use of pointers.

I do not agree with the notion that if you merely take the address of something,
pass that to a function, and then dereference it inside the function, you are
``implementing'' pass by reference.

What you are doing is simply using a mechanism that is already implemented in
the language. The original implementor of it is Dennis Ritchie, not you nor I.

Taking the address and dereferencing it is a only a near minimal test-case for
these language features: exercising the unary & and *, in turn.

Here is an example of actually inventing a way to implement ``address off''
and ``dereference'' in a language that doesn't have these things:

Getting it not quite right, in 2004:
http://groups.google.com/group/comp.lang.lisp/msg/984ab01eb71d1192

Brushing the dust off pretty much the same thing in 2008:
http://groups.google.com/group/comp.lang.lisp/msg/291204c2b3af0549

Then in an immediate follow up, getting it right:
http://groups.google.com/group/comp.lang.lisp/msg/4976df2eab69ca5b
 
K

Keith Thompson

Bart said:
Probably because in C it's impossible to pass an array by value, only
by reference.

I'm now going to make the opposite of the argument I made a moment
ago.

(You can wrap an array in a struct and pass the struct by value, but
we'll ignore that.)

In C, it's impossible to pass an array as an argument *at all*. Some
aspects of the language syntax, unfortunately IMHO, try to hide this
fact. Given the following code:

int arr[10];
func(arr);

I know that what I'm actually passing is not arr, but the address of
arr's first element. I'm not even passing a pointer to the entire
array, so func has no way of knowing how long the array is unless you
tell it by other means.

This kind of thing is how you can implement, in C, what other
languages do by passing an array by reference. And it can be useful
to think of this as "passing an array by reference". But it's always
best to keep in mind what's really happening behind the scenes: you're
passing, by value, a pointer to (i.e., the address of) the array's
first element.

If you forget this, you're liable to do something like this:

void func(int arr[])
{
for (i = 0; i < sizeof arr / sizeof arr[0]; i ++) {
/* ... */
}
}

If you just think of arr being passed by reference, without
understanding *how* it's passed by reference, you can't even explain
why this is wrong.
 
K

Kaz Kylheku

Bart said:


Nope. All passing is by value. Since the value you get when you
evaluate an array name is a pointer to the array's first element,
you can't actually pass the array /at all/. What you pass is the
pointer. By value.

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!

If it wasn't passed, how is it being operated upon in two places of the program
at the same time?
 
B

Barry Schwarz

I'm a noob. Now that that is out of the way,
I want to pass an array of strings to a function:

snip

I hope you got enough useful responses before your thread got
hijacked.
 
B

Ben Bacarisse

Richard said:
Ben Bacarisse <[email protected]> writes:

Your comments are fair enough.

But the term "de-reference" is very common. And when limiting to C I
dont see how saying "ptr references a block of memory" is anyway
confusing. Yes, you can convince yourself it is confusing if one wishes
to think of C++ etc, but even then I never really had the problem. It
seems, well, obvious to me in context.

My main grudge here is that people like to overly complicate
explanations to beginners frequently to show how much they know rather
than to impart knowledge.

Again, I will ignore the sociology. The OP has had lots of helpful
answers. The group is working well in this case.
To say a string ptr is a pass by value is one such thing that still has
me scratching my head despite 20 years of professional SW
development. Yes, yes, I know what is meant. I just dont see the need to
push it. But no one is interested in the parameter itself as a
value. The point is that it POINTS to (or references) something
elsewhere.

The details matter in the specific case of this thread. The OP
returned and asked, in effect, about passing two strings to a function
that would then makes changes to them. This loose wording has two
meanings in C and unravelling what might be meant requires using the
right words. I think OP has gone, so I did not post a reply, but they
might have wanted something like:

void swap_str(char **s1, char **s2)
{
char *tmp = *s1;
*s1 = *s2;
*s2 = tmp;
}

or they might have wanted:

void swap_str(char *s1, char *s2)
{
char tmp[10]; /* the OP has 10 character arrays */
memcpy(tmp, s1, sizeof tmp);
memcpy(s1, s2, sizeof tmp);
memcpy(s2, tmp, sizeof tmp);
}

The phrase "passing a string by reference" is doubly confusing in C
and, I think, it helps to clarify the matter before answering.
 
B

Bart

Bart said:



Nope. All passing is by value. Since the value you get when you
evaluate an array name is a pointer to the array's first element,
you can't actually pass the array /at all/. What you pass is the
pointer. By value.

I'd imagine the OP and others would think of the value of an array as
the contents of all the elements of the array.

It's funny then that when you pass the array to a function that
modifies the elements of the array it's given, the original elements
are also modified!

Just as you might expect to happen in pass-by-reference, and unlike
what you might expect to happen (or not happen) in pass-by-value.

Technically you're probably correct, in terms of the parameter in
question being a copy of a pointer; modifying this won't change the
original array address in any way. But in this example it is the array
contents that are of interest.
 
K

Kaz Kylheku

Kaz Kylheku said:

The program design varies from program to program.

True, and so our regard for what is going on can vary from
program to program. Mental flexibility!

// No array-like semantics here!
set_to_42(int *p)
{
*p = 42;
}

...

// Hence, no array passing here! Just the first element is
// passed by reference.
int a[10];
set_to_42(a); // better expressed as set_to_42(&a[0]);

The design view of what is going on just as real, true and pertinent as
the level C mechanics in which it is expressed.

These views are not contradicting, nor incompatible, even if they use some of
the same words differently. You can hold these views simultaneously, and your
head will not explode.

Thinking is not merely a process of macro-replacing words with their
definitions and evaluating the resulting sentences.
 
K

Kaz Kylheku

The phrase "passing a string by reference" is doubly confusing in C
and, I think, it helps to clarify the matter before answering.

Yes it is, but it's only confusing because a string is, simultaneously,
understood to be a null-terminated array, as well as a pointer to the
first element of such an array.

So a reference to a string can be a pointer to that text, or a pointer to that
pointer.

The point is that although ``passing a string by reference'' may be confusing,
but it's not confusing due to the the words ``by'' and ``reference''.

``passing a pointer to a string'' is still confusing in exactly the same way.
Do you mean char * or char **?
 
P

Phil Carmody

Bart said:
Probably because in C it's impossible to pass an array by value, only
by reference.

I don't know if I'd go as far as to say "impossible". I seem
to remember seeing "how do I pass an array by value?", complete
with an answer, in one of the earliest C programming tutorials
I encountered.

Untested, not even compiled, but you get the idea:

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.
Sure, they aren't naked arrays, but the arrays in the struct
are being passed as much by value as the struct itself.

Phil
 
K

Keith Thompson

Kaz Kylheku said:
Yes it is, but it's only confusing because a string is, simultaneously,
understood to be a null-terminated array, as well as a pointer to the
first element of such an array.
[...]

Anyone who understands a string to be a pointer does not understand
what a string is in C.
 
I

Ian Collins

Richard said:
Ian Collins said:


A pointer is a reference to the object pointed to. See 3.1.2.5 of
C89 or 6.2.5 of C99.


Perhaps. And perhaps they simply don't bother to call a pointer a
reference because it's more idiomatic to call it a pointer.

Oops, I didn't expect to open such a big can of worms.

I spend a lot of time working with languages that do have references and
pass by reference, so I tend to differentiate clearly between
references and pointers.
To be precise, a pointer /is/ a reference.

Note that this does not mean that passing a pointer equates to pass
by reference. It doesn't. You can pass a reference in C, but you
can't pass /by/ reference!

Which was the original subject of both this post and this sub-thread
before it degenerated into an general pointer/reference flamefest.
 
R

Richard

Keith Thompson said:
Kaz Kylheku said:
Yes it is, but it's only confusing because a string is, simultaneously,
understood to be a null-terminated array, as well as a pointer to the
first element of such an array.
[...]

Anyone who understands a string to be a pointer does not understand
what a string is in C.

That is a simply ridiculous thing to say.

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.
 
K

Kaz Kylheku

Kaz Kylheku said:
Yes it is, but it's only confusing because a string is, simultaneously,
understood to be a null-terminated array, as well as a pointer to the
first element of such an array.
[...]

Anyone who understands a string to be a pointer does not understand
what a string is in C.

So that would then be the true source of this alleged confusion, right?

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.

Oh, here we go!


7.11.2.1 The localeconv function

...

The members of the structure [struct lconv] with type char *
are pointers to strings.

[ ... so far so good! ... ]

The members include the following:

[ ... ]

char *grouping
A string whose elements indicate the size of each group of
digits in formatted nonmonetary quantities.

Oops! Whoever wrote the first paragraph understood what a string is, but then
the rest was taken over by someone who didn't understand what a string is in C.

Here is another gem, in 7.21.4.5. Apparently, functions that take char * or
const char * arguments can be ``applied to strings'', rather than to pointers.

The transformation is such that if the strcmp function is applied to
two transformed strings, it returns a value greater than, equal to,
or less than zero, corresponding to the result of the strcoll function
applied to the same two original strings.

Maybe it's simply a very difficult task to produce a document written in
perfectly crisp, flawless standardese, from cover to cover.
 

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