passing char arrays by reference

J

jackassplus

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

int stuff(char some_string, int j){
strcpy("crap", some_string[j]);
j++;
return j;
}

int main(){
char a_string[10][10];
int i=0;
int result;
int j=0;
result = stuff(&a_string, &i);
printf("i=%i, j=%i, a_string=%s\n",i,j,a_string);
return 0;
}

the compiler tells me that j is not a string, and that argument 1 of
stuff is an incompatible pointer type. Why is that?
 
J

jackassplus

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

int stuff(char some_string, int j){
        strcpy("crap", some_string[j]);
        j++;
        return j;

}

int main(){
        char a_string[10][10];
        int i=0;
        int result;
        int j=0;
        result = stuff(&a_string, &i);
        printf("i=%i, j=%i, a_string=%s\n",i,j,a_string);
        return 0;

}

the compiler tells me that j is not a string, and that argument 1 of
stuff is an incompatible pointer type. Why is that?


sorry, just a clarification, the compiler tells me j is not an int.
 
B

Bart

I want to pass an array of strings to a function:

int stuff(char some_string, int j){
        strcpy("crap", some_string[j]);
        j++;
        return j;
}
int main(){
        char a_string[10][10];
        int i=0;
        int result;
        int j=0;
        result = stuff(&a_string, &i);
        printf("i=%i, j=%i, a_string=%s\n",i,j,a_string);
        return 0;
}


I modified your code to the following. I haven't a clue about complex
type declarations so I've used a typedef to help out:

typedef char tenchar[10];

int stuff(tenchar *some_string, int j){
strcpy(some_string[j],"crap");
j++;
return j;
}

int main(){
tenchar a_string[10];
int i=0;
int result;
int j=0;
result = stuff(a_string, i);
printf("i=%i, j=%i, a_string=%s\n",i,j,a_string);
return 0;
}

(The strcpy() functions works in reverse to what you had.)

If you don't like typedefs, look at RH's version.
 
R

Richard

Richard Heathfield said:
(e-mail address removed) said:


Two nits before we start:

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, but it's good
to get the terminology right as it helps to understand more clearly
what's actually going on.

Only in c.l.c

In C programming circles in the rest of the world passing a string by
reference is immediately obvious to all but the most anally retentive.
 
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:

How you do it depends on how the array of strings is defined. Two
obvious possibilities come to mind immediately:

1 - An array of arrays of char. Given appropriate values for
M and N, the array
char array_of_arrays[M][N];
can hold up to M strings, each of which can have a length between 0
and N-1, inclusive.

2 - An array of pointers to char. Given an appropriate value
for M, the array
char *array_of_pointers[M];
can hold up to M pointers to char, each of which can point to a
string. The declaration does not place any limit on the length of the
strings.

Your code below has problems.
int stuff(char some_string, int j){
strcpy("crap", some_string[j]);

Multiple problems here:

some_string is a char so you cannot apply a subscript to it.

If you change the type of some_string so that it does contain
or point to a string, then some_string[j] would be a char and that is
not a suitable second argument for strcpy.

If you change the type of some_string so that it does contain
an array of strings, your call to strcpy would attempt to replace the
string literal "crap" with the contents of the j-th string. Attempting
to modify a string literal invokes undefined behavior.
j++;
return j;
}

int main(){
char a_string[10][10];

The contents of a_string are uninitialized and therefore
indeterminate. Attempts in stuff to copy from this indeterminate data
do not produce well defined results. If there is no '\0' in the data,
strcpy will write all over memory, invoking undefined behavior. Even
if there is a '\0' in the data before strcpy overflows the target
location, you have no idea what data was copied.
int i=0;
int result;
int j=0;
result = stuff(&a_string, &i);

More problems here:

You are passing the address of a char[10][10] array to stuff.
For this to work, you need to declare the parameter in the definition
of stuff as char(*some_string)[10][10] and pass it as the second
argument to strcpy as (*some_string)[j].

This is unnecessarily cumbersome. If you remove the & from
the argument, you are passing the array to stuff. In most contexts
(use with the & operator as above being one of three exceptions), an
expression with array type is converted to the address of the first
element with type pointer to element type. In this case, the
expression a_string would be converted to &a_string[0]. You can then
declare the parameter in stuff as either char (*some_string)[10] or
the easier, to my mind, char some_string[10][10]. (Note: some prefer
the former because it more closely matches what is actually passed to
the function.) In either case, you pass it as the second argument to
strcpy simply as some_string[j].

You are also passing the address of i, which has type int*,
when the parameter is expecting an int. Since you use the int
directly in stuff, the obvious solution is to remove the &.
printf("i=%i, j=%i, a_string=%s\n",i,j,a_string);


While attempting to copy from a_string produces random or chaotic
results, attempting to print from it produces formally undefined
behavior.
return 0;
}

the compiler tells me that j is not a string, and that argument 1 of
stuff is an incompatible pointer type. Why is that?

You passed a char(*)[10][10] to a function that was expecting a simple
char. As noted, argument 2 is incompatible also.
 
I

Ike Naar

int stuff(char (*some_bunch_of_strings)[10], int j)
{
strcpy((some_bunch_of_strings)[j], "oh I see");
return ++j;
}

Just a nit: since the side effect of ++j is not used,
it's clearer to ``return j+1;'' instead of ``return ++j;''.

Newbies sometimes think of ``++j'' as a cool-looking shorthand for j+1,
which it is not.
 
K

Keith Thompson

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

int stuff(char some_string, int j){
strcpy("crap", some_string[j]);
j++;
return j;
}

int main(){
char a_string[10][10];
int i=0;
int result;
int j=0;
result = stuff(&a_string, &i);
printf("i=%i, j=%i, a_string=%s\n",i,j,a_string);
return 0;
}

the compiler tells me that j is not a string, and that argument 1 of
stuff is an incompatible pointer type. Why is that?


sorry, just a clarification, the compiler tells me j is not an int.

Since j is an int, I seriously doubt that your compiler told you it
wasn't. It's always best to copy-and-paste the exact error message.
If you don't understand what it means, it's not likely you'll be able
to paraphrase it in a way that lets us know what it means.

Here's what I get when I compile your code with gcc:

c.c: In function 'stuff':
c.c:2: warning: incompatible implicit declaration of built-in function 'strcpy'
c.c:2: error: subscripted value is neither array nor pointer
c.c: In function 'main':
c.c:12: warning: passing argument 1 of 'stuff' makes integer from pointer without a cast
c.c:12: warning: passing argument 2 of 'stuff' makes integer from pointer without a cast
c.c:13: warning: incompatible implicit declaration of built-in function 'printf'

The first thing you need to do is add these lines:
#include <stdio.h>
#include <string.h>
<stdio.h> gives you the declaration of printf; <string.h> gives you
the declaration of strcpy. Your compiler might let you get away with
omitting the #include directives, but they're really not optional.

After adding those lines, I get:

c.c: In function 'stuff':
c.c:5: error: subscripted value is neither array nor pointer
c.c: In function 'main':
c.c:15: warning: passing argument 1 of 'stuff' makes integer from pointer without a cast
c.c:15: warning: passing argument 2 of 'stuff' makes integer from pointer without a cast

where line 5 is the call to strcpy and line 15 is the call to stuff.

You need to read the documentation for strcpy. You have the arguments
in the wrong order.

And your call to stuff just doesn't make any sense. You've declared
it to take two arguments of type char (that's a single character, not
what you want) and int, but you're passing arguments of types
char(*)[10][10] and int*.

So let's back off and take a look at what you're trying to do. You
say you want to pass an array of strings to a function. C has no
string type; a "string" is a data format, not a data type. If you
want to pass a string to a function, you'll usually pass a pointer to
a string (which is really just a pointer to the first character of the
string). For example:

void print_string(char *s)
{
printf("s = \"%s\""\n", s);
}

...

print_string("hello");

But you want to pass "an array of strings". Well, you can't do that
directly, but there are several ways to do it indirectly. One way to
represent an "array of strings" is as an array of pointers, each of
which is of type char*. Each element of this array points to a
string.

Or you can have a two-dimensional array of char (or, equivalently, an
array of array of char), as you've tried to do here. Each row of the
array is an array of char which can contain a string. If you want to
pass one of these strings to print_string(), for example, you need to
obtain its address.

I suggest reading sections 4, 6, and 8 of the comp.lang.c FAQ,
<http://www.c-faq.com/>.
 
I

Ian Collins

Richard said:
Only in c.l.c

In C programming circles in the rest of the world passing a string by
reference is immediately obvious to all but the most anally retentive.

Even for you, that's bollocks. How can something the language doesn't
do be immediately obvious? You need to get out more.
 
J

jackassplus

(e-mail address removed) said:


Two nits before we start:

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, but it's good
to get the terminology right as it helps to understand more clearly
what's actually going on.

...
It's not clear what you intended main's j to be for.

By looking at this reply and the others that follow, I find that I
know less about pointers than I thought I did (which isn't much)
Furthermore, my little test program does not at all convey what I'm
trying to do.

Is there a way to pass two strings to a function, change them to two
new values, and have both of those values available to the scope from
whence they came?

If this makes no sense, I apologize.
 
J

jackassplus

Is there a way to pass two strings to a function, change them to two
new values, and have both of those values available to the scope from
whence they came?
If this makes no sense, I apologize.

Yes, but doing so does have risks.

Something as simple as

#include <stdio.h>
#include <string.h>

void stuff( char* data )
{
   strcpy(data, "oh I see");

}

int main(void)
{
   char a_string[10][10] = {0};

   stuff( a_string[0] );

   printf("a_string=%s\n", a_string[0]);

   return 0;

}

will change the value, but you have to make sure what you write is no
longer than the size of the original string.

That is exactly what I was trying to accomplish.
The rest of the answers do give me much to meditate on. Thanks
everyone!
 
R

Richard

Ian Collins said:
Even for you, that's bollocks. How can something the language doesn't
do be immediately obvious? You need to get out more.

Err, BECAUSE it does not support "C++ references" the meaning is
obviously clear.

If it is NOT clear to you then I suggest you take you own advice.

If in C someone says this is a reference to this here I know the thing
being talked about is a pointer to a block of memory (in laymans non
c.l.c speak).

Are you really telling me you would be confused if someone said ptr is a
reference to a 200k block of data?

Really?

I don't believe you.
 
H

Harold Aptroot

By looking at this reply and the others that follow, I find that I
know less about pointers than I thought I did (which isn't much)
Furthermore, my little test program does not at all convey what I'm
trying to do.

Is there a way to pass two strings to a function, change them to two
new values, and have both of those values available to the scope from
whence they came?

If this makes no sense, I apologize.

Well if you pass a pointer by value, you'd be passing whatever it points to
"by reference". Only unofficially though, and not in c.l.c
If you pass a string to a function (ie you pass a pointer to the beginning
of it to a function) you can change the contents and you can shorten it (by
setting some previously non-NUL chars to NUL) but you can't make it longer
or have it point to a different string. If you want to do that you'd have to
"pass a reference to the pointer". Ok, no. You'd pass a pointer to a pointer
to the first character in the string. Just be careful not to let the
original pointer slip away and cause a memory leak.
 
I

Ian Collins

Richard said:
If in C someone says this is a reference to this here I know the thing
being talked about is a pointer to a block of memory (in laymans non
c.l.c speak).

I admit to being a novice with only 28 years of C programming experience
in 3 countries, but I've never known anyone refer to a pointer as a
reference. Maybe the small subset of C programmers I've known have
known their arses from the elbows.
Are you really telling me you would be confused if someone said ptr is a
reference to a 200k block of data?

I wouldn't be confused, I'd correct their mistake. Programming relies
on accuracy of description as well as application.
 
S

Stefan Ram

Ian Collins said:
I've never known anyone refer to a pointer as a reference.

»A pointer type describes an object whose value provides
a reference to an entity of the referenced type.«

ISO/IEC 9899:1999 (E) 6.2.5 #20
 
J

jackassplus

Since j is an int, I seriously doubt that your compiler told you it
wasn't.  It's always best to copy-and-paste the exact error message.
If you don't understand what it means, it's not likely you'll be able
to paraphrase it in a way that lets us know what it means.

This is what it said:

C:\DJGPP\TEST_S~1>gcc -Wall -o pass_by_reference pass_by_reference.c
pass_by_reference.c: In function 'stuff':
pass_by_reference.c:6: error: array subscript is not an integer
pass_by_reference.c:8: warning: return makes integer from pointer
without a cast

pass_by_reference.c: In function 'main':
pass_by_reference.c:17: warning: passing argument 1 of 'stuff' from
incompatible
pointer type
 
K

Kaz Kylheku

Even for you, that's bollocks. How can something the language doesn't
do be immediately obvious? You need to get out more.

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

Kaz Kylheku

I admit to being a novice with only 28 years of C programming experience
in 3 countries, but I've never known anyone refer to a pointer as a
reference. Maybe the small subset of C programmers I've known have
known their arses from the elbows.

I know my arse from my elbow, even though you can squeeze a folded elbow
to resemble an arse. There is most definitely a concept of reference
semantics in computer science, which appears throughout the literator.

Now here is a pop quiz for you. From what document does this text fome from?

A pointer type may be derived from a function type, an object type, or an
incomplete type, called the referenced type. A pointer type describes an
object whose value provides a reference to an entity of the referenced type.
A pointer type derived from the referenced type T is sometimes called
"pointer to T". The construction of a pointer type from a referenced type is
called "pointer type derivation"

For bonus marks, identify the section and paragraph number, and count the
number of occurences of words that are "reference", or are derived from
that root!

Lastly, what are we doing when we take a pointer and put a * in front of a
pointer expression in order to gain access to the value that it points to?
Fill in the blank: we ``de _____ '' the pointer.

Come on, does this line of debate have any productive aim whatsoever?

Is this is what c.l.c should be about?
 
J

jackassplus

... I can assure
you that there are plenty of C programmers out there who are
writing exceptional pieces of software and who may not even have
a conscious appreciation of the trivia given in this thread. It's
mostly for language fanatics.

Yours,
Han from China

I think that if I can somehow fully grok pointers, the rest of the
language will just click.
Don't try to cram your head with too many subtle facts as you're
learning.

This is why I gave up x86 assembly...

Thanks for your guidance.

- Cory
 
K

Keith Thompson

Richard Heathfield said:
To be precise, a pointer /is/ a reference.

In C, yes. There are other contexts in which "pointer" and
"reference" mean different things. (I'm thinking of C++.)
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!

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.
 

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,680
Members
48,796
Latest member
Greg L.

Latest Threads

Top