3
\$\begingroup\$

Is there a simple way to concatenate all of the fprintf(qFile, "%-1.1c", mod[cnt].name[x]); expressions into a small number of expressions?

Appreciate any other suggestions.

    #include "stdafx.h"
    #include <stdio.h>
    #include <iostream>

    // fprintfQuestion.cpp : Defines the entry point for the console application.
    // add _CRT_SECURE_NO_DEPRECATE  to Properties \ C\C++ \ Preprocessor \  Preprocessor Definitions

    struct mod
    {
        char    name[32];
        int     dateStart;
        int     dateEnd;
    };

The struct mod is an abbreviated version of the struct used in a GUI editor for the game for which I'm an apprentice developer. The full struct includes about 20 variables. Objects from this struct correspond to "script modules" used by the game's computer-opponent, and which can be randomly or statically assigned to specific scenarios in the game by scenario designers.

The goal of the exercise I'm engaged in at present is to develop a "loader" application that can transfer data between the .dat files the editor works with and .csv files that humans can manipulate in spreadsheets. Most of the scenario designers are not programmers.

    int main()
    {
        FILE     *pFile, *qFile;
        int      cnt = 0, n = 0;
        char     str[40]; //1328
        mod      mod[3]; //2000
        long     bytes = 1328; // first record of 0 to 1327 is blank

    pFile = fopen("W:\\User\\dir\\sourcefile.dat", "rb");
    qFile = fopen("W:\\User\\dir\\targetfile.csv", "a");

    for (cnt = 0; cnt < 3; cnt++)
       {
        fseek(pFile, bytes, SEEK_SET);
          for (n = 0; n < 40; n++)
             {
               str[n] = getc(pFile);
             };
          memmove(mod+cnt, str, 40);
          fprintf(qFile, "%-1.1c", mod[cnt].name[0]);
          fprintf(qFile, "%-1.1c", mod[cnt].name[1]);
          fprintf(qFile, "%-1.1c", mod[cnt].name[2]);
          fprintf(qFile, "%-1.1c", mod[cnt].name[3]);
          fprintf(qFile, "%-1.1c", mod[cnt].name[4]);
          fprintf(qFile, "%-1.1c", mod[cnt].name[5]);
          fprintf(qFile, "%-1.1c", mod[cnt].name[6]);
          fprintf(qFile, "%-1.1c", mod[cnt].name[7]);
          fprintf(qFile, "%-1.1c", mod[cnt].name[8]);
          fprintf(qFile, "%-1.1c", mod[cnt].name[9]);
          fprintf(qFile, "%-1.1c", mod[cnt].name[10]);
          fprintf(qFile, "%-1.1c", mod[cnt].name[11]);
          fprintf(qFile, "%-1.1c", mod[cnt].name[12]);
          fprintf(qFile, "%-1.1c", mod[cnt].name[13]);
          fprintf(qFile, "%-1.1c", mod[cnt].name[14]);
          fprintf(qFile, "%-1.1c", mod[cnt].name[15]);
          fprintf(qFile, "%-1.1c", mod[cnt].name[16]);
          fprintf(qFile, "%-1.1c", mod[cnt].name[17]);
          fprintf(qFile, "%-1.1c", mod[cnt].name[18]);
          fprintf(qFile, "%-1.1c", mod[cnt].name[19]);
          fprintf(qFile, "%-1.1c", mod[cnt].name[20]);
          fprintf(qFile, "%-1.1c", mod[cnt].name[21]);
          fprintf(qFile, "%-1.1c", mod[cnt].name[22]);
          fprintf(qFile, "%-1.1c", mod[cnt].name[23]);
          fprintf(qFile, "%-1.1c", mod[cnt].name[24]);
          fprintf(qFile, "%-1.1c", mod[cnt].name[25]);
          fprintf(qFile, "%-1.1c", mod[cnt].name[26]);
          fprintf(qFile, "%-1.1c", mod[cnt].name[27]);
          fprintf(qFile, "%-1.1c", mod[cnt].name[28]);
          fprintf(qFile, "%-1.1c", mod[cnt].name[29]);
          fprintf(qFile, "%-1.1c", mod[cnt].name[30]);
          fprintf(qFile, "%-1.1c,", mod[cnt].name[31]);
          fprintf(qFile, "%.6i,", mod[cnt].dateStart);
          fprintf(qFile, "%.6i,", mod[cnt].dateEnd);
          fprintf(qFile,"\n");
          bytes = (bytes + 1328);
    };

    fclose(pFile);
    fclose(qFile);
    std::cout << "Type any key to quit. \n";
    std::cin.get();
    return 0;
}

As far as I know, there are no null-terminated records in the data; my examination of the .dat files with HexEdit does not suggest as much to me.

A typical row of output in the .csv that this code generates might be:

Attack Orleans Rgt,281012,291228

Corresponding to the name of the script, the date it can start (12 Oct 1428) and the date it can end (28 Dec 1429).

\$\endgroup\$
11
  • \$\begingroup\$ Please verify your indentation. The easiest way to post code is to paste it, highlight it, and press Ctrl-K to mark it as a code block. \$\endgroup\$ Feb 23, 2017 at 19:05
  • 1
    \$\begingroup\$ What does a struct mod represent? What are you really aiming to accomplish with this code? \$\endgroup\$ Feb 23, 2017 at 19:07
  • 3
    \$\begingroup\$ Is there some reason a simple loop wouldn't work? for (i=0; i<32; i++) fprintf(qfile, "%-1.1c", mod[cnt].name[i]); \$\endgroup\$ Feb 23, 2017 at 19:07
  • \$\begingroup\$ Thnx for the headsup on the indentation 200_success. There are .dat files each with around 2 million bytes of data of varying types. The struct I present here is an abbreviated version of the actual struct used in the editor (the source code we do not have). These .dat files are used by an gui "editor" application by developers and "modders" building scenarios for the game. The goal is to enable full i/o between .dat files and .csv files. \$\endgroup\$
    – Diche Bach
    Feb 23, 2017 at 19:12
  • 1
    \$\begingroup\$ @DicheBach Can you explain why you use "%-1.1c" as your format string? Doesn't that just print one character? You specify left alignment, minimum one character, and precision one character, but I don't see how that is any different than just "%c" when we are talking about printing single characters? Perhaps you could show us an example of a line of output. \$\endgroup\$
    – JS1
    Feb 23, 2017 at 19:32

2 Answers 2

4
\$\begingroup\$

Merge all fprintf()s into a single one

You could try merging all of your fprintf() calls into this single call:

fprintf(qFile, "%.32s,%.6i,%.6i,\n", mod[cnt].name, mod[cnt].dateStart,
        mod[cnt].dateEnd);

The %.32s specifier means "print a string up to 32 characters long". From the example output you showed in the comments, I think that this would work for you. If you don't need a trailing comma at the end of the line, you could remove it. (Your code had it there but your example didn't so I left it in).

Use fread()

Instead of this loop and memmove():

    for (n = 0; n < 40; n++)
         {
           str[n] = getc(pFile);
         };
    memmove(mod+cnt, str, 40);

You could use one call to fread:

    fread(&mod[cnt], 1, sizeof(mod[cnt]), pFile);

You might want to static_assert that sizeof(struct mod) == 40 somewhere, since your code seems to depend on that.

\$\endgroup\$
8
  • \$\begingroup\$ "%.32s" assumes that name is a null-terminated, which the author has not confirmed. (I've downvoted the question for lack of clarity.) \$\endgroup\$ Feb 23, 2017 at 21:29
  • \$\begingroup\$ As far as I know, none of it is null-terminated. How would I know if it is for certain? @JS1: thanks for the suggestions! I will check it out. \$\endgroup\$
    – Diche Bach
    Feb 23, 2017 at 22:03
  • \$\begingroup\$ @200_success Even if name is not null-terminated, "%.32s" will still only print the first 32 characters, so I'm not sure what the problem is. \$\endgroup\$
    – JS1
    Feb 23, 2017 at 22:52
  • \$\begingroup\$ It could also contain internal nulls, though. \$\endgroup\$ Feb 23, 2017 at 22:53
  • \$\begingroup\$ Yep, those changes worked JS1. I'm tempted to post the revised version of it, but not sure if that is poor etiquette or if I would do it in an answer or as an edit to the original post. Anyway thanks to everyone for responding. I've learned more about C/C++ and that is always a good thing! :) \$\endgroup\$
    – Diche Bach
    Feb 23, 2017 at 23:00
0
\$\begingroup\$

Sorry if this is bad etiquette, but the help I've received has been so decisive and clear, I wanted to post the "revised" version of the code based on the suggestions received above, and especially the accepted answer by JS1

#include "stdafx.h"
#include <stdio.h>
#include <iostream>

// fprintfQuestion.cpp : Defines the entry point for the console application.
// add _CRT_SECURE_NO_DEPRECATE  to Properties \ C\C++ \ Preprocessor \  Preprocessor Definitions

struct mod
{
    char    name[32];
    int     dateStart;
    int     dateEnd;
};

static_assert (sizeof(mod) == 40, "Struct mod is != 40.");

int main()
{
    FILE     *pFile, *qFile;
    int      cnt = 0, n = 0, i = 0;
    char     str[40]; //1328
    mod      mod[3]; //2000
    long     bytes = 1328; // first record of 0 to 1327 is blank

    pFile = fopen("W:\\User\\dir\\sourcefile.dat", "rb");
    qFile = fopen("W:\\User\\dir\\targetfile.csv", "a");

    for (cnt = 0; cnt < 3; cnt++)
    {
        fseek(pFile, bytes, SEEK_SET);
        fread(&mod[cnt], 1, sizeof(mod[cnt]), pFile);
        fprintf(qFile, "%.32s,%.6i,%.6i,\n", mod[cnt].name, mod[cnt].dateStart, 
        mod[cnt].dateEnd);
        bytes = (bytes + 1328);
    };

    fclose(pFile);
    fclose(qFile);
    std::cout << "Type any key to quit.\n";
    std::cin.get();
    return 0;
}
\$\endgroup\$
2
  • \$\begingroup\$ The revised version might be a good candidate for a new question. There is still a lot that can be improved here, if you're interested. \$\endgroup\$
    – Edward
    Feb 24, 2017 at 1:49
  • \$\begingroup\$ @Edward Cool, yeah. Let the suggestions ensue! \$\endgroup\$
    – Diche Bach
    Feb 24, 2017 at 13:51

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge that you have read and understand our privacy policy and code of conduct.

Not the answer you're looking for? Browse other questions tagged or ask your own question.