[net.lang.c] String help!

upen@watarts.UUCP (Ue-Li Pen) (02/19/85)

Question:

Is it allowed & portable to use the construct:

char* foo(){

return("foobar");    

}

This would hopefully return a pointer to the string "foobar"..

If it isn't.. should it be allowed? It would seem reasonable.

david@ukma.UUCP (David Herron, NPR Lover) (02/21/85)

In article <8257@watarts.UUCP> upen@watarts.UUCP (Ue-Li Pen) writes:
> Is it allowed & portable to use the construct:
> char* foo(){
> return("foobar");    
> }
> This would hopefully return a pointer to the string "foobar"..

Yes it does....However it is a pointer to a STATIC data area.
So it wouldn't be a good idea to change the contents of the string.
-- 
-:--:--:--:--:--:--:--:--:--:--:--:--:--:--:--:--:--:--:--:--:--:--:--:-
-:-David Herron;
-:-ARPA-> "ukma!david"@ANL-MCS or david%ukma.uucp@anl-mcs.arpa
-:-ARPA-> Or even anlams!ukma!david@ucbvax.arpa
-:-UUCP-> {ucbvax,unmvax,boulder,research}!anlams!ukma!david
-:-UUCP-> {mcvax!qtlon,vax135,mddc}!qusavx!ukma!david
-:-UUCP-> {A-Large-Portion-of-The-World}!cbosgd!ukma!david

gwyn@brl-tgr.ARPA (Doug Gwyn <gwyn>) (02/21/85)

> return("foobar");    

Works just fine.  (The parentheses are unnecessary and misleading.)

huisjes@ark.UUCP (Michiel B. Huisjes) (02/24/85)

In article <929@ukma.UUCP> david@ukma.UUCP (David Herron, NPR Lover) writes:
>In article <8257@watarts.UUCP> upen@watarts.UUCP (Ue-Li Pen) writes:
>> Is it allowed & portable to use the construct:
>> char* foo(){
>> return("foobar");    
>> }
>> This would hopefully return a pointer to the string "foobar"..
>
>Yes it does....However it is a pointer to a STATIC data area.
>So it wouldn't be a good idea to change the contents of the string.
>-- 
>-:--:--:--:--:--:--:--:--:--:--:--:--:--:--:--:--:--:--:--:--:--:--:--:-
>-:-David Herron;

David Herron is right, except for the fact that you are allowed to
change the contents of the string as long as you don't change the 
length of it!
So you are allowed to say:

main()
{
	char *ptr;
	char *foo();

	ptr = foo();
	strcpy( ptr, "barfoo" );
	.....
}
-- 

			Michiel Huisjes.
			{seismo|decvax|philabs}!mcvax!vu44!ark!huisjes

gjerawlins@watdaisy.UUCP (Gregory J.E. Rawlins) (02/27/85)

In article <8257@watarts.UUCP> upen@watarts.UUCP (Ue-Li Pen) writes:
> Is it allowed & portable to use the construct:
> char* foo(){
> return("foobar");}
> This would hopefully return a pointer to the string "foobar"..

In article <929@ukma.UUCP> david@ukma.UUCP (David Herron, NPR Lover) writes:
> Yes it does....However it is a pointer to a STATIC data area.
> So it wouldn't be a good idea to change the contents of the string.

In article <437@ark.UUCP> huisjes@ark.UUCP (Michiel Huisjes) writes:
> David Herron is right, except for the fact that you are allowed to
> change the contents of the string as long as you don't change the 
> length of it!

(a confused hon-hacker writes...) Why would you want to keep a pointer to
a constant string (or at least a constant length string)??
-- 
Gregory Rawlins CS Dept.,U.Waterloo,Waterloo,Ont.N2L3G1 (519)884-3852
gjerawlins%watdaisy@waterloo.csnet                              CSNET
gjerawlins%watdaisy%waterloo.csnet@csnet-relay.arpa              ARPA
{allegra|clyde|linus|inhp4|decvax}!watmath!watdaisy!gjerawlins   UUCP

g-frank@gumby.UUCP (03/01/85)

> (a confused hon-hacker writes...) Why would you want to keep a pointer to
> a constant string (or at least a constant length string)??
> -- 

Well, you might not keep a pointer to it, but since strings must be passed
to functions by passing their addresses, you don't have a lot of choice.
In fact, these kinds of limitations (implementing pass by reference with
explicit pointers) really tie the hands of compiler implementers, especially
on machines that don't look like VAXen or PDP-11's.


-- 
      Dan Frank

	  Q: What's the difference between an Apple MacIntosh
	     and an Etch-A-Sketch?

	  A: You don't have to shake the Mac to clear the screen.

jeff@rtech.ARPA (Jeff Lichtman) (03/01/85)

> 
> David Herron is right, except for the fact that you are allowed to
> change the contents of the string as long as you don't change the 
> length of it!
> So you are allowed to say:
> 
> main()
> {
> 	char *ptr;
> 	char *foo();
> 
> 	ptr = foo();
> 	strcpy( ptr, "barfoo" );
> 	.....
> }
> -- 
> 
> 			Michiel Huisjes.
> 			{seismo|decvax|philabs}!mcvax!vu44!ark!huisjes

In DEC C, string constants are read-only.  They are in a special, write-
protected psect.  If you try to do something like the above, you will
get a run-time error.
-- 
Jeff Lichtman at rtech (Relational Technology, Inc.)
aka Swazoo Koolak

mroddy@enmasse.UUCP (Mark Roddy) (03/01/85)

> 

> (a confused hon-hacker writes...) Why would you want to keep a pointer to
> a constant string (or at least a constant length string)??
foo(n)
{
static char str="foobar 0x0000\n";
	hexdigit(n,&str[9]);		/* puts n into string */
	return(str);
}

As to why, imagine an environment without stdio etc- i.e., as is 
happening more frequently, C used to implement intelligent peripheral
device software.

-- 
						Mark Roddy
						Net working,
						Just reading the news.

					(harvard!talcott!panda!enmasse!mroddy)

ndiamond@watdaisy.UUCP (Norman Diamond) (03/04/85)

> > You are allowed to say:
> > 
> > main()
> > {
> > 	char *ptr;
> > 	char *foo();
> > 
> > 	ptr = foo();
> > 	strcpy( ptr, "barfoo" );
> > 	.....
> > }
> > -- Michiel Huisjes.
> 
> In DEC C, string constants are read-only.  They are in a special, write-
> protected psect.  If you try to do something like the above, you will
> get a run-time error.  --  Jeff Lichtman

What does the standard say about this?  Can an implementation legally prevent
a C program from modifying storage accessed by a valid pointer?

-- 

   Norman Diamond

UUCP:  {decvax|utzoo|ihnp4|allegra}!watmath!watdaisy!ndiamond
CSNET: ndiamond%watdaisy@waterloo.csnet
ARPA:  ndiamond%watdaisy%waterloo.csnet@csnet-relay.arpa

"Opinions are those of the keyboard, and do not reflect on me or higher-ups."

henry@utzoo.UUCP (Henry Spencer) (03/05/85)

> > In DEC C, string constants are read-only.  They are in a special, write-
> > protected psect.  If you try to do something like the above, you will
> > get a run-time error.  --  Jeff Lichtman
> 
> What does the standard say about this?  Can an implementation legally prevent
> a C program from modifying storage accessed by a valid pointer?

The latest ANSI draft (11 Feb 1985) says that string literals are of
type "const char[]" (not just "char[]") and thus it is illegal for you
to alter their contents.  This has both advantages and disadvantages.
It will break some programs, notably ones that use mktemp() in the
most simplistic way.  On the other hand, it will produce widespread
(if modest) improvements in efficiency, and will make life noticeably
easier for people writing C code to go in ROM.  [Please, let us not
have a renewed debate on the merits or lack thereof of this change;
we did that, at length, a few months ago.]
-- 
				Henry Spencer @ U of Toronto Zoology
				{allegra,ihnp4,linus,decvax}!utzoo!henry

jc@mit-athena.UUCP (John Chambers) (03/05/85)

Let's see, reasons for returning pointers to constant strings...?

Several times in the past couple years I have written routines that
end with code something like:
  ...
  fail:				/* Jump here for disasters*/
    errno = EGLORCH;
    fprintf(stderr,"***foo() FAILED.\n");
    return("???FOO???");
  }
This is for a function that normally returns a pointer to a string
of characters.  The idea is that if the caller doesn't notice the
failure and tries to use the return value, the program won't just
bomb inexplicably (as it might do if you return NULL); it will have
a character string that will tend to stand out wherever it pops up
later.  In this case, it doesn't much matter if the caller changes
the string, since it is basically a string of garbage anyway.

Anyone got any more examples?

			John Chambers

david@ukma.UUCP (David Herron, NPR Lover) (03/06/85)

>> > main()
>> > {
>> > 	char *ptr;
>> > 	char *foo();
>> > 
>> > 	ptr = foo();
>> > 	strcpy( ptr, "barfoo" );
>> > 	.....
>> > }
>> 
>> In DEC C, string constants are read-only.  They are in a special, write-
>> protected psect.  If you try to do something like the above, you will
>> get a run-time error.  --  Jeff Lichtman
>
>What does the standard say about this?  Can an implementation legally prevent
>a C program from modifying storage accessed by a valid pointer?

A string constant (like above) is a CONSTANT.  You should be prevented
from changing the values of CONSTANTS.  The fact that you ever could
is laziness (or something) on the part of the original implementors.

Allowing one to change the value of constants (can, not necessarily will)
create hard to find bugs.  (usually in the case of careless programmers...)

What I want to know is what (of the code above) would generate a
run-time error?
-- 
:------------------------------------------------------------------:
:- David Herron							  -:
:-								  -:
:- ARPA-> "ukma!david"@ANL-MCS or david%ukma.uucp@anl-mcs.arpa    -:
:- ARPA-> Or even anlams!ukma!david@ucbvax.arpa			  -:
:-								  -:
:- UUCP-> {ucbvax,unmvax,boulder,research}!anlams!ukma!david	  -:
:- UUCP-> {mcvax!qtlon,vax135,mddc}!qusavx!ukma!david		  -:
:- UUCP-> {A-Large-Portion-of-The-World}!cbosgd!ukma!david	  -:
:------------------------------------------------------------------:

	"The home of poly-unsaturated thinking".

gwyn@Brl-Vld.ARPA (VLD/VMB) (03/06/85)

The latest draft proposed ANSI standard for C supports a "const"
type-modifier, to flag data that may not be modified.  String
literals are (const char) arrays and may not be modified.  It
is possible to initialize a non-const (char) array with a string
if one wants to be able to modify it at run-time.

One significant advantage of (const char) strings is that they
are ROMable.  Another is that storage for identical strings can
be shared if the compiler/loader is sufficiently clever.

jc@mit-athena.UUCP (John Chambers) (03/12/85)

Hmmm... According to some of the advice here, the following is not
an acceptable way to declare an initialized array:

	char *fup = "0123456789";

The reason is that some C compilers are likely to take the string 
constant and put it into a read-only portion of memory.  Instead,
if we want an initialized character array, we are supposed to say 
something like:

	char fup[11];	/* I hope this isn't read-only */
	int  i;
	...
	for (i=0; i<11; i++)
	    fup[i] = i + '0';
	fup[i] = '\0';

or maybe:

	char *fup;
	int  i;
	...
	fup = malloc(11);
	if (fup == NULL) {	/* Gotta check for failure */
	    fprintf(stderr,"Out of space, can't get 11 bytes\n");
	    perror("foo");
	    exit(17);
	}
	for (i=0; i<11; i++)	/* Initialize the sucker */
	    fup[i] = i + '0';
	fup[i] = '\0';

To this, I say "NONSENSE".  Any compiler-writer that considers a
string constant to be read-only is a total and utter turkey, and
I would rather use a sensible compiler.  I don't need such stuff
to make my code slower and kludgier and harder to understand; I
can do a bad enough job by myself without encouragement from the
compiler writers! (:-)

Please, writing simple, straightforward code is a hard enough job
already.  One of the nice things about C is that such things as
the above example need not be kludgy and hard to read.  If we are
going to change C, let's try to make it better, not worse!

			John Chambers

P.S. An extension to the language to declare a symbol to be a
constant would be nice at times.  It would help those who are
dealing with ROM.

ndiamond@watdaisy.UUCP (Norman Diamond) (03/13/85)

> Hmmm... According to some of the advice here, the following is not
> an acceptable way to declare an initialized array:
> 
> 	char *fup = "0123456789";
> 
> The reason is that some C compilers are likely to take the string 
> constant and put it into a read-only portion of memory.

fup is not read-only.  The string might be.

> Instead,
> if we want an initialized character array, we are supposed to say 
> something like:
> 
> 	char fup[11];	/* I hope this isn't read-only */

The array fup is not read-only.

> 	int  i;
> 	...
> 	for (i=0; i<11; i++)
> 	    fup[i] = i + '0';
> 	fup[i] = '\0';
> 
> or maybe:
> 
> 	char *fup;
> 	int  i;

Yup, this time you gotta do it.

> 	...
> 	fup = malloc(11);

... proving that fup is not read-only ...

> 	if (fup == NULL) {	/* Gotta check for failure */
> 	    fprintf(stderr,"Out of space, can't get 11 bytes\n");
> 	    perror("foo");
> 	    exit(17);
> 	}
> 	for (i=0; i<11; i++)	/* Initialize the sucker */
> 	    fup[i] = i + '0';
> 	fup[i] = '\0';
> 
> To this, I say "NONSENSE".

It is nonsense, all right.  Try:

   char fup[11] = "0123456789";

This is not the same as assigning a pointer to address a read-only item.
This initializes the contents of the writable array fup.

-- 

   Norman Diamond

UUCP:  {decvax|utzoo|ihnp4|allegra}!watmath!watdaisy!ndiamond
CSNET: ndiamond%watdaisy@waterloo.csnet
ARPA:  ndiamond%watdaisy%waterloo.csnet@csnet-relay.arpa

"Opinions are those of the keyboard, and do not reflect on me or higher-ups."

guy@rlgvax.UUCP (Guy Harris) (03/13/85)

> Hmmm... According to some of the advice here, the following is not
> an acceptable way to declare an initialized array:
> 
> 	char *fup = "0123456789";

Damn straight.  It defines an initialized *pointer* which points to
a nameless array.  Try

	char fup[] = "0123456789";

to declare an array.

This *is* the sensible thing to do.  If you actually plan to *modify*
that array, the first example is truly lousy; if you end up putting 11
characters into it, you stomp on some strange area of memory (unless
the string is put in read-only memory, in which case your program gets
properly punished).  If you expect up to 128 characters in the array,
try

	char fup[128+1/*for the null terminator*/] = "0123456789";

Why should random strings get put in writable areas of your address space?
Currently, there are a lot of horrible kludges to move strings, etc. into
read-only sharable text space; putting strings there by default obviates
the need for some of those kludges (the "const" attribute obviates the
need for the others).

Please learn how to construct initialized strings before blindly
criticizing this language change.

	Guy Harris
	{seismo,ihnp4,allegra}!rlgvax!guy
-- 
	Guy Harris
	{seismo,ihnp4,allegra}!rlgvax!guy

jsdy@hadron.UUCP (Joseph S. D. Yao) (03/13/85)

> >> Is it allowed & portable to use the construct:
> >> char* foo(){
> >> return("foobar");    
> >> }
> >> This would hopefully return a pointer to the string "foobar"..
> >Yes it does....However it is a pointer to a STATIC data area.
> >So it wouldn't be a good idea to change the contents of the string.
> David Herron is right, except for the fact that you are allowed to
> change the contents of the string as long as you don't change the 
> length of it!

Perhaps you should remember that if you do, say, strcpy(foo(), "barfoo")),
then the next call to foo() will return "barfoo".  This is because the
"barfoo" string is copied into the static location of the string that
is returned by foo().  Another way to say this is that new instances
of the string "foobar" are  n o t  dynamically created each time you
call foo().  All of this assumes, BTW, that you are not using a DEC or
ANSI C compiler.

Also BTW, one response asks about the legitimacy of not being able to
modify the contents of any valid pointer.  In case henry's answer didn't
suggest it, ANSI C introduces a new storage class "const", which is a
class of data which may be assumed to remain constant, and (i guess if
possible) should be placed in read-only storage.  A no-write data-space
psect fills this requirement.  The opposite is "volatile", which means:
"Even if you are optimising the heck out of this code, watch it!  This
variable will change when you least expect it!"  This is good for data
manipulated by interrupt routines, or if you feel like being perverse
while adb/sdb/dbx'ing the thing.	;-)

Joe Yao		hadron!jsdy@seismo.{ARPA,UUCP}

*BTW == By The Way, for our friends not in the States.	;-)

wjr@x.UUCP (Bill Richard) (03/14/85)

> Hmmm... According to some of the advice here, the following is not
> an acceptable way to declare an initialized array:
> 
> 	char *fup = "0123456789";
> 
> The reason is that some C compilers are likely to take the string 
> constant and put it into a read-only portion of memory.  Instead,
> if we want an initialized character array, we are supposed to say 
> something like:
>
> <2 examples of run time array initialization>
>
> To this, I say "NONSENSE".  Any compiler-writer that considers a
> string constant to be read-only is a total and utter turkey, and
> I would rather use a sensible compiler.  ...
> 			John Chambers

	To this I say "RTFM John". K&R Section 8.6 (pg 199) says:
"A final abbreviation <of initializer forms> allows a _char_ array to
be initialized by a string. In this case successive characters of the
string initialize the members of the array." Thus:

 	char fup[] = "0123456789";

will give you a writable array of chars initialized to look like the
string. I assume that the ANSII committee hasn't broken this feature,
if they have I have a complaint.

	Or are you making a general objection to constants being
constant? In which case you must love those Fortran compilers which
allow you to dynamically change the value of a NUMERIC constant. :-)

-- 
----
William J. Richard @ Charles River Data Systems
983 Concord St. Framingham, MA 01701
Tel: (617) 626-1112
uucp: ...!decvax!frog!wjr

jeff@rtech.ARPA (Jeff Lichtman) (03/14/85)

> Hmmm... According to some of the advice here, the following is not
> an acceptable way to declare an initialized array:
> 
> 	char *fup = "0123456789";
> 
> The reason is that some C compilers are likely to take the string 
> constant and put it into a read-only portion of memory.  Instead,
> if we want an initialized character array, we are supposed to say 
> something like:
> 
	Unnecessarily complicated code here.
>
> or maybe:
> 
	Even more complicated code here.
>
> 			John Chambers

First of all, it's fine to initialize a character pointer to point to a
string constant.  Just don't try to alter the constant.  If you
want to initialize a character pointer to point to a non-constant string,
try the following:

	# define CONST	"0123456789"

	char	nonconst[sizeof(CONST)];
	char	*p = nonconst;

	strcpy(nonconst, CONST);

There, that's not so hard, is it?  I don't think it's a good programming
practice to modify the value of a constant, anyway.
-- 
Jeff Lichtman at rtech (Relational Technology, Inc.)
aka Swazoo Koolak

hansen@pegasus.UUCP (Tony L. Hansen) (03/19/85)

By definition, in ANSI C (according to the latest Feb. draft) string
constants are of type "const char[]".  The first horrified thought that
comes to the mind of many UNIX programmers is "What do I do with all of my
calls to mktemp() now?"  Easy!

	mktemp ("/tmp/fooXXXXXX");

		becomes

	mktemp ( (char *) "/tmp/fooXXXXXX");

Since the cast is used withOUT the "const" qualifier, the compiler is forced
to place the string in writable memory.  Note that I am NOT casting a "char *"
back into a "char *", but am instead casting a "const char *" into a "char *".

Since the number of times that such idioms will be needed will be very small,
this change to ANSI C will definitely be more beneficial than harmful.

					Tony Hansen
					pegasus!hansen

guy@rlgvax.UUCP (Guy Harris) (03/20/85)

> By definition, in ANSI C (according to the latest Feb. draft) string
> constants are of type "const char[]".  The first horrified thought that
> comes to the mind of many UNIX programmers is "What do I do with all of my
> calls to mktemp() now?"  Easy!
> 
> 	mktemp ("/tmp/fooXXXXXX");
> 
> 		becomes
> 
> 	mktemp ( (char *) "/tmp/fooXXXXXX");

Even better, it becomes

	char tempstr[14+1];

	strcpy(tempstr, "/tmp/fooXXXXXX");
	mktemp(tempstr);

which can, unlike

	mktemp("/tmp/fooXXXXXX");

be executed more than once and work every time.
-- 
	Guy Harris
	{seismo,ihnp4,allegra}!rlgvax!guy

kendall@talcott.UUCP (Sam Kendall) (03/22/85)

> 	mktemp ("/tmp/fooXXXXXX");
> 
> 		becomes
> 
> 	mktemp ( (char *) "/tmp/fooXXXXXX");
> 
> Since the cast is used withOUT the "const" qualifier, the compiler is forced
> to place the string in writable memory.  Note that I am NOT casting a "char *"
> back into a "char *", but am instead casting a "const char *" into a "char *".
> 
> 					Tony Hansen
> 					pegasus!hansen

This won't do it.  The cast makes a pointer to non-const out of a pointer
to const, but the result of the cast still points to storage defined as const,
so the result of any attempt to modify it (by mktemp) is undefined.

See Guy Harris's note on this topic for the right way to do it.

	Sam Kendall
	Delft Consulting
	{allegra, ihnp4}!pyuxvv!delftcc!sam