134

Suppose you have a string which is NOT null terminated and you know its exact size, so how can you print that string with printf in C? I recall such a method but I can not find out now...

hbagdi
  • 485
  • 6
  • 18
whoi
  • 3,281
  • 7
  • 36
  • 44
  • 10
    In `C` context, all strings are null terminated. Arrays of char without a null in them are not strings ... they are arrays of char :) – pmg Sep 22 '10 at 09:30
  • 6
    possible duplicate of [How do I print a non-null-terminated string using printf?](http://stackoverflow.com/questions/2137779/how-do-i-print-a-non-null-terminated-string-using-printf) – Justin Nov 08 '11 at 09:49
  • https://stackoverflow.com/questions/2239519/is-there-a-way-to-specify-how-many-characters-of-a-string-to-print-out-using-pri – Ciro Santilli OurBigBook.com Jul 30 '17 at 09:57
  • You want to print "My String\0\0\0\0random characters"? – Sandburg Mar 04 '22 at 08:30
  • Does this answer your question? [How do I print a non-null-terminated string using printf?](https://stackoverflow.com/questions/2137779/how-do-i-print-a-non-null-terminated-string-using-printf) – malat Apr 13 '22 at 13:54

6 Answers6

214

There is a possibility with printf, it goes like this:

printf("%.*s", stringLength, pointerToString);

No need to copy anything, no need to modify the original string or buffer.

DarkDust
  • 90,870
  • 19
  • 190
  • 224
  • 6
    @Pmod: Not necessarily if the buffer is not exposed to the outside world. It's also very useful to just print *parts* of a string (which may be null terminated, of course). If you really want to see this in action, have a look at the OpenSER/Kamailio SIP proxy where they avoid copying stuff due to this technique a lot (also using sprintf). – DarkDust Sep 22 '10 at 08:53
  • I don't have anything against printing a part of NULL-terminated string in a way you described. I also do in that way in my progs. But I am against using NON-NULL-terminated strings to pretend that they're terminated. Someone may some day str(n)cpy it or expose outside without noticing this specific. – pmod Sep 22 '10 at 10:16
  • 1
    @pmod: to your concerns, I typically declare an array of `uint8_t` instead of `char`, as an attempt to make it clear that it is not a null-terminated string. – tomlogic Mar 31 '13 at 22:00
  • 1
    For me it's very useful when I receive a non-null terminated string from an API (some windows API do this!) and have to return it in a 'reasonable' way. So: long life to %.*s (or %.*S which will also make the conversion UNICODE <-> SINGLE-BYTE for you! ;) ) – FrizzTheSnail Jul 12 '13 at 15:46
  • Does this actually work? I try a string not terminated by null, but containing a null in the middle, it only printed up to the null character in the middle. ```#include int main() { char x[] = "Hello" "\0" "World"; printf("%.*s", 11, x); return 0; } ``` – user1424739 Feb 16 '19 at 17:31
  • 8
    @user1424739: In your case `printf` will print up to 11 characters _or_ until it encounters NULL, whichever comes first; in your example NULL comes first. Specifying a maximum length does not make NULL lose its "end-of-string" meaning for `printf`. – DarkDust Feb 17 '19 at 08:59
37

Here is an explanation of how %.*s works, and where it's specified.

The conversion specifications in a printf template string have the general form:

% [ param-no $] flags width [ . precision ] type conversion

or

% [ param-no $] flags width . * [ param-no $] type conversion

The second form is for getting the precision from the argument list:

You can also specify a precision of ‘*’. This means that the next argument in the argument list (before the actual value to be printed) is used as the precision. The value must be an int, and is ignored if it is negative.

— Output conversion syntax in the glibc manual

For %s string formatting, precision has a special meaning:

A precision can be specified to indicate the maximum number of characters to write; otherwise characters in the string up to but not including the terminating null character are written to the output stream.

— Other output conversions in the glibc manual

Other useful variants:

  • "%*.*s", maxlen, maxlen, val will right-justify, inserting spaces before;
  • "%-*.*s", maxlen, maxlen, val will left-justify.
Tobu
  • 24,771
  • 4
  • 91
  • 98
  • 1
    If I understand correctly, the following would pad the output yet still prevent a string overflow? `"%-*.*s", padding, str_view.size(), str_view.data()` – scx Feb 25 '18 at 01:01
27

You can use an fwrite() to stdout!

fwrite(your_string, sizeof(char), number_of_chars, stdout);

This way you will output the first chars (number defined in number_of_chars variable ) to a file, in this case to stdout (the standard output, your screen)!

Pedro Sousa
  • 380
  • 3
  • 10
17

printf("%.*s", length, string) will NOT work.

This means to print UP TO length bytes OR a null byte, whichever comes first. If your non-null-terminated array-of-char contains null bytes BEFORE the length, printf will stop on those, and not continue.

Kirk Woll
  • 76,112
  • 22
  • 180
  • 195
Todd Freed
  • 877
  • 6
  • 19
  • 6
    And how is this an answer to the OP's question? – Shahbaz Sep 15 '11 at 12:31
  • 17
    if it's not null-terminated, then null is a valid character for the string to contain. this still thinks the array is null-terminated, it just treats it as a longer array that it's sub-selecting from - which means that if you have a string with nulls in it, this will cause problems. – lahwran Mar 16 '16 at 00:39
3
printf("%.5s", pointerToNonNullTerminatedString);

The string length will be 5.

codeDom
  • 1,623
  • 18
  • 54
1
#include<string.h> 
int main()
{
/*suppose a string str which is not null terminated and n is its length*/
 int i;
 for(i=0;i<n;i++)
 {
 printf("%c",str[i]);
 }
 return 0;
}

I edited the code,heres another way:

#include<stdio.h>
int main()
{
printf ("%.5s","fahaduddin");/*if 5 is the number of bytes to be printed and fahaduddin is the string.*/

return 0;

}
  • Very bad performance due to lots of unnecessary byte reads (which come with a performance penalty if the the byte is not on a word-aligned address on most CPUs) and also the formatting parsing and applying is done for each and every character. Don't do that :-) See my answer for the solution. – DarkDust Sep 22 '10 at 13:28
  • @DarkDust: only a pathological machine would penalize byte reads not aligned to word boundaries. Are you thinking of word reads not aligned to word boundaries? Or some ancient mips crap or something? – R.. GitHub STOP HELPING ICE Sep 23 '10 at 03:33
  • @R..: If you consider x86 brain-damaged and out-dated, I absolutely agree. Because x86 does have a penalty for reading and write non-word aligned memory. So does ARM. See for example [this question](http://stackoverflow.com/questions/3025125/cpu-and-data-alignment) or [this question](http://stackoverflow.com/questions/1855896/memory-alignment-on-modern-processors). The thing is (if I understood that correctly) that data is fetched in word-size chunks from memory and getting the correct byte is another micro-op. No big deal, but in a huge loop it might make a difference. – DarkDust Sep 23 '10 at 06:50
  • @DarkDust: you are completely wrong about that for byte reads. Why don't you go do a benchmark? x86 has completely atomic byte operations and always had. It does not fetch word-size chunks (except at the cache level, which fetches much larger chunks and alignment is irrelevant, but I'm talking about already-cached data). – R.. GitHub STOP HELPING ICE Sep 23 '10 at 13:28
  • @DarkDust: PS3 does not support unaligned byte read or write on SPU. In fact it does not even support scalar types, there are only vector, that must be aligned. The compiler emulate them. And many ARM processor does not support byte read or write, but only perform word read or write. – Sylvain Defresne Mar 15 '11 at 22:32