0

I would like to name output files based on a base filename with a different extension. In C psuedo-code:

a_file = fopen(filename + ".dt1","wt");
b_file = fopen(filename + ".dt2","wt");
c_file = fopen(filename + ".dt3","wt");

I tried following this example using strncat, but my program keeps appending to filename.

f1=fopen(strcat(filename,".dt1"),"wt");
f2=fopen(strcat(filename,".dt2"),"wt");
f3=fopen(strcat(filename,".dt3"),"wt");

This outputs:

filename.dt1
filename.dt1.dt2
filename.dt1.dt2.dt3

I need the end result to look like:

filename.dt1
filename.dt2
filename.dt3
Community
  • 1
  • 1
user785179
  • 919
  • 5
  • 14
  • 24
  • Can't u use a different variable every time, thus having one variable as fileName and using the same string stored in fileName the other types since according to the help of strcat, it changes the contents of the destination string – chaitanya Aug 06 '12 at 21:20
  • Can't you just increment the last character each time? – Kerrek SB Aug 06 '12 at 21:28

5 Answers5

7

Your code is working as expected considering that strcat appends the extension to the given string. You're using only one string, and so the extensions get stacked upon one another.

Here's one way to do this, amending your posted code which uses a single string for filename:

size_t len = strlen(filename);
f1 = fopen(strcat(filename, ".dt1"), "wt");
filename[len] = '\0';
f2 = fopen(strcat(filename, ".dt2"), "wt");
filename[len] = '\0';
f3 = fopen(strcat(filename, ".dt3"), "wt");

Setting this index to \0 effectively truncates filename back to the original string between calls.

Note that filename must be large enough to contain the appended extensions - room for 4 additional characters - and that by doing this you'll lose the intermediate file names after opening each file.

Alternately, if your extensions will only differ in the last character:

size_t len = 0;
f1 = fopen(strcat(filename, ".dt1"), "wt");
len = strlen(filename);
filename[len - 1] = '2';
f2 = fopen(filename), "wt");
filename[len - 1] = '3';
f3 = fopen(filename, "wt");

The same caveats as above apply.

Note: this answer assumes that filename has been allocated correctly and with sufficient space to store the string lengths being used, as mentioned above.

pb2q
  • 58,613
  • 19
  • 146
  • 147
  • 1
    It might be helpful to note why he is getting his problem. He is appending them on top of each other because he is reusing the same string instead of creating a source string. – kurtzbot Aug 06 '12 at 21:22
  • 1
    We know nothing of how storage is allocated for `filename` - lots of potential for buffer overruns and it to go bang. – marko Aug 06 '12 at 21:28
7

That's because strcat writes directly to the buffer of the first string.

The easiest way is probably to use snprintf to join the two strings together:

snprintf(filename_a, n+4, "%s.dt1", filename);
snprintf(filename_b, n+4, "%s.dt2", filename);
snprintf(filename_c, n+4, "%s.dt3", filename);

Here, filename is of length n (including the trailing \0), and filename_a, filename_b and filename_c are buffers of length at least n+4.

(You could also use sprintf, but it's always good to be careful.)

Sebastian Paaske Tørholm
  • 49,493
  • 11
  • 100
  • 118
2

Pretty much reasonable output of yours I would say:

char * strcat ( char * destination, const char * source );

Appends a copy of the source string to the destination string. The terminating null character in destination is overwritten by the first character of source, and a new null-character is appended at the end of the new string formed by the concatenation of both in destination.

So, character array pointed to by filename is both returned from strcat and gets modified with concatenation result.

Very easy fix is to remember filename length before modification and then:

filename[filename_length_before_modification] = '\0';

this will effectively cut appended extension and get you back to starting point

Roman Saveljev
  • 2,544
  • 1
  • 21
  • 20
  • How do I find out the length of 'filename' (array)? I assume doing something like int len = sizeof(filename)? And then filename[int] = '\0'? – user785179 Aug 06 '12 at 21:28
  • better use strlen(filename). sizeof(filename) at its best can return total size of the array and then you will be writing past its boundary. Depending on how you declared it it may also just return sizeof(char*) – Roman Saveljev Aug 06 '12 at 21:30
2

Kind of a pain with standard C libs, but this is the way I would do it.

    char *fn = malloc(strlen(filename+5)); // Allocate a string with enough space
                                           // for the extensions.

    sprintf(fn, "%s.dt1", filename);       // Copy the name with extensions into fn.
    a_file = fopen(fn,"wt");               //
    sprintf(fn, "%s.dt2", filename);       //
    b_file = fopen(fn,"wt");               //
    sprintf(fn, "%s.dt3", filename);       //
    c_file = fopen(fn,"wt");               //

    free(fn); // Free the memory gained from malloc.
Kevin Cox
  • 3,080
  • 1
  • 32
  • 32
DavidMFrey
  • 1,658
  • 1
  • 14
  • 14
  • Thanks. Your code worked fine, although no explanation. :( Your code with explanations from pb2q and Sebastian Paaske Tørholm above helped me understand how strcat works. – user785179 Aug 06 '12 at 22:35
1

A more efficent way. It only copies the extension each time. It can be made even more efficient if we assume that only the last character changes (see pb2q's second solution).

(Untested, off by one likely)

size_t len = strlen(filename);
char *buf = malloc(len+4); // Allocate a string with enough space for the
                           // extensions.
strcpy(buf, filename);
char *ext = buf+len // Get a pointer to where the extension starts.

strcpy(ext, ".dt1");             // Copy the name with extensions into fn.
FILE *a_file = fopen(buf, "wt"); //
strcpy(ext, ".dt2");             // 
FILE *b_file = fopen(buf, "wt"); //
strcpy(ext, ".dt3");             // 
FILE *c_file = fopen(buf, "wt"); //

free(buf); // Free the memory gained from malloc.
Community
  • 1
  • 1
Kevin Cox
  • 3,080
  • 1
  • 32
  • 32