Thread: Pointer returning too big value

  1. #1
    Registered User
    Join Date
    Jun 2005
    Posts
    20

    Pointer returning too big value

    In my program the number of decimal places is read from a file. Depending on that value,
    an amount is divided by the appropriate constant. If the value is greater than 5 then it
    throws an error.


    Code:
    struct ccyRec      /* currency file  */
    {
       char  CcyRtypeXC [2];
       char  CcyRtype00 [2];
       char  Ccycode    [2];
       char  Ccysymbol  [3];
       char  CcyDecpl   [1];   /*  decimal places  */
    };
    
    
    int i_precision ;
    char *a_precision; 
    char          tst2 [2];
    
    struct ccyRec   CCY_REC_BUF,  *pq;  /* pointer pq used for this file  */
    Code:
    main ()
    {
       pq = &CCY_REC_BUF;
    
    <snip>
          strncpy (tst2, pq->Ccycode, 2);
    <snip>
    
    /* Copy decimal places to a_precision  */
       strncpy (a_precision, pq->CcyDecpl , 1);  
    /* Convert to integer                  */
       i_precision = atoi(wrk_prec);
    
    
    /* Round off the report balance  */
    
    strcpy (a_precision, pq->CcyDecpl); 
    i_precision = atoi(a_precision);
    
    if ( i_precision > 99)
                     i_precision /= 100;
                  else if ( i_precision > 9)
                     i_precision /= 10;
    
    strncpy (inputAmt, po->Rept_bal, 14);  
    
    if ( i_precision ==  0)
       sprintf (outputAmt, "%.*lf", 0, atof(inputAmt) );
    else if (i_precision  == 1)
       sprintf (outputAmt, "%.*lf", 0, atof(inputAmt)/10);
    else if (i_precision  == 2)
       sprintf (outputAmt, "%.*lf", 0, atof(inputAmt)/100);
    else if (i_precision  == 3)
       sprintf (outputAmt, "%.*lf", 0, atof(inputAmt)/1000);
    else if (i_precision  == 4)
       sprintf (outputAmt, "%.*lf", 0, atof(inputAmt)/10000);
    else if (i_precision  == 5)
       sprintf (outputAmt, "%.*lf", 0, atof(inputAmt)/100000);
    else
      {
       emessage ("Wrong currency decimal place", "Rept bal", a_precision); 
      }
    
    printf ("Ccycode = %s          \n", tst2);
    printf ("a_precision = %s          \n", a_precision);
    printf ("i_precision = %d          \n", i_precision);
    printf ("CcyDecpl = %s          \n", pq->CcyDecpl);
    
    <snip>
    When it reaches currency code 04, which is the first to have decimal places = 0,
    it fails the comparisons and my print statements give the following output:

    Ccycode = 04
    a_precision = (null)
    i_precision = 6
    CcyDecpl = 006

    The currency file looks like this:
    Code:
    XC0000USD2
    XC0001USD2
    XC0002   2
    XC0003CAD2
    XC0004JPY0
    XC0005JBU0
    XC0006GBU2
    XC0007HKD2
    XC0008SGD2
    XC0011GBP2
    XC0012AUD2
    XC0013DEM2
    XC0015CHF2
    XC0016ITL0
    XC0017FRF2
    XC0018IEP2
    XC0019NLG2
    XC0020EUR2
    XC0022BBD2
    XC0024BEF2
    XC0025   0
    XC0026ESP0
    XC0027SEK2
    XC0028NOK2
    XC0029DKK2
    XC0030NZD2
    XC0031THB2
    XC0032INR2
    XC0033MYR2
    XC0034KRW0
    XC0036PTE2
    XC0050XAU3
    XC0051XAG3
    XC0052IDR0
    XC0070CNY2
    XC0092CHU2
    XC0093NBU2
    XC0094HBU2
    XC0095EBU2
    XC0097ABU2
    XC0098CBU2
    XC0099US$2
    Hence it is picking up more than the 0 from the data "XC0004JPY0".

    Can anyone please explain to me why, and maybe how to fix it?

    Many thanks,
    Bob

  2. #2
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,788
    int main

    Why do you use globals?
    Do you have initialization of CCY_REC_BUF?
    Do you have the initialization of a_precision?

    etc

    Could you post the minimum amount of the code that can be compiled and still represents the problem?
    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    – David J. Wheeler

  3. #3
    and the hat of int overfl Salem's Avatar
    Join Date
    Aug 2001
    Location
    The edge of the known universe
    Posts
    39,661
    1. How are you assigning things to currency record?
    Because if you're expecting to be able to just do a single read of the file, and expecting all those fields to be populated, then it isn't going to work reliably. All structures are subject to internal padding, which means there may be invisible holes between your data members.

    2. strncpy (a_precision, pq->CcyDecpl , 1);
    Several things wrong here
    - a_precision isn't pointing anywhere (unless you snipped it)
    - strncpy doesn't always append a \0 to make the result a proper string.

    So I think you need something like
    Code:
    char buff[BUFSIZ];
    fgets( buff, sizeof buff, fin );
    Then extract the decimal places with something like
    dp = buff[9];

    or the code with
    char code[5];
    strncpy( code, &buff[2], 4 ); code[4] = '\0';
    If you dance barefoot on the broken glass of undefined behaviour, you've got to expect the occasional cut.
    If at first you don't succeed, try writing your phone number on the exam paper.

  4. #4
    Registered User
    Join Date
    Jan 2006
    Location
    India
    Posts
    6
    I hope that u have allocated sufficient memory to inputAmt using malloc before copying
    data to it. And dont forget to free it later when the need is over.

  5. #5
    Registered User
    Join Date
    Jun 2005
    Posts
    20
    OK, thanks for all your help; I have two obstacles,
    I'm amending someone else's code (which I'm assuming is correct) and my own lack of experience in
    real life C programming.

    I'll definitely look at the pointer initialization and perhaps not even use a pointer there.

    Looking over my post again, I realized one of my main worries is when I retrieve CcyDecpl why is
    it giving me three characters instead of one?


    Firstly, a bit more info on the program. I'll reflect on posting the whole program, but feel
    it is too large and, anyway, cannot be run without the appropriate Btrieve files. Hence I am
    striving to give all relevant information. The program reads a GL file and for each GL record
    extracts additional information, such as from the Currency file, before writing to an output file.

    Getting back to my Currency structure, I declared it so
    Code:
    struct ccyRec
    {
       char  CcyRtypeXC [2];
       char  CcyRtype00 [2];
       char  Ccycode    [2];
       char  Ccysymbol  [3];
       char  CcyDecpl   [1];
    };
    The pointer is declared with
    Code:
    struct ccyRec  CCY_REC_BUF,  *pq;
    My understanding is that this is declaring two things; an instance of structure ccyRec called CCY_REC_BUF,
    and a pointer pq.

    pq is inialized (i.e. pointed at the structure)
    Code:
    pq = &CCY_REC_BUF;

    The file is opened (not shown) and at the appropriate times this loop is used to find the correct record
    (matching Ccycode) and the corresponding value of Ccysymbol is saved. The Btrieve record is read into CCY_REC_BUF.
    Code:
    /*================================================================*/
    /* Check CcyCode = Limit Currency, as per Join in original 2A.c  */
    /*================================================================*/
       cStatus = BTRV (B_GETFST, CCY_POS_BLK, &CCY_REC_BUF, &CCY_BUF_LEN, CCY_KEY_BUF, 0);
    
       strncpy(str4, "XXX", 3);
    
       while (cStatus != EOF_ERR)
       {
          if (cStatus != 0)
          {
    	 emessage("Reading","CCYTABLE.BTR",cStatus);
    	 exit(2);
          }
          strncpy (tst1, pi->GLDAc_cc, 2);
          strncpy (tst2, pq->Ccycode, 2);
    
          if (strncmp(tst2, tst1, 2) == 0)
            {
                 memcpy (str4, pq->Ccysymbol, 3);
                 cStatus = EOF_ERR;
            }
           else
            {
       cStatus = BTRV (B_GETNX, CCY_POS_BLK, &CCY_REC_BUF, &CCY_BUF_LEN, CCY_KEY_BUF, 0);
            }
       }
    Assuming a matching record is found in the Currency file, then processing continues...
    Code:
    /*================================================================*/
    /* Continue if CCYTABLE lookup is successful                      */
    /*================================================================*/
    
        if (strncmp(str4,"XXX",3) == 0)
            {
             goto getnxt;
            }
    
    <snip>
    
     	 /* 4.  Round off the report balance */
    		strcpy (a_precision, pq->CcyDecpl); 
    		i_precision = atoi(a_precision);
    
    		if ( i_precision > 99)
                       i_precision /= 100;
                    else if ( i_precision > 9)
                       i_precision /= 10;
    
    		strncpy (inputAmt, po->Rept_bal, 14);  
    
    		if ( i_precision ==  0)
    		   sprintf (outputAmt, "%.*lf", 0, atof(inputAmt) );
    		else if (i_precision  == 1)
    		   sprintf (outputAmt, "%.*lf", 0, atof(inputAmt)/10);
    		else if (i_precision  == 2)
    		   sprintf (outputAmt, "%.*lf", 0, atof(inputAmt)/100);
    		else if (i_precision  == 3)
    		   sprintf (outputAmt, "%.*lf", 0, atof(inputAmt)/1000);
                    else if (i_precision  == 4)
                       sprintf (outputAmt, "%.*lf", 0, atof(inputAmt)/10000);
                    else if (i_precision  == 5)
                       sprintf (outputAmt, "%.*lf", 0, atof(inputAmt)/100000);
                    else
    		  {
    		   emessage ("Wrong currency decimal place", "Rept bal", a_precision); 
    		  }
    
    
    		/* copy converted Report bal amount to output buffer */
    		strncpy (po->Rept_bal, outputAmt, 14);  
    
    /* ============================================================================================================= */
    
    	/* WRITE OUTPUT  */
            STATUS = BTRV (B_INSERT, OUT_POS_BLK, &OUT_BUF, &OUT_BUF_LEN, OUT_KEY_BUF, 0);
            if (STATUS != 0)
             {
    	  emessage("Writing","ICRSEX2A.BTR",STATUS);
    	  exit(2);
             }
    
            ++count;
            if ( count % 10 == 0 )
             {
    	   printf ("                                                 \r");
    	   printf ("%d  record(s) being written.                       \r", count);
             }
    
    getnxt:
    	/* READ NEXT  */
          STATUS = BTRV (B_GETNX, GLD_POS_BLK, &GLD_REC_BUF, &GLD_BUF_LEN, GLD_KEY_BUF, 0);
       }
       printf ("%d  record(s) written.                          \n", count);
    In the above we have the issues with a_precision, etc., regarding initialization of course.

    When it reports a wrong decimal place (incorrectly at the moment!) I display several values on screen,
    as shown in my original post. The specific one I'm concerned about is
    Code:
          printf ("CcyDecpl = %s          \n", pq->CcyDecpl);
    because its output is "006" when I am expecting "0" and this is what is causing me my main problem.

    I understand "pq->CcyDecpl" to mean I am dereferencing the pointer pq to the member CcyDecpl of the
    structure CCY_REC_BUF (which is an instance of ccyRec). i.e. It is "looking at" the contents of the structure, populated by the last record read. The particular structure member is declared as "char CcyDecpl [1];"
    so where do the other two characters come from?

  6. #6
    Hurry Slowly vart's Avatar
    Join Date
    Oct 2006
    Location
    Rishon LeZion, Israel
    Posts
    6,788
    1. strncpy does not always append the \0 charracter.
    But you use the atof without check
    2.
    Code:
    printf ("CcyDecpl = %s          \n", pq->CcyDecpl);
    because pq->CcyDecpl is only 1 char you should use
    printf ("CcyDecpl = %c \n", pq->CcyDecpl[0]);

    you cannot use %s format to print strings that are not null-terminated
    All problems in computer science can be solved by another level of indirection,
    except for the problem of too many layers of indirection.
    – David J. Wheeler

  7. #7
    Registered User
    Join Date
    Jun 2005
    Posts
    20
    Quote Originally Posted by vart
    1. strncpy does not always append the \0 charracter.
    But you use the atof without check
    Part of original coding untouched by me.
    2.
    Code:
    printf ("CcyDecpl = %s          \n", pq->CcyDecpl);
    because pq->CcyDecpl is only 1 char you should use
    printf ("CcyDecpl = %c \n", pq->CcyDecpl[0]);

    you cannot use %s format to print strings that are not null-terminated
    Output today, with %s, was showing as "009".
    With %c it outputs this character "╤"!

  8. #8
    Registered User
    Join Date
    Jun 2005
    Posts
    20

    Smile

    Quote Originally Posted by vart
    1. strncpy does not always append the \0 charracter.
    But you use the atof without check
    2.
    Code:
    printf ("CcyDecpl = %s          \n", pq->CcyDecpl);
    because pq->CcyDecpl is only 1 char you should use
    printf ("CcyDecpl = %c \n", pq->CcyDecpl[0]);

    you cannot use %s format to print strings that are not null-terminated
    OK, I understand that
    Code:
          printf ("CcyDecpl = %s          \n", pq->CcyDecpl);
    will start with my structure member CcyDecpl and then continue displaying until it reaches a "\0", so I ignored that as a red herring.

    I decided just to review the atof statements, even though I hadn't touched them, and I have now got past the decimal place error in the program! Well, the program has finished without falling over anyway; I've yet to check the output.

    I noticed that the previous programmer (of many, many moons ago) had increased a strncpy from 12 to 14
    Code:
    strncpy (po->Rept_bal, outputAmt, 14);
    ...but hadn't increased the size of outputAmt from 12 to 14!

    Also, I declared the variable a_precision as char[2] and did a strncpy into it (now I look at it I don't know why they had it as a pointer).

    Many thanks for your help on what I gave you!

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. Replies: 5
    Last Post: 04-04-2009, 03:45 AM
  2. Direct3D problem
    By cboard_member in forum Game Programming
    Replies: 10
    Last Post: 04-09-2006, 03:36 AM
  3. towers of hanoi problem
    By aik_21 in forum C Programming
    Replies: 1
    Last Post: 10-02-2004, 01:34 PM
  4. Quick question about SIGSEGV
    By Cikotic in forum C Programming
    Replies: 30
    Last Post: 07-01-2004, 07:48 PM
  5. returning a pointer
    By uler in forum C++ Programming
    Replies: 4
    Last Post: 09-13-2001, 01:59 PM