4

I'm doing an exercise in K&R:

Write a program detab that replaces tabs in the input with the proper number of blanks to space to the next tab stop.

And this is what I have so far (w/o error checking on the file):

#include <stdio.h>
#define tab 2
#define MAX_LENGTH 1000
int main(int argc, char **argv)
{
    FILE *fp = fopen(argv[1], "r+");    
    int c, n;
    char buffer[MAX_LENGTH + 1];
    for (n = 0; n < MAX_LENGTH && (c = fgetc(fp)) != EOF; ++n) {
        if (c == '\t') {
            for (int x = 0; x < tab; ++x)
                buffer[n++] = ' ';
            --n;
        }
        else
            buffer[n] = c;
    }
    //buffer[n] = '\0';
    //rewind(fp);
    //fputs(buffer, fp);
    printf("%s\n", buffer);
    fclose(fp);
    return 0;
}

It seems to work, but I'm wondering why \0 wasn't needed at the end. Was I just lucky?

Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
mwlow
  • 141
  • 10

4 Answers4

5

Yes, you were lucky. To avoid this problem, you could have used fwrite, which doesn't require a null terminator (since you specify exactly how many bytes to write):

fwrite(buffer, 1, n, stdout);
Greg Hewgill
  • 951,095
  • 183
  • 1,149
  • 1,285
4

You can tell printf(...) the (maximum) number of characters to print for a given string.

printf("%.*s\n", n, buffer);

See printf(3), section "The precision":

An optional precision, in the form of a period ('.') followed by an optional decimal digit string. Instead of a decimal digit string one may write "*" [...] to specify that the precision is given in the next argument [...], which must be of type int. [...] This gives [...] the maximum number of characters to be printed from a string for s [...] conversions.

Live demo of printf ("%.*s\n", 5, "Hello, world!"): http://ideone.com/KHKLl.

Kijewski
  • 25,517
  • 12
  • 101
  • 143
2

You can initialize your buffer with:

memset(buffer, '\0', MAX_LENGTH + 1);

And you wont have to worry about the null termination.

Francisco Soto
  • 10,277
  • 2
  • 37
  • 46
  • 1
    He won't overrun the buffer in this case - the position in the buffer (`n`) is checked to be less than `MAX_LENGTH`. In his code, `MAX_LENGTH` is the maximum output length, not input. – Timothy Jones Jan 05 '12 at 03:19
  • Ah good point, for some reason I "saw" he was using another variable in the for. – Francisco Soto Jan 05 '12 at 03:32
1

As the other answers have pointed out, you were lucky that the array contained nulls at the right places.

You can initialise it when you create it using this shorthand:

char buffer[MAX_LENGTH + 1] = { 0 }; // all elements will be zero

Note that this is because the compiler will initialise unspecified entries with zeroes - so if you said

char buffer[MAX_LENGTH + 1] = { 'a' };

then the array would be {'a',0,0,0....}

Timothy Jones
  • 21,495
  • 6
  • 60
  • 90
  • Thanks for the tip. I never noticed {0} set all elements to be zero only because unspecified entries will be initialized to zero. – mwlow Jan 05 '12 at 06:28