1

So, I'm rewriting the tar extract command, and I stumbled upon a weird problem:

In short, I allocate a HEADER struct that contains multiple char arrays, let's say:

struct HEADER {
     char foo[42];
     char bar[12];
}

When I fprintf foo, I get a 3 character-long string, which is OK since the fourth character is a '\0'. But when I print bar, I have 25 characters that are printed.

How can I do to only get the 12 characters of bar?

EDIT The fact that the array isn't null terminated is 'normal' and cannot be changed, otherwise I wouldn't have so much trouble with it. What I want to do is parse the x first characters of my array, something like

char res[13];
magicScanf(res, 12, bar);
res[12] = '\0'

EDIT It turns out the string WAS null-terminated already. I thought it wasn't since it was the most logic possibility for my bug. As it's another question, I'll accept an answer that matched the problem described. If someone has an idea as to why sprintf could've printed 25 characters INCLUDING 2 \0, I would be glad.

Turtle
  • 1,626
  • 16
  • 26
  • 1
    Make sure to add a terminating '\0' manually at the end of bar[] array – Cherubim May 07 '17 at 17:02
  • That's what I've one for now, but it overrides the informations written after in memory. I have to parse the 12 characters, then stop. – Turtle May 07 '17 at 17:13
  • If you need to store 12 characters, you need an array of size char[12+1], additional char to store \0 which marks the end of the string – Cherubim May 07 '17 at 17:16
  • @Cherubim I edited my question, as I realized it wasn't clear at all – Turtle May 07 '17 at 17:21
  • `sprintf` should never copy a null character -- but if it copies, say, 10 characters, any existing null characters past position 10 in the target array will not be overwritten. If that doesn't answer your question, post a new question with the code that causes the problem. (Looks like the question changed from `fprintf` to `sprintf`.) – Keith Thompson May 09 '17 at 18:33

4 Answers4

1

You can print strings without NUL terminators by including a precision:

printf ("%.25s", s);

or, if your precision is unknown at compilation time:

printf ("%.*s", length, s);
Luis Colorado
  • 10,974
  • 1
  • 16
  • 31
Jonathon Reinhart
  • 132,704
  • 33
  • 254
  • 328
0

The problem is that the size of arrays are lost when calling a function. Thus, the fprintf function does not know the size of the array and can only end at a \0.

JohanL
  • 6,671
  • 1
  • 12
  • 26
0

No, unless you have supplied the precision, fprintf() has no magical way to know the size of the array supplied as argument to %s, it still relies on the terminating null.

Quoting C11, chapter §7.21.6.1, (emphasis mine)

s

If no l length modifier is present, the argument shall be a pointer to the initial element of an array of character type.280) Characters from the array are written up to (but not including) the terminating null character. If the precision is specified, no more than that many bytes are written. If the precision is not specified or is greater than the size of the array, the array shall contain a null character.

So, in case your array is not null terminated, you must use a precision wo avoid out of bound access.

Community
  • 1
  • 1
Sourav Ghosh
  • 133,132
  • 16
  • 183
  • 261
0
void printbar(struct HEADER *h) {
    printf("%.12s", h->bar);
}

You can use it like this

struct HEADER data[100];
/* ... */
printbar(data + 42); /* print data[42].bar */

Note that if one of the 12 bytes of bar has a value of zero, not all of them get printed.
You might be better off printing them one by one

void printbar(struct HEADER *h) {
    printf("%02x", h->bar[0]);
    for (int i = 1; i < 12; i++) printf(" %02x", h->bar[i]);
}
pmg
  • 106,608
  • 13
  • 126
  • 198