
www.Usenet.com
| <-- __Chronological__ --> | <-- __Thread__ --> |
On 17 Aug 2003 10:37:03 -0700, [EMAIL PROTECTED] (Marek Ratajczak)
wrote in comp.compilers.tools.pccts, which is completely unrelated to
the question; fu2 comp.lang.c where this belongs and is a FAQ, 1.32 at
the usual places and http://www.eskimo.com/~scs/C-faq/top.html :
> I move my graphic program from gcc & djgpp enviroment into Microsoft VC 6
> and Allegro graphic library.
> Fragment of this huge project i have attached bellow, as completed, very
> small program.
>
> There is structure of menu system, opened with my graphic module.
> Compiled with GCC this program works good, in this example, printing on
> screen first menu position contents.
>
> Value '\0' follows the string "Position 1", "Position 2" etc. is
> for recognition of "end of first part of string". Second part of string is
> modified in function :
>
> void menu_par_new (char *pole, char *par).
>
These aren't "parts" of strings; they are strings. In C, a string is
*defined* as a series of characters terminated by a null character,
which is what \0 (in a char or string literal) is. What you have is a
(single) string *literal* (a source construct) generating a char array
at runtime that contains several strings, packed together.
> In this example i try to change value 'Y' into 'N', but in function:
> strcpy(st, par)
> program crashes.
>
> In GCC compiler all is ok, and program works, and is no way to change menu
> data structure (project is to large).
>
> What is wrong?
>
> If any idea how to do it in VC, answere me, please....
>
It is not allowed in standard C to modify (the contents of the
anonymous array generated for) a string literal; specifically it is
"Undefined Behavior" and the implementation is not required to
diagnose the error but may do anything, including the traditional
early-C behavior of allowing it, or ignoring the change, or crashing.
It is usually better to use const char* pointers to point to string
literal values, so that such attempts it are caught by the compiler.
gcc normally makes string literal values read-only, so this crashes
there too usually depending on OS/hw support, unless you specify
-fwritable-strings or -traditional. But the djgpp port *to MSDOS*
can't do this AFAICT; in contrast mingw *on Windows* does.
There may be similar options in MSVC; check the doc or ask in an
implementation-specific group (presumably under microsoft.public.*
somewhere, but I don't know exactly, someone else may).
<snip&reorder>
> /*menu window data structure*/
> typedef struct {
> char *txt; /*string address of menu position*/
> char wcod; /*char shortcut of menu position*/
> struct tmn *menu; /*submenu address*/
> } POLE;
>
> static POLE pmParametres[]={
> {"Position 1 \0 Y\0 ", '1',NULL},
> {"Position 2 \0 Y\0 ", '2',NULL},
> {"Position 3 \0 Y\0 ", '3',NULL},
> {"Position 4 \0 Y\0 ", '4',NULL},
> } ;
>
If you really can't change the data structure at all this (modifying
the char(s) POLE.txt points to) will never be standard or safe. If
you can change POLE.txt to be an actual array (with a fixed limit)
rather than a pointer that would be OK. If you leave it a pointer but
change to point to an actual and non-const char array rather than a
string literal that would be OK; you could either do this during
initialization with extra variables/names:
static char param0value [] = "Position 1 \0 Y\0 ";
static char param1value [] = "Position 2 \0 Y\0 ";
etc.
static POLE pmParametres [] = {
{ param0value, '1', NULL},
{ param1value, '2', NULL), etc. );
or define as before but at startup before first use (or even just
before first modification) *copy* into space allocated by malloc or
similar (including all pieces, and the terminators!), and re-point to
that. For a single string you could use <nonstandard but common>
strdup, but not for multiple strings like you have.
Why are there spaces before the Y in the second strings here, but not
in the value you try to modify it to below? Do you intend them to be
formatted differently, or is this a mistake? For that matter, why is
there a third string in each literal that contains only spaces? Did
you think that "\0 " (with spaces) is a single null? It's not, it's
a null plus two spaces. (\nnn allows *up to* three octal digits, not
exactly three characters.) If so, and you were trying to "add" a null
at the end of the string, that's useless; *every* string literal value
has a null appended automatically. <pedantic>Though a string literal
(token) used as initializer in a definition of a char array, perhaps
with a declared bound that doesn't allow for an added null, does not
have a value, only the array does.</>
> typedef struct tmn {
<snip>
> POLE (*pola)[]; /*table of descriptions in menu
> positions*/
<snip>
> } TMENU;
> TMENU
> mParametres={4,0,30,23,4,TADD,CMNU,CMBR,CMTX,0,0,0,&pmParametres,NULL,NULL};
>
(with later references to (*mParametres.pola)[0 /*or whatever*/] )
Why is this a pointer-to-array (of unknown bound) instead of just a
pointer-to-element, used to access the array in the usual way?
Although not illegal or actually wrong, this is a waste of effort,
clutters the program, and confuses the reader.
>
> void menu_par_new (char *pole, char *par)
> /*---------------------------------------*/
> { char *st;
>
> st=pole + strlen(pole) + 1;
>
> strcpy(st, par);
> }
>
>
> int main ()
>
> {
> char st[10];
> int len;
> char *options;
<snip>
> strcpy(st,"N") ;
>
>
> ///////////// function doesn't work //////////////////
>
> menu_par_new ((*mParametres.pola)[0].txt, st) ;
>
Note that even if you make POLE.txt writable, in one of the ways
above, this works only if the string you want to write is the same
length or shorter, and if shorter it screws up any use of the
subsequent strings or data; if the original string is always 1
character, which it was not in your example(s) but I wonder if you
might have intended, the new string must be only 1 character, so you
could just assign that character:
(in menu_par_new) st[0] = par[0]; /* or equivalent arg */
- David.Thompson1 at worldnet.att.net
| <-- __Chronological__ --> | <-- __Thread__ --> |