delorie.com/archives/browse.cgi   search  
Mail Archives: djgpp/1999/09/15/11:08:08

Message-Id: <199909150739.KAA00434@ankara.Foo.COM>
From: "S. M. Halloran" <mitch AT duzen DOT com DOT tr>
Organization: User RFC 822- and 1123-compliant
To: djgpp AT delorie DOT com
Date: Wed, 15 Sep 1999 11:44:31 +0200
MIME-Version: 1.0
Subject: Re: invalid operands
In-reply-to: <1684.990913@Phreaker.net>
X-mailer: Pegasus Mail for Win32 (v3.12)
Reply-To: djgpp AT delorie DOT com
X-Mailing-List: djgpp AT delorie DOT com
X-Unsubscribes-To: listserv AT delorie DOT com

On 13 Sep 99, Batchex was found to have commented thusly:

> Hi,
> 
>   I have  a difficulty with the code below :
> 
>   FILE *fp;
>   int nIdx, nNumEntries;
>   long lnDataStart, lnFileSize;
>   char **lpszTable;
> 
>   // clipped
> 
>   lpszTable = (char **)malloc(nNumEntries*sizeof(char *));
>   fread(lpszTable,sizeof(char *),nNumEntries,fp);

You've stored pointer in a file and believe that by loading them that they will
point where you want, as if memory addresses are burned into the application?  
Or is fp just a reference to another type of dynamic data storage object, i.e., 
really memory? 

>   lnDataStart = (long)lpszTable[0];
                        ^^^^^^^^^^^^
Uninitialized value used in assignment.

>   lpszTable[0] = (char *)malloc((lnFileSize-lnDataStart)*sizeof(char));
                                   ^^^^^^^^^^ ^^^^^^^^^^^

And now you initialize lpszTable[0] with the value lnDataStart, which was 
itself initialized by lpszTable[0].  Even if it is something you wanted to do, 
at the very least you should free lpszTable[0] first before assigning it a new 
value.

You are also doing pointer arithmetic without thinking about the values of the 
pointers or integers created by those magic casts.  Casting pointers to 
integers and back again are okay at times, and the compiler won't complain 
because it assumes the programmer knows what he is doing when he uses casts in 
a limited fashion.  Get out your debugger and put watches on lnFileSize, 
lnDataStart, and the expression "lnFileSize-lnDataStart" and see if it is doing 
what you expected.  You almost certainly will find it is not the case.  It's a 
universally good idea, especially for people new to programming in C/C++, to 
test always the pointer returned by an _alloc() function, to see if it is NULL 
and to include hand-waving code in the condition that it is.

How did you set your compilers warnings btw?  Make sure your warning levels are 
set correctly, and handle [nearly] every warning as if it's a compiler error 
(for some, those warnings *are* errors).

>   for(nIdx=1;nIdx<nNumEntries;nIdx++)
>    lpszTable[nIdx]=(char *)(lpszTable[0]+(lpszTable[nIdx]-lnDataStart));

The operands are invalid because in your expression (char *)(x + (y - z)), the 
addition of x (a pointer) is to another pointer (the evalution of y - z).  The 
evaluation of y - z is valid in general, but not the way you used it here.

>   NOTE : fp, nNumEntries & lnFileSize is initialized somewhere else
>   before the above code.
> 
>   The last line of the code always gives me "invalid operands for
>   binary +". If lpszTable[0] is not malloc()ed before the for loop, it
>   compiles and run fine. I have tried some variations for the
>   assignment, and I think the lpszTable[0] operand is the culprit.
>   What I need is to load some data to an allocated buffer, load the
>   entries offsets to another allocated buffer ('cause the entries have
>   variable lengths), then add the offsets to the address of the
>   allocated data buffer (the first allocated buffer). How can I do
>   this if adding lpszTable[0] with some value gives "invalid operands
>   for binary +"?

The way they probably teach you in school is the following [set your message 
line width to 80 chars on your mail reader]:

    1. Allocate block of memory to contain your pointers to memory which are
       offsets to your entries:

             if ((lpszTable = calloc(nNumEntries, sizeof(char *))) == NULL)
                 goto scream_nomem;  /* or scream_fatal_error("NOMEM") */

    2. For each entry, you now determine its size (number of chars plus a NUL
        byte if you intend to treat it as a NUL-terminated string) and then
        allocate:

          int size_of_entries = { BYTES_ENTRY_1, BYTES_ENTRY_2, /* ... */ };

          for (i = 0; i < nNumEntries; i++)
          {
             if ((lpszTable[i] = malloc((size_of_entries[i] + 1) *
                            sizeof(char))) == NULL)
                     goto scream_nomem;
              /* copy the chars into the allocd mem while you're at it */
          }

        If you are working with a file and you want to read it into one buffer
        and you know the offsets for each of the nNumEntries, then you can try:

         int my_offsets_from_start_of_buffer { OFFSET_1, OFFSET_2, /* ...*/};

         if ((lpszTable[0] = malloc(lnFileSize))) == NULL)
			;
         fread(lpszTable[0], 1, lnFileSize, fp);
         for (i = 1; i < nNumEntries; i++)
			lpszTable[i] = lpszTable[0] + my_offsets_from_start_of_buffer[i];

         Note that mem is allocd as a block, and then you just set up the
         offsets from the address where the buffer starts using pointer
         addition.

         In either case you have to know what your offsets are or have a way
         of calculating them.

>   One other question, not related to the above code, anybody know any
>   function that can read raw data from file (like _dos_read()) that is
>   POSIX compliant? fread() seems to stop whenever it encounter CR/LF
>   pair ("\n"), and my data have a lot of them.

With DJGPP and most other systems, you can get that POSIX-compliant behavior by 
using:

             if ((fp = fopen(myfilename, "rb"))) == NULL)
                  ;

   Note the flag "rb" for "read binary" whereas "r" is "read [text]".  You need 
to do that as well with the open() Unix call:  
    
     open(myfilename, O_RDONLY | O_BINARY)

Countless programming hours have been lost by novice and experienced alike 
because of this idiosyncrasy.

Mitch Halloran
Research (Bio)chemist
Duzen Laboratories Group
Ankara       TURKEY

- Raw text -


  webmaster     delorie software   privacy  
  Copyright © 2019   by DJ Delorie     Updated Jul 2019