[comp.lang.c] pointer problems, help!

mitchemt@silver.ucs.indiana.edu (Terry Mitchem) (03/22/91)

        I am having some major problems getting a piece of code to work.
It seems that everytime I change the contents of one string, it affects
another one. For example, when I build the filename below, it gets wiped
out when I null the members of "target_player". The code is below, and below
that is the datafile I am using.

void edit_category()
{
  struct
  {
    char *card_number;
    char *quantity;
    char *first_name;
    char *last_name;
    char *price_mint;
    char *price_ex;
  } target_player;

  char filename[80],carriage_return[5];
  int infile,bytes;

  *filename=NULL;

  strcat(filename,".\\"); strcat(filename,category.brand);
  strcat(filename,"\\");  strcat(filename,category.type);
  strcat(filename,"\\");  strcat(filename,category.year);
  strcat(filename,"\\");  strcat(filename,category.other);
  strcat(filename,"\\data");

  *target_player.card_number=NULL; *target_player.quantity=NULL;
  *target_player.first_name=NULL; *target_player.last_name=NULL;
  *target_player.price_mint=NULL; *target_player.price_ex=NULL;

  infile=open(filename,O_RDONLY);
  if (infile==-1) exit(1);

  read(infile,target_player.card_number,5);
  read(infile,target_player.quantity,3);
  read(infile,target_player.first_name,21);
  read(infile,target_player.last_name,21);
  read(infile,target_player.price_mint,7);
  read(infile,target_player.price_ex,7);
}
----------------------------------------------------------------------------
Here is the datafile:

8    2  joe                  montana              .75    .40
9    2  christian            okoye                .20    .10    

        Any and all help is appreciated. I don't seem to be able to get
anything useful out of K&R to help me. I am compiling with turbo-c.
                        Thanks in advance
                                Terry

reg@pinet.aip.org (Dr. Richard Glass) (03/23/91)

The answer is that your structure definition contains pointers
that do not have valid rvalues to de-reference (PPRL)
(pointers pointing to random locations).  The
value of these pointers are random memory.  In this case,
most likely to the same address do to your results.  On some systems,
a runtime error could be produced sometimes - other times - who knows.

The fix here is to either re-define the fields of the structure to be
arrays or allocate the various fields
ex: target_player.first_name = malloc(the_size_U_need_to_hold_name +1)

The bug here is equivalent to the following piece of code:

foo()
{
char *random_pointer;

strcpy(random_pointer,"Hello world");
}

Ricky Glass reg@pinet.aip.org

c60b-1eq@web-4h.berkeley.edu (Noam Mendelson) (03/23/91)

In article <1991Mar22.082225.24948@bronze.ucs.indiana.edu> mitchemt@silver.ucs.indiana.edu (Terry Mitchem) writes:
>
>        I am having some major problems getting a piece of code to work.
>It seems that everytime I change the contents of one string, it affects
>another one. For example, when I build the filename below, it gets wiped
>out when I null the members of "target_player". The code is below, and below
>that is the datafile I am using.
>
>void edit_category()
>{
>  struct
>  {
>    char *card_number;
>    char *quantity;
>    char *first_name;
>    char *last_name;
>    char *price_mint;
>    char *price_ex;
>  } target_player;
>
>  char filename[80],carriage_return[5];
>  int infile,bytes;
>
>  *filename=NULL;
>
>  ...misc code deleted...
>
>  *target_player.card_number=NULL; *target_player.quantity=NULL;
>  *target_player.first_name=NULL; *target_player.last_name=NULL;
>  *target_player.price_mint=NULL; *target_player.price_ex=NULL;
>
>  infile=open(filename,O_RDONLY);
>  if (infile==-1) exit(1);
>
>  read(infile,target_player.card_number,5);
>  read(infile,target_player.quantity,3);
>  read(infile,target_player.first_name,21);
>  read(infile,target_player.last_name,21);
>  read(infile,target_player.price_mint,7);
>  read(infile,target_player.price_ex,7);
>}
>----------------------------------------------------------------------------
>Here is the datafile:
>
>8    2  joe                  montana              .75    .40
>9    2  christian            okoye                .20    .10    
>
>        Any and all help is appreciated. I don't seem to be able to get
>anything useful out of K&R to help me. I am compiling with turbo-c.

You declared pointers without assigning them to an address!  Therefore,
the random memory location that each one is pointing to when the struct
is declared is initialized with NULL (a no-no).  Furthermore, you are loading
the data into those random memory locations.
What you need to do is to malloc() memory and assign each of the pointers
to those blocks of memory _before_ you use them.  In your case, however,
it will probably be much easier to declare:
  struct
  {
    short int card_number;
    short int quantity;
    char first_name[40];
    char last_name[40];
    float price_mint;
    float price_ex;
  }
or something along those lines.  This will simplify your code.

===========================================================================
| Noam Mendelson    ..!ucbvax!web!c60b-1eq  | "I haven't lost my mind,    |
| c60b-1eq@web.Berkeley.EDU                 |  it's backed up on tape     |
| University of California at Berkeley      |  somewhere."                |

hagins@gamecock.rtp.dg.com (Jody Hagins) (03/23/91)

In article <1991Mar22.082225.24948@bronze.ucs.indiana.edu>, mitchemt@silver.ucs.indiana.edu (Terry Mitchem) writes:
|> 
|>         I am having some major problems getting a piece of code to work.
|> It seems that everytime I change the contents of one string, it affects
|> another one. For example, when I build the filename below, it gets wiped
|> out when I null the members of "target_player". The code is below, and below
|> that is the datafile I am using.
|> 
|> void edit_category()
|> {
|>   struct
|>   {
|>     char *card_number;
|>     char *quantity;
|>     char *first_name;
|>     char *last_name;
|>     char *price_mint;
|>     char *price_ex;
|>   } target_player;
|> 
|>   char filename[80],carriage_return[5];
     ^^^^^^^^^^^^^^^^^

This means that you are setting aside enough space for 80 chars, and
that memory has a starting address.  The starting address is stored in
the variable <filename>.


|>   int infile,bytes;
|> 
|>   *filename=NULL;
|> 
|>   strcat(filename,".\\"); strcat(filename,category.brand);
|>   strcat(filename,"\\");  strcat(filename,category.type);
|>   strcat(filename,"\\");  strcat(filename,category.year);
|>   strcat(filename,"\\");  strcat(filename,category.other);
|>   strcat(filename,"\\data");


Ever heard of sprintf()?


|> 
|>   *target_player.card_number=NULL; *target_player.quantity=NULL;
|>   *target_player.first_name=NULL; *target_player.last_name=NULL;
|>   *target_player.price_mint=NULL; *target_player.price_ex=NULL;


Here you are initializing a piece of memory to NULL.

Yeh, I know, I'm setting the first character to null, just like filename
above.  (I think you think that's what you are doing)

Well, no.  See, target_player.card_number (as well as the rest of the members
of this structure) is a char pointer.  That means it POINTS TO A CHAR.  It
takes up enough space in memory to store the address of a char data type.
However, it's value is not initialized, and therefore could be pointing out
in space to anywhere.  When you say *target_player.card_number = NULL, you are
saying "set the char that target_player.card_number points to, to NULL.  However,
target_player.card_number doesn't point to anything that we know of.  Therefore
you are setting some unknown place in memory (probably 0, but that's another
story) to NULL.


|> 
|>   infile=open(filename,O_RDONLY);
|>   if (infile==-1) exit(1);
|> 
|>   read(infile,target_player.card_number,5);
|>   read(infile,target_player.quantity,3);
|>   read(infile,target_player.first_name,21);
|>   read(infile,target_player.last_name,21);
|>   read(infile,target_player.price_mint,7);
|>   read(infile,target_player.price_ex,7);


Again, you obviously do not understand the concept of pointers.  I suggest
that you read through the section on pointers in a good C ref. book.

But hey, Jody, what are you talking about?  read() is supposed to read a
certain number of bytes into the char * passed as the 2nd arg.

Yeh, you got that right!

Huh?

Well, think of it this way.  read() reads a certain number of bytes, and
puts the result into the buffer pointed to by the 2nd arg.  However, you
have not allocated space for a buffer.  What's more, you have uninitialized
pointers, so you are reading into "unknown" memory areas (again, probably 0).
Remember that allocating a pointer is not the same as allocating the memory
that the pointer points to!  You need to have some space in which to read the
data.


|> }
|> ----------------------------------------------------------------------------
|> Here is the datafile:
|> 
|> 8    2  joe                  montana              .75    .40
|> 9    2  christian            okoye                .20    .10    
|> 
|>         Any and all help is appreciated. I don't seem to be able to get
|> anything useful out of K&R to help me. I am compiling with turbo-c.
|>                         Thanks in advance
|>                                 Terry
|> 



Seriously, this is not a flame.  However, I do think you need to go back to
your text, and instructor, and get a grasp on the difference between a pointer
and the data the pointer is referencing.


-- 

Jody Hagins             
hagins@gamecock.rtp.dg.com    
Data General Corp.      
62 Alexander Dr.        
RTP, N.C.  27709        
(919) 248-6035          

Nothing I ever say reflects the opinions of DGC.

darcy@druid.uucp (D'Arcy J.M. Cain) (03/23/91)

In <1991Mar22.082225.24948@bronze.ucs.indiana.edu> Terry Mitchem writes:
>        I am having some major problems getting a piece of code to work.
>  struct
>  {
>    char *card_number;
>    char *quantity;
>    char *first_name;
>    char *last_name;
>    char *price_mint;
>    char *price_ex;
>  } target_player;
>
>  char filename[80],carriage_return[5];
>  int infile,bytes;
>
>  *filename=NULL;
Don't do this.  NULL does not mean 0 on all systems (although the opposite
*is* true) but may instead mean "(void *)(0)."  Use "*filename = 0" or
"filename = '\0'" for this.  Better yet see my comments below and don't
bother with this line at all.

>  strcat(filename,".\\"); strcat(filename,category.brand);
>  strcat(filename,"\\");  strcat(filename,category.type);
>  strcat(filename,"\\");  strcat(filename,category.year);
>  strcat(filename,"\\");  strcat(filename,category.other);
>  strcat(filename,"\\data");
I assume category is a structure of strings or string pointers defined
previously.  Why not use:
  sprintf(filename, "./%s/%s/%s/%s/data",
    category.brand, category.type category.year, category.other);

Side note: DOS accepts the forward slash and the above makes you portable
to Unix.

>  *target_player.card_number=NULL; *target_player.quantity=NULL;
etc.
Even assuming that NULL is 0, you can't do this.  The strings you are
writing to do not have any space allocated to them.  They are simply
uninitialized pointers.  You either have to malloc space for each
pointer or declare the structure elements as follows:
    char card_number[6];
etc.  Note the extra character for the 0 terminator.

>  read(infile,target_player.card_number,5);
etc.
Same problem as above.  The fix for above will fix this.  You may also
want to check out fscanf(3) to fill the structure all at once.  Note
that it may not be suitable for you, I don't know what your data file
specs are from looking at two lines from it, but it may simplify the
input.

>        Any and all help is appreciated. I don't seem to be able to get
>anything useful out of K&R to help me. I am compiling with turbo-c.

Check out the FAQ for comp.lang.c.  It explains the use of pointers very
well and talks about a lot of misconceptions regarding them.

-- 
D'Arcy J.M. Cain (darcy@druid)     |
D'Arcy Cain Consulting             |   There's no government
Toronto, Ontario, Canada           |   like no government!
+1 416 424 2871                    |

throopw@sheol.UUCP (Wayne Throop) (03/24/91)

- hagins@gamecock.rtp.dg.com (Jody Hagins)
--   char filename[80],carriage_return[5];
- This means that you are setting aside enough space for 80 chars, and
- that memory has a starting address.  The starting address is stored in
- the variable <filename>.

No, that's not what it means.  The starting address of the array (by
which is probably meant the address of the first element, BTW: an
important distinction to make in C) is not stored anywhere in runtime
memory by this declaration, least of all "in" the variable named
"filename". 

Where do these myths come from, anyhow?

What the declaration of filename above means in C is that space for
eighty characters is set aside, and this space is given the name
"filename".  (It might mean something different as a formal
argument declaration, but that's not what it was in the example.)

- I do think you need to go back to
- your text, and instructor, and get a grasp on the difference between a pointer
- and the data the pointer is referencing.

This comment, on the other hand is correct.  Another possible expression
of the problem in the original post is that NULL should not be used to
assign values to or to compare with characters, but rather pointers.
--
Wayne Throop  ...!mcnc!dg-rtp!sheol!throopw

torek@elf.ee.lbl.gov (Chris Torek) (03/25/91)

In article <1991Mar22.193636.10853@dg-rtp.dg.com> hagins@gamecock.rtp.dg.com
(Jody Hagins) writes:
[a bunch of stuff, mostly right, but a fine point that needs correcting]
>>   char filename[80], ...

>This means that you are setting aside enough space for 80 chars, and
>that memory has a starting address.  The starting address is stored in
>the variable <filename>.

Actually,

	char filename[80];

declares `filename' as an <object, array 80 of char>, setting aside
space for 80 `char's.  The starting address is not necessarily `stored'
anywhere, but it can be computed on demand (in an arbitrary,
machine-dependent manner, by the compiler) and in in fact computed
whenever

	<object, array 80 of char, filename>

appears where a value is required.  The Rule says that, in any value
context, an object of type `array N of T' (for any integer constant N
and legal type T) is converted to a value of type `pointer to T' whose
value is the address of the 0'th element of that array.
-- 
In-Real-Life: Chris Torek, Lawrence Berkeley Lab CSE/EE (+1 415 486 5427)
Berkeley, CA		Domain:	torek@ee.lbl.gov