Reassigning array to string literal

S

songkv

Hi,
I am trying to reassign an array of char to a string literal by
calling a function.
In the function I use pointer-to-pointer since I want to reassign the
"string array pointer" to the string literal.
But the second printf seems to give me garbage.
Any advise on what I am doing wrong?

Thanx

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>

static char *b = "This is a test";

int main( int argc, char **argv ) {

char a[10] = "abc";
int x;

printf( "1st : a = %s*\n", a );
call(&a);
printf( "2nd : a = %s*\n", a );

}

int call( char **input ) {


*input = b;
return 0;
}
 
U

user

Hi,
I am trying to reassign an array of char to a string literal by
calling a function.
In the function I use pointer-to-pointer since I want to reassign the
"string array pointer" to the string literal.
But the second printf seems to give me garbage.
Any advise on what I am doing wrong?

Thanx

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>

static char *b = "This is a test";

int main( int argc, char **argv ) {

char a[10] = "abc";

to get correct output, you could try this

char *a = "abc";
int x;

printf( "1st : a = %s*\n", a );
call(&a);
printf( "2nd : a = %s*\n", a );

}

int call( char **input ) {


*input = b;

Here 'a' is constant and can not appear as a Lvalue. Thus, this is a
undefined behavior. am I correct?
 
K

Kevin Goodsell

Hi,
I am trying to reassign an array of char to a string literal by
calling a function.

Arrays cannot be assigned to. They are non-modifiable lvalues.
Individual elements of an array can be assigned to, though.
In the function I use pointer-to-pointer since I want to reassign the
"string array pointer" to the string literal.

It doesn't work that way. Types don't magically change to what you want
them to be. If you pass type A to a function, the function will not
receive type B under any circumstances. In your code, you lied about the
argument type the function expected and passed it a type that didn't
match the type the function thought it was receiving.
But the second printf seems to give me garbage.

That's a perfectly valid result, under the circumstances.
Any advise on what I am doing wrong?

You are invoking undefined behavior.

First, here are the diagnostics issued by my compiler (gcc using a
custom set of warning options):

"C:\cygwin\bin\gcc.exe" -W -Wall -Wcast-align -Wwrite-strings
-Wno-sign-compare -Wno-unused-parameter -Wpointer-arith -ansi
-pedantic-errors -ggdb -c fun.c
fun.c:5: error: initialization discards qualifiers from pointer target type
fun.c: In function `main':
fun.c:13: warning: implicit declaration of function `call'
fun.c:10: warning: unused variable `x'
Terminated with exit code 1
#include <errno.h>
#include <stdio.h>
#include <stdlib.h>

You don't seem to be using anything from said:
static char *b = "This is a test";

This is the source of the first error. String literals are
non-modifiable, but a dangerous and archaic language feature allows a
string literal to be assigned to a (non-const) char pointer. Doing so is
almost always a mistake, because it allows you to attempt to modify the
string literal through that pointer, and the compiler is generally not
able or required to warn you about it. I use -Wwrite-strings in order to
receive a diagnostic when this dangerous feature is used.
int main( int argc, char **argv ) {

char a[10] = "abc";
int x;

'x' is not used.
printf( "1st : a = %s*\n", a );
call(&a);

'call' is not declared. Calling an undeclared function is a bad idea,
and no longer valid under the latest standard. You should always have a
declaration (specifically, a prototype) in scope before calling any
function. Because you did not, 'call' was implicitly declared, and that
implicit declaration does not match the function's real signature.

When I added a prototype for 'call', the following diagnostic was added:

fun.c:15: error: passing arg 1 of `call' from incompatible pointer type

The expression &a has type char (*)[10] (pointer to array[10] of char).
This is a completely different type from char ** (pointer to pointer to
char).
printf( "2nd : a = %s*\n", a );

Wouldn't hurt to add:

return 0;
}

int call( char **input ) {


*input = b;

What did you expect this to do? If you passed it the address of a char
pointer, it would make that pointer point to the string literal, but it
would still be dangerous because it makes a non-const pointer point to a
non-modifiable object (the string literal). If you fixed b's declaration:

static const char * const b = "This is a test";

(Second const added for good measure - it's not needed to avoid the
problem in question, but seems to be what was intended anyway.)

Now the compiler will diagnose this assignment because it loses a
'const' qualifier.
return 0;
}

What do you really want to do? You can always make a char pointer point
to a different string if you want to (but it better be a const char * if
you want it to point to a string literal):

const char *string1 = "This is the first string.";
const char *string2 = "This is the second string.";
const char *p = string1;
/* ... */
p = string2;

And you can store a string into an array of char:

char array[100] = "This is the initial string.";
/* ... */
strcpy(array, string1);

That will copy the string "This is the first string." into 'array'.
#include <string.h> for strcpy, and make sure you have enough space in
the destination array for the entire string, including the null character.

-Kevin
 
B

Barry Schwarz

Hi,
I am trying to reassign an array of char to a string literal by
calling a function.
In the function I use pointer-to-pointer since I want to reassign the
"string array pointer" to the string literal.
But the second printf seems to give me garbage.
Any advise on what I am doing wrong?

Thanx

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>

static char *b = "This is a test";

int main( int argc, char **argv ) {

char a[10] = "abc";
int x;

printf( "1st : a = %s*\n", a );
call(&a);

The only reason this does not generate a diagnostic is because you did
not include a prototype of call() in scope before you called the
function. If you had, you would have been informed that the argument
&a is not of type char** as required by call(). It is in fact of type
char(*)[10].

See for yourself. Place the following before the start of main():
int call(char**);
printf( "2nd : a = %s*\n", a );

Now that you have invoked undefined behavior, this can result in
anything. What I suspect happened is that call() has assembly code of
the form:

pick up sizeof(char*) bytes of data starting at the address input
points to
treat these bytes as a char* /*this value is the address of a*/
compute the address of b
store this computed value in the sizeof(char*) bytes starting
with the first byte of a /*as determined by step 2 above*/

If sizeof(char*) on your system is 2, then this replaces the first two
bytes of a (the 'a' and the 'b') with whatever two bytes form the
address of b. If sizeof(char*) is 4, it also replaces the 3rd and 4th
characters (the 'c' and the first '\0'). In either case, you still
have an array of char which is terminated by a '\0' so it is a
"string." Whether or not the bytes in the string are printable is a
matter of luck regarding the address of b and your character set.
}

int call( char **input ) {


*input = b;
return 0;
}



<<Remove the del for email>>
 
B

Barry Schwarz

Hi,
I am trying to reassign an array of char to a string literal by
calling a function.
In the function I use pointer-to-pointer since I want to reassign the
"string array pointer" to the string literal.
But the second printf seems to give me garbage.
Any advise on what I am doing wrong?

Thanx

#include <errno.h>
#include <stdio.h>
#include <stdlib.h>

static char *b = "This is a test";

int main( int argc, char **argv ) {

char a[10] = "abc";

to get correct output, you could try this

char *a = "abc";
int x;

printf( "1st : a = %s*\n", a );
call(&a);
printf( "2nd : a = %s*\n", a );

}

int call( char **input ) {


*input = b;

Here 'a' is constant and can not appear as a Lvalue. Thus, this is a
undefined behavior. am I correct?

Nope. a is not a constant. a is a pointer that points to data which
should be treated as constant. (Technically, it is not constant, just
unmodifiable.) For this discussion, let's assume that c does treat
string literals as constants. a would then be a pointer to const
char, not a const pointer. It is perfectly legal to reassign a to
point to the same data b points (which is another const char). In
both cases, a points to the first char of a const array of char or the
equivalent array of const char.

In fact, by defining a as a char* instead of a char[], you eliminate
the syntax error in the original code. (&a has type char(*)[10] while
call() is expecting a char**.) This error was undetected by the OP
because he failed to include a prototype of call() before calling the
function.

Therefore, while it doesn't do what the OP requested, you have in fact
removed the undefined behavior from the original code and created a
program without undefined behavior.



<<Remove the del for email>>
 

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

No members online now.

Forum statistics

Threads
473,769
Messages
2,569,577
Members
45,054
Latest member
LucyCarper

Latest Threads

Top