hanie
hanie

Reputation: 1885

access elements of string after `\0`

Recently I have seen a code in which a string was being sorted, and \0 (since it has smallest ASCII code) came first of the string.

But using format specifier %c the true sorted string was printed, but I checked with %s and nothing was printed.

So here is my question, if I add a \0 in a string (while I have valid value in my string after terminator), could I access those values with something like %c, is it safe? And will this answer always or it just answered because of UB?

Here is an example:

int main()
{
    char a[8]="abcdefg";
    char b[8];
    for (int i = 0; i < 8; i++)
    {
        b[7-i] = a[i];
    }
    for (int i = 0; i < 8; i++)
        printf("%c ", b[i]);
    printf("%s", b);
}

In above example printf("%c ", b[i]); prints the hole string , even after \0.

In second one printf("%s", b); nothing is printed?

Actually I want to know if using first printf is true and legal?

Upvotes: 1

Views: 511

Answers (3)

Yunnosch
Yunnosch

Reputation: 26703

This solution uses a +1 to skip the first unwanted '\0' terminator and the precision part of the format specifier to make sure to only print the desired string length (which I assume to be known, since the size of the array is fixed).

#include <stdio.h>

int main()
{
    char a[8]="abcdefg";
    char b[8];
    for (int i = 0; i < 8; i++)
    {
        b[7-i] = a[i];
    }
    printf("%.7s", b+1);
}

This works because in the call to printf() the parameter b is treated like a pointer to char and a +1 skips the first of those chars, which happens to be the undesired terminator.

Then the '%s' is used, with extended options. The precision specifier .7 set up now minimum width (i.e. no padding) by the empty left side of the . and a maximum of 7 characters to be printed, by the part right of the ..

This way it is possible to print the string with %s and drop the terminator.

In case the length is dynamic (e.g. you want to use the initially unknown length of a) you can upgrade to the next level of complexity and use the *version of the precision. That would allow to put the "7" into a variable instead.

Upvotes: 1

Ardent Coder
Ardent Coder

Reputation: 3995

char a[8]="abcdefg";

Note: a[7] contains '\0' (automatically added).

char b[8];
for (int i = 0; i < 8; i++)
{
    b[7-i] = a[i];
}

Note: b is the reverse of a => b[0] contains the null character ('\0')

Now, getting into your questions:

for (int i = 0; i < 8; i++)
    printf("%c ", b[i]);

This prints b character by character, but not as an entire string. There is no problem in doing this.

And the output will look something like this:

<empty> g f e d c b a

That empty space is because b[0] is a null character.

in second one printf("%s", b); nothing is printed?

Again, b[0] contains the null character i.e. the first character of this string is \0. So it is treated as an empty string though it contains a text. The null character marks the end of a string.

actually I want to know if using first printf is true and legal?

Of course, that can be seen as printing a char array. Not every char array has to be a "string"!

Upvotes: 3

Šimon T&#243;th
Šimon T&#243;th

Reputation: 36433

A string is just an array of characters. So as long as you don't go out of bounds of the array, everything is well defined.

This of course requires you to know the "capacity" of the string.

Upvotes: 0

Related Questions