2

I have a file name "test.mf" as a character pointer. I want to change extension of this file into "test.pfb". I am writing a simple code for this but it is resulting in printing some garbage characters. Running same code on online C compiler results in no garbage values but running it using GCC results in garbage value. If I can achieve the same thing (changing file extension of .mf file to .pfb) in a much better, fast way please suggest. I am new in this so please ignore silly mistakes.

Code

char *Get_PFB_font_file_name(char *TTF_Font_name) 
{
    size_t alen = strlen(TTF_Font_name);
    alen = alen+1; 
    char mystring[alen];
    const char* extension = ".pfb";
    char *PFB_File= malloc(alen+1);
    strncpy(mystring, TTF_Font_name, alen-4);
    strcat( mystring, extension );
    strncpy(PFB_File, mystring, alen);

    if(!PFB_File)
    {
        printf("error in get TTX conversion function");
        exit(1);
    } 
    return PFB_File;
}

int main ( void )
{
    char *MF_Font_file_name = "test.mf";
    char *PFB_Font_file_name;
    PFB_Font_file_name = Get_PFB_font_file_name(MF_Font_file_name);
    printf("PFB font file name is %s \n", PFB_Font_file_name); // garbage value here (test�.p)

    return 0;
}
WedaPashi
  • 3,561
  • 26
  • 42
Ammar Ul Hassan
  • 826
  • 1
  • 18
  • 48
  • 2
    `strncpy(mystring, TTF_Font_name, alen-4);`: that doesn't nul-terminate right? – Jean-François Fabre Nov 22 '17 at 08:25
  • 2
    @EdHeal it's to be sure that the C++ compiler isn't used :) – Jean-François Fabre Nov 22 '17 at 08:25
  • 2
    [The `strncpy` function](http://en.cppreference.com/w/c/string/byte/strncpy) might not terminate the string in one case. And that happens for you. – Some programmer dude Nov 22 '17 at 08:25
  • And then `strcat` goes *WTF?* so add `mystring[alen-4] = 0;` after your first call to `strncpy` before `strcat` (and you will want to insure `mystring` is again *nul-terminated* after `strncpy(PFB_File, mystring, alen);` – David C. Rankin Nov 22 '17 at 08:26
  • you forgot the null termination of string – danglingpointer Nov 22 '17 at 08:28
  • @DavidC.Rankin Thanks i have fixed it by adding a null termination. Can u suggest me if this is the right way to achieve what i want or can i improve it by some other way? – Ammar Ul Hassan Nov 22 '17 at 08:40
  • @EdHeal What's wrong with `new`? Should we really care about keywords from any language we don't use? If this will break the code in C++, that's a nice bonus. – Gerhardh Nov 22 '17 at 08:40
  • @Gerhardh - It is a keyword for C++ and other languages - so may lead to confusion. Also it is not a meaningful variable name – Ed Heal Nov 22 '17 at 09:06
  • @EdHeal There are lots of keywords in other languages which are also not relevant for C. If it forces the reader to think a few seconds, that's not a bad thing. It reminds them that it is not C++. – Gerhardh Nov 22 '17 at 09:21

1 Answers1

4

about strncpy:

The strncpy() function is similar (to strcpy), except that at most n bytes of src are copied. Warning: If there is no null byte among the first n bytes of src, the string placed in dest will not be null-terminated.

strncpy(mystring, TTF_Font_name, alen-4);
strcat( mystring, extension );

this has undefined behaviour because TTF_Font_name is longer than alen-4 so the warning/limitation above applies, and strcat cannot compute the size of mystring properly.

One way to fix it: just insert this between the two lines:

mystring[alen-4] = '\0';
user2736738
  • 30,591
  • 5
  • 42
  • 56
Jean-François Fabre
  • 137,073
  • 23
  • 153
  • 219
  • @AmmarUlHassan: sorry conflicting edits. But semicolon added thanks. – Jean-François Fabre Nov 22 '17 at 08:31
  • I tried that but same garbage value. I have a similar function in same file which almost uses same variable names. can it be the cause of it? – Ammar Ul Hassan Nov 22 '17 at 08:32
  • Thanks it worked. Do you think it is the right way to do what i want to achieve can i improve this? – Ammar Ul Hassan Nov 22 '17 at 08:39
  • there's a way to use `printf` to limit the size but the formatting must be passed as literal, so in your case it's not very convenient. Handling strings is C is very manual, close to the asm level. Of course, using C++ would improve string handling (now that you renamed `new` :)) Seriously, I suggest that you create a small set of tested functions to handle those extension replacements. Once tested & robust, you can use them everywhere in your project(s), instead of copying pasting some buggy code around. – Jean-François Fabre Nov 22 '17 at 08:45
  • also, make sure you're allocating enough bytes for your dest string. It seems OK but a bit complicated (with your many +1s). If you don't want to be bothered, use a big auto buffer like `char buf[1000];`, and use `strdup` in the end. – Jean-François Fabre Nov 22 '17 at 08:47
  • ahh fine. Thanks alot. Actually i was trying to avoid creating a buffer (giving a manual size) but thats an alternate. As far as +1's are concerned actually as u noticed extensions may be 3 characters or 2 like "mf" and "pfb" in that case it varies so i had to do it manually. – Ammar Ul Hassan Nov 22 '17 at 08:52
  • 1
    Don't skimp on buffer sizes. Sure, be reasonable, but I would a lot rather have a buffer that is 1000 bytes too long, than one that is 1-byte too short `:)` – David C. Rankin Nov 22 '17 at 09:41
  • @DavidC.Rankin specially on auto memory, when allocation is done with a single addition. OK maybe 1000 is too much but shaving it too close like you're on a 8-bit 1980 machine is as stupid. – Jean-François Fabre Nov 22 '17 at 09:46
  • 1
    Yes, I agree. If I was sure the max was 30 chars, 64 or 128 would be reasonable. If I wanted to be 100% (or as close as possible safe), I would use `PATH_MAX` -- which with gcc gives a whopping 8192 bytes `:)` – David C. Rankin Nov 22 '17 at 09:50