Thread: Format Specifiers

  1. #1
    Registered User
    Join Date
    Aug 2003
    Posts
    93

    Format Specifiers

    Hi,

    this has me a bit stumped,

    Code:
          case TOTAL_USD:
             sprintf(temp_buffer, "%*.*ld", sizeof(output->total_usd), sizeof(output->total_usd), atol(text));
             memcpy(output->total_usd, temp_buffer, sizeof(output->total_usd));
             output->total_usd[O_TOTAL_USD_LEN] = '\0';
    printf("before [%s]\n", text);
    printf("after [%s]\n", output->total_usd);
             break;
    
    
    
          case TOTAL_USD:
             sprintf(temp_buffer, "%*.*lf", sizeof(output->total_usd), sizeof(output->total_usd), atol(text));
             memcpy(output->total_usd, temp_buffer, sizeof(output->total_usd));
             output->total_usd[O_TOTAL_USD_LEN] = '\0';
    printf("before [%s]\n", text);
    printf("after [%s]\n", output->total_usd);
             break;

    /* OUTPUT */

    before [230.11]
    after [000000000000000000000000000230]

    before [230.11]
    after [0.0000000000000000000000000000]


    if I use the %d I lose the fraction, if I use %f I lose it all !

    These are the only specifiers I know
    %d (or %i) int
    %c char
    %f float
    %lf double
    %s string

    Is the another way I can manipulate these strings to be able to retain the fraction ?


    tia,

  2. #2
    Registered User
    Join Date
    Aug 2003
    Posts
    93
    Hi,

    this has done it for me

    Code:
          case TOTAL_USD:
             sprintf(temp_buffer, "%030.3f", sizeof(output->total_usd), sizeof(output->total_usd), atof(text));
             memcpy(output->total_usd, temp_buffer, sizeof(output->total_usd));
             output->total_usd[O_TOTAL_USD_LEN] = '\0';
    printf("before [%s]\n", text);
    printf("after [%s]\n", output->total_usd);
             break;
    before [230.11]
    after [00000000000000000000000230.110]

  3. #3
    Just Lurking Dave_Sinkula's Avatar
    Join Date
    Oct 2002
    Posts
    5,005
    >this has done it for me
    Code:
    sprintf(temp_buffer, "%030.3f", sizeof(output->total_usd), sizeof(output->total_usd), atof(text));
    This looks suspect to me: you've got more parameters than format specifiers. And the result of sizeof should not be a floating point value. Also, why follow the sprintf call with memcpy to make a string out of the string you just made?

    Could something like this do what you want without the need to hard-code the buffer size in the format specifier?
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    int main(void)
    {
       char buffer[30], text[] = "230.11";
       sprintf(buffer, "%0*.3f", (int)(sizeof(buffer) - 1), atof(text));
       printf("before [%s]\nafter  [%s]\n", text, buffer);
       return 0;
    }
    
    /* my output
    before [230.11]
    after  [0000000000000000000000230.110]
    */
    [edit]
    And by the way,
    >%lf double
    The %lf specifier is used for doubles with the scanf family, but %f is used for doubles with the printf family.
    [/edit]
    Last edited by Dave_Sinkula; 10-01-2003 at 08:12 AM.
    7. It is easier to write an incorrect program than understand a correct one.
    40. There are two ways to write error-free programs; only the third one works.*

  4. #4
    Registered User
    Join Date
    Aug 2003
    Posts
    93
    Code:
          case TOTAL_USD:
             sprintf(temp_buffer, "%030.3f", atof(text));
             memcpy(output->total_usd, temp_buffer, (O_TOTAL_USD_LEN + 1));
    printf("before [%s]\n", text);
    printf("after [%s]\n", output->total_usd);
             break;
    before [230.11]
    after [00000000000000000000000230.110]


    Hi Dave,

    I have now removed the extra and apparantly obsolete parameters and am getting the same result, so my code is a lot smaller now.

    The reason for memcpy is to fill a file with the output,


    thanks for the thought Dave

  5. #5
    Just Lurking Dave_Sinkula's Avatar
    Join Date
    Oct 2002
    Posts
    5,005
    Originally posted by darfader
    I have now removed the extra and apparantly obsolete parameters and am getting the same result, so my code is a lot smaller now.

    The reason for memcpy is to fill a file with the output
    Well, memcpy doesn't fill a file, it fills a char array. And so does sprintf. Why put 30 characters to temp_buffer only to turn around and copy the same 30 characters to output->total_usd? Why not "avoid the middleman" and go right to output->total_usd?

    It also seems like you are getting away from a form that would be easier from a maintenance perspective. Properly using sizeof allows your code to be correct regardless of whether an associated #define (?) such as O_TOTAL_USD_LEN is correct or not. And if you ever change the size of the string, you only need to make the change at the definition of the string.
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    struct sType
    {
       /* ... */
       char total_usd[30];
       /* ... */
    };
    
    int main(void)
    {
       struct sType object, *output = &object;
       char text[] = "230.11";
       sprintf(output->total_usd, "%0*.3f", (int)(sizeof(output->total_usd) - 1), atof(text));
       printf("text              [%s]\n", text);
       printf("output->total_usd [%s]\n", output->total_usd);
       return 0;
    }
    
    /* my output
    text              [230.11]
    output->total_usd [0000000000000000000000230.110]
    */
    Code:
    #include <stdio.h>
    #include <stdlib.h>
    
    struct sType
    {
       /* ... */
       char total_usd[20];
       /* ... */
    };
    
    int main(void)
    {
       struct sType object, *output = &object;
       char text[] = "230.11";
       sprintf(output->total_usd, "%0*.3f", (int)(sizeof(output->total_usd) - 1), atof(text));
       printf("text              [%s]\n", text);
       printf("output->total_usd [%s]\n", output->total_usd);
       return 0;
    }
    
    /* my output
    text              [230.11]
    output->total_usd [000000000000230.110]
    */
    I do realize that the string might be declared with a #define (?) such as O_TOTAL_USD_LEN to do this same thing. My preference leans toward the sizeof()-1/*for the null*/ because it eliminates the need to know how a string is defined. Or whether O_TOTAL_USD_LEN+1 is the right size or it is one too many. Or if the string were accidentally declared with size TOTAL_USD+1.

    Just some things to consider.
    7. It is easier to write an incorrect program than understand a correct one.
    40. There are two ways to write error-free programs; only the third one works.*

  6. #6
    Registered User
    Join Date
    Aug 2003
    Posts
    93
    Hi Dave,

    I was hoping to make a program that would be easier for the next maintenace programmer to follow,

    I have an enumeration
    Code:
    #ifndef CIRP_ENUMERATION_H
    #define CIRP_ENUMERATION_H
    
    
    enum
    {
       COUNTRY,
       REGION_CODE,
       REGION_NAME,
    
    ... 84 in total
    a structure
    Code:
    #ifndef CIRP_DATA_EXTRACT_OUTPUT_LAYOUT_H
    #define CIRP_DATA_EXTRACT_OUTPUT_LAYOUT_H
    
    #include "cirp_data_extract_output_field_sizes.h"
    
    typedef struct {
        char country                             [O_COUNTRY_LEN];
        char region_code                         [O_REGION_CODE_LEN];
        char region_name                         [O_REGION_NAME_LEN];
    
    ... 84 in total
    a set of constants for the field sizes
    Code:
    #ifndef CIRP_DATA_EXTRACT_OUTPUT_FIELD_LENGTHS_H
    #define CIRP_DATA_EXTRACT_OUTPUT_FIELD_LENGTHS_H
    
    #define  O_COUNTRY_LEN                              80
    #define  O_REGION_CODE_LEN                          20
    #define  O_REGION_NAME_LEN                          80
    
    ... 84 in total
    and a program that opens a delimited text file and works on it.

    The last process it does at present, is run through the current output file and change it from being delimited to fixed length

    Code:
    void create_smartbills(FILE ** fp)
    {
    RecordOut out_file;
    int loop;
    char buffer[BUFFER_SIZE];
    char * start;
    char * end;
    int field_number = COUNTRY;
    int count = 0;
    
    #ifdef DEBUG
        printf("In create_smartbills().\n");
        fflush(NULL);
    #endif
    
       /* count the number of lines in the file */
       count = get_count(fp, FIN_FILE);
       rewind(fp[FIN_FILE]);
    
       for(loop = 0; loop < count; loop++)
       {
          while(fgets(buffer, BUFFER_SIZE, fp[FIN_FILE]))
          {
             if(*buffer == EOF || *buffer == NULL)
             {
                break;
             }
             else
             {
                start = buffer;
    
                /* initialise the output record to spaces */
                memset(&out_file, SPACE_INT, sizeof(out_file));
    
                while(*start)
                {
                   /* find the terminating semi-colon  */
                   for(end = start; * end != '\n' && * end != SEPARATOR; end++);
    
                   /* terminate the string  */
                   *end = 0;
    
                   /* copy the field to the output record  */
                   set_output_field(&out_file, start, field_number);
    
                   /* advance to the next field  */
                   start = end + 1;
                   field_number++;
    
                   /* reset the enum value for each record */
                   if(field_number == LAST_FIELD)
                   {
                      /* first field */
                      field_number = COUNTRY;
                   }
                }
                fwrite(&out_file, sizeof(out_file), 1, fp[DELTA_FILE]);
                fwrite("\n", 1, 1, fp[DELTA_FILE]);
             }
          }
       }
    
    #ifdef DEBUG
        printf("Out create_smartbills().\n");
        fflush(NULL);
    #endif
    }
    
    int get_count(FILE ** fp, int text_file)
    {
    int ch;
    int count = 0;
    
    #ifdef DEBUG
        printf("In get_count().\n");
        fflush(NULL);
    #endif
    
       /* helper function to count files already written */
       fseek(fp[text_file], 0, SEEK_SET);
    
       while((ch = fgetc(fp[text_file])) != EOF)
          if(ch == '\n')
             count++;
    
       return count;
    
    #ifdef DEBUG
        printf("Out get_count().\n");
        fflush(NULL);
    #endif
    }
    
    void set_output_field(RecordOut * output, char * text, int field_number)
    {
    /* Long enough for the longest int  */
    char temp_buffer[128];
    
    #ifdef DEBUG
        printf("In set_output_field().\n");
        fflush(NULL);
    #endif
    
       switch(field_number)
       {
          case COUNTRY:
             memcpy(output->country, text, strlen(text));
             break;
    
          case REGION_CODE:
             memcpy(output->region_code, text, strlen(text));
             break;
    
          case REGION_NAME:
             memcpy(output->region_name, text, strlen(text));
             break;
    
    ... 84 in total
    and after a week, that is the best I have come up with so far, my time is running out here, but I will always gladly listen to advice,


    tia,

  7. #7
    Comment your source code! Lynux-Penguin's Avatar
    Join Date
    Apr 2002
    Posts
    533
    you're fflushing NULL.... why in god's name would you want to do that?

    ok... if I remember correctly... NULL is 0... now in terms of streams... stream 0 is stdout... (I think) that or its nothing

    either way why not use fflush(stdout) or just NOT flush at all if 0 is not stdout...

    ???

    -LC
    Asking the right question is sometimes more important than knowing the answer.
    Please read the FAQ
    C Reference Card (A MUST!)
    Pointers and Memory
    The Essentials
    CString lib

  8. #8
    Registered User
    Join Date
    Aug 2003
    Posts
    93
    because if the stream argument is NULL, fflush flushes all open output streams, or so I thought

  9. #9
    root
    Join Date
    Sep 2003
    Posts
    232
    >ok... if I remember correctly... NULL is 0... now in terms of streams... stream 0 is stdout... (I think) that or its nothing
    You're confused. I think you're thinking in terms of Unix file descriptors where 0 is stdin, 1 is stdout and 2 is stderr. But C uses pointers to a structure called FILE as handles. Usually, you'll have an array of FILE structures like so:
    Code:
    FILE _iobuf[MAX_OPEN] = {
      { /* Really implementation dependent */, 0 },
      { /* Really implementation dependent */, 1 },
      { /* Really implementation dependent */, 2 },
    };
    
    #define stdin  &_iobuf[0]
    #define stdout &_iobuf[1]
    #define stderr &_iobuf[2]
    So unless your system uses an insane memory mapping method, none of the streams' addresses will be even remotely close to 0. Taking advantage of this, if you pass fflush a null pointer, it flushes all open output streams. You can check K&R or the C standard and it will tell you the same thing.
    The information given in this message is known to work on FreeBSD 4.8 STABLE.
    *The above statement is false if I was too lazy to test it.*
    Please take note that I am not a technical writer, nor do I care to become one.
    If someone finds a mistake, gleaming error or typo, do me a favor...bite me.
    Don't assume that I'm ever entirely serious or entirely joking.

Popular pages Recent additions subscribe to a feed

Similar Threads

  1. ras.h errors
    By Trent_Easton in forum Windows Programming
    Replies: 8
    Last Post: 07-15-2005, 10:52 PM
  2. wsprintf and format specifiers
    By incognito in forum Windows Programming
    Replies: 2
    Last Post: 01-03-2004, 10:00 PM
  3. header file bringing errors?
    By bluehead in forum Windows Programming
    Replies: 4
    Last Post: 08-19-2003, 12:51 PM
  4. format specifiers quick question
    By meltingdude in forum C Programming
    Replies: 2
    Last Post: 06-21-2003, 08:19 AM
  5. gcc/borland and sscanf format specifiers
    By Sargnagel in forum C Programming
    Replies: 2
    Last Post: 01-24-2003, 06:40 PM