Pass by reference?

P

__PaTeR

I have a var in function main. I want to change its value... just
passing it in a new function. Following the faqs, i found out that c
only passes arguments by value, not by reference. I build up this code
to make things work.


void f(char **ipp) {
static char *b = "B";
printf("f %x %x %x\n", &ipp, ipp, *ipp);
printf("f %x %x %x\n", &b, b, *b);
*ipp = b;
printf("f %x %x %x\n", &ipp, ipp, *ipp);
}

int main() {
char *a = "A";
printf("%x %x %x\n", &a, a, *a);
f(&a);
printf("%x %x %x\n", &a, a, *a);
}

it works... but there are few things i still don't understand. this
function has as argument the address of the pointer to the stack
address of the string... in function "f" i just overwrite the value of
the a variable ( that is the pointer to the stack address ) with the
address of string stored where b points to.

No doubts in this... but i wrote another code that i don't know why it
doesn't work:

void g(char *ipp)
{
int *g = &ipp;
printf("g %x %x %x\n", &g, g, *g);
memset(*g, 'B', 1);
printf("g %x %x %x\n", &g, g, *g);
}

int main() {
char *a = "A";
printf("%x %x %x\n", &a, a, *a);
g(a);
printf("%x %x %x\n", &a, a, *a);
}

this time i pass the value. As far as i know, when you create a
string, for example

char *a = "HELLO";

you have this:
a = a pointer to the first char of the string in the stack
*a = the first char itself
&a = the address where the stack address for "H" is stored.

So, if i pass as argument simply "a", i should pass the address of the
string start in the stack. In effect, i pass that. So, continuing, i
assign the pointer to an int value... Now, "g" contains the pointer to
the start address.

In the function "f", i modified the pointer value... now i'm trying to
modify directly the data... why does it go in segmentation fault?
 
K

Kenny McCormack

__PaTeR said:
it works... but there are few things i still don't understand. this
function has as argument the address of the pointer to the stack
address of the string... in function "f" i just overwrite the value of
the a variable ( that is the pointer to the stack address ) with the
address of string stored where b points to.

<Beavis and Butthead>

He said "stack"!

</Beavis and Butthead>

Word to the wise: You are not allowed to use "the S word" in this
newsgroup. One or more of the regulars will be showing up at your
doorstep within the hour to "discuss" this matter with you personally.
 
B

Barry Schwarz

I have a var in function main. I want to change its value... just
passing it in a new function. Following the faqs, i found out that c
only passes arguments by value, not by reference. I build up this code
to make things work.


void f(char **ipp) {
static char *b = "B";

Your program does not depend on b being static. It only requires that
the object b points to have a life span that extends beyond the end
the function f.
printf("f %x %x %x\n", &ipp, ipp, *ipp);

This invokes undefined behavior. The three variadic arguments are all
pointers. %x requires an unsigned int. If you want to print
pointers, use %p and cast the pointer values to void*.
printf("f %x %x %x\n", &b, b, *b);

Here also but only for the first two variadic arguments.
*ipp = b;

ipp contains the address of a in main. *ipp evaluates to the object a
in main. This changes the value in that object from its current value
(pointing to the string literal "A") to point to the string literal
"B".
printf("f %x %x %x\n", &ipp, ipp, *ipp);
}

int main() {
char *a = "A";
printf("%x %x %x\n", &a, a, *a);
f(&a);
printf("%x %x %x\n", &a, a, *a);
}

it works... but there are few things i still don't understand. this

That is extremely unfortunate. One of the worst manifestations of
undefined behavior is to do what is expected.
function has as argument the address of the pointer to the stack
address of the string... in function "f" i just overwrite the value of

Probably not. String literals have static duration. Consequently,
even those systems which use a stack for automatic variables (not all
do) usually don't store static objects on the stack.
the a variable ( that is the pointer to the stack address ) with the
address of string stored where b points to.

No doubts in this... but i wrote another code that i don't know why it
doesn't work:

void g(char *ipp)
{
int *g = &ipp;

This requires a diagnostic. There is no implicit conversion between
char** (the type of &ipp) and int* (the type of g). If you add the
cast, it could still invoke undefined behavior if ipp is not properly
aligned for an int.
printf("g %x %x %x\n", &g, g, *g);
memset(*g, 'B', 1);

This stores the value 'B' in the first byte of ipp, not in what ipp
points to.
printf("g %x %x %x\n", &g, g, *g);
}

int main() {
char *a = "A";
printf("%x %x %x\n", &a, a, *a);
g(a);
printf("%x %x %x\n", &a, a, *a);
}

this time i pass the value. As far as i know, when you create a
string, for example

char *a = "HELLO";

you have this:
a = a pointer to the first char of the string in the stack

Usually not if the string is a string literal.
*a = the first char itself
&a = the address where the stack address for "H" is stored.

The address of a (which contains the address of the 'H').
So, if i pass as argument simply "a", i should pass the address of the
string start in the stack. In effect, i pass that. So, continuing, i
assign the pointer to an int value... Now, "g" contains the pointer to

No you didn't. When you called the function, the compiler generated
code to copy the value of a (the address of the 'H') to an automatic
object called ipp. What you did was assign the address of ipp (not
the address of the 'H') to an int* (not an int).
the start address.

Nope, g contains the address of ipp.
In the function "f", i modified the pointer value... now i'm trying to
modify directly the data... why does it go in segmentation fault?

At no point does g() attempt to modify the string literal pointed to
by a in main.

If your code did what you wanted it to, it would invoke undefined
behavior. You cannot modify the value of a string literal. On
systems which store string literals in read only memory, attempting to
modify one would cause a memory access failure (possibly called a
segmentation fault). Unfortunately, you code is so full of undefined
behavior that a segmentation fault may be the best possible result.
 
B

Ben Bacarisse

Barry Schwarz said:
This requires a diagnostic. There is no implicit conversion between
char** (the type of &ipp) and int* (the type of g). If you add the
cast, it could still invoke undefined behavior if ipp is not properly
aligned for an int.


This stores the value 'B' in the first byte of ipp, not in what ipp
points to.

I don't think so (though, of course, all the conversions are
implementation defined so who knows). If you replace g with the right
type, so can see what is likely to happen:

char **g = &ipp;
memset(*g, 'B', 1);

Provided that the OP's implementation converts char ** to int * and
int to void * in some value-preserving way, then this is just a
complicated way to write:

ipp[0] = 'B';

and thereby violate the rule about modifying string literals (or at
least the arrays they give rise to).
 
P

__PaTeR

Mmm... i have some doubts then: which are the differences between:

char ciao[] = "LOL"

and

char *ciao = "LOL"

?

--- simple program ---

int main() {
char a[4] = "ASD";
char *b = "LOL";

return 0;
}


--- GDB examination:
g0d@g0d-desktop:~/Projects/8.Server$ gdb -q test
(gdb) break 5
Breakpoint 1 at 0x80483ad: file test.c, line 5.
(gdb) break 6
Breakpoint 2 at 0x80483b4: file test.c, line 6.
(gdb) run
Starting program: /home/g0d/Projects/8.Server/test

Breakpoint 1, main () at test.c:5
5 char *b = "LOL";
(gdb) print &a
$1 = (char (*)[4]) 0xbfc2e950
(gdb) print a
$2 = "ASD"
(gdb) print *a
$3 = 65 'A'
(gdb) x/5x $1
0xbfc2e950: 0x00445341 0xbfc2e970 0xbfc2e9c8 0xb7eba685
0xbfc2e960: 0x080483e0
(gdb) x/s $1
0xbfc2e950: "ASD"
(gdb) cont
Continuing.

Breakpoint 2, main () at test.c:7
7 return 0;
(gdb) print &b
$4 = (char **) 0xbfc2e94c
(gdb) print b
$5 = 0x8048490 "LOL"
(gdb) print *b
$6 = 76 'L'

Aren't the 2 statements the same?? i thought they were...
 
P

__PaTeR

Mmm... i have some doubts then: which are the differences between:

char ciao[] = "LOL"

and

char *ciao = "LOL"

?

--- simple program ---

int main() {
        char a[4] = "ASD";
        char *b = "LOL";

        return 0;

}

--- GDB examination:
g0d@g0d-desktop:~/Projects/8.Server$ gdb -q test
(gdb) break 5
Breakpoint 1 at 0x80483ad: file test.c, line 5.
(gdb) break 6
Breakpoint 2 at 0x80483b4: file test.c, line 6.
(gdb) run
Starting program: /home/g0d/Projects/8.Server/test

Breakpoint 1, main () at test.c:5
5               char *b = "LOL";
(gdb) print &a
$1 = (char (*)[4]) 0xbfc2e950
(gdb) print a
$2 = "ASD"
(gdb) print *a
$3 = 65 'A'
(gdb) x/5x $1
0xbfc2e950:     0x00445341      0xbfc2e970      0xbfc2e9c8      0xb7eba685
0xbfc2e960:     0x080483e0
(gdb) x/s $1
0xbfc2e950:      "ASD"
(gdb) cont
Continuing.

Breakpoint 2, main () at test.c:7
7               return 0;
(gdb) print &b
$4 = (char **) 0xbfc2e94c
(gdb) print b
$5 = 0x8048490 "LOL"
(gdb) print *b
$6 = 76 'L'

Aren't the 2 statements the same?? i thought they were...

omg... i wrote a crap... forget my last post... char *b should have a
pointer as value... sry
 
J

James Kuyper

__PaTeR said:
Mmm... i have some doubts then: which are the differences between:

char ciao[] = "LOL"

This statement creates an array of 4 chars named ciao, initialized with
the values {'L', 'O', 'L','\0'}.

It has been argued that a strict reading of the standard implies that it
also creates a separate, unnamed array of the same length with the same
contents; but since there's no portable way for user code to access that
other array, the "as if' rule allows an implementation to leave it out.
and

char *ciao = "LOL"

That creates an unnamed array of 4 chars, initialized with the values
{'L', 'O', 'L', '\0'}. It also creates an object of the type 'pointer to
char' with the name 'ciao', initialized to point at the first element of
the unnamed array. In this case, the unnamed array cannot be left out,
because the user code has a way to access it, through that pointer.
 
B

Barry Schwarz

Barry Schwarz said:
This requires a diagnostic. There is no implicit conversion between
char** (the type of &ipp) and int* (the type of g). If you add the
cast, it could still invoke undefined behavior if ipp is not properly
aligned for an int.


This stores the value 'B' in the first byte of ipp, not in what ipp
points to.

I don't think so (though, of course, all the conversions are
implementation defined so who knows). If you replace g with the right
type, so can see what is likely to happen:

char **g = &ipp;
memset(*g, 'B', 1);

Provided that the OP's implementation converts char ** to int * and
int to void * in some value-preserving way, then this is just a
complicated way to write:

ipp[0] = 'B';

and thereby violate the rule about modifying string literals (or at
least the arrays they give rise to).

Obviously I was still thinking in terms of function f(). Thanks for
catching that.

To the OP: Attempting to modify the string literal does explain the
segmentation fault.
 

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
473,981
Messages
2,570,188
Members
46,731
Latest member
MarcyGipso

Latest Threads

Top