null以外で終了する文字列でのprintfの使用


107

null終端されていない文字列があり、その正確なサイズがわかっているとしましょうprintf。Cでその文字列をどのように印刷できますか?そのような方法を思い出しましたが、今はわかりません...


9
ではC、コンテキスト、すべての文字列がnullで終了しています。nullを含まないcharの配列は文字列ではありません...それらはcharの配列です:)
pmg


回答:


174

printfには可能性があります。次のようになります。

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

何もコピーする必要も、元の文字列やバッファを変更する必要もありません。


10
しかし、いずれにしても危険です。誰かがこの文字列を%sでいつかprintfします
pmod

6
@Pmod:バッファが外部に公開されていない場合は、必ずしもそうではありません。文字列の一部を印刷することも非常に便利です(もちろんnullで終了することもあります)。これが実際に動作することを確認したい場合は、OpenSER / Kamailio SIPプロキシを確認してください。この手法により、この手法(sprintfも使用)が原因で、データのコピーが回避されます。
DarkDust 2010

6
別の+1。printf〜10年後のような基本的なことについて学ぶとき、私はそれが大好きです... :)
ヘルツェル・ギネス

1
私にとっては、APIからnullで終了していない文字列を受け取り(一部のWindows APIがこれを行う!)、それを「合理的な」方法で返す必要がある場合に非常に便利です。したがって、%。* s(または%。* Sに変換すると、UNICODE <-> SINGLE-BYTEにも変換されます;))までの
寿命

3
@ user1424739:あなたのケースでprintfは、最大11文字、または NULLに遭遇するまで、どちらか早い方で出力されます。あなたの例ではNULLが最初に来ます。最大長を指定しても、NULLがの「文字列の終わり」の意味を失うことはありませんprintf
DarkDust

29

これがどのように%.*s機能するか、そしてそれがどこに指定されているかの説明です。

printfテンプレート文字列の変換仕様は、一般的な形式を持っています。

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

または

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

2番目の形式は、引数リストから精度を取得するためのものです。

'*'の精度を指定することもできます。これは、引数リストの次の引数(出力される実際の値の前)が精度として使用されることを意味します。値は整数でなければならず、負の場合は無視されます。

—  glibcマニュアルの出力変換構文

以下のために%s文字列の書式、精度は特別な意味を持っています:

書き込む文字の最大数を示す精度を指定できます。それ以外の場合、文字列内の終端のnull文字を含まない文字は、出力ストリームに書き込まれます。

—  glibcマニュアルの他の出力変換

その他の便利なバリエーション:

  • "%*.*s", maxlen, maxlen, val 右揃えし、前にスペースを挿入します。
  • "%-*.*s", maxlen, maxlen, val 左揃えになります。

私が正しく理解している場合、以下は出力にパディングしますが、文字列のオーバーフローを防ぎますか?"%-*.*s", padding, str_view.size(), str_view.data()
scx 2018

20

fwrite()を使用してstdoutできます!

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

このようにして、最初の文字(number_of_chars変数で定義された数)をファイルに出力します。この場合は、標準出力(標準出力、画面)に出力します。


2
文字列とゼロを含む長いバッファを検査する場合に非常に役立ちます。
Elist 2016

13

printf("%.*s", length, string) 動作しないでしょう。

これは、最大で長さバイトまたはnullバイトのいずれか早い方を出力することを意味します。nullで終了していないcharのarray-of-charに長さより前のnullバイトが含まれている場合、printfはその長さで停止し、続行しません。


4
そして、これはOPの質問に対する答えですか?
Shahbaz 2011

12
nullで終了していない場合、nullは文字列に含まれる有効な文字です。これは依然として配列がnullで終了していると見なし、それを副選択するより長い配列として扱うだけです。つまり、nullを含む文字列がある場合、問題が発生します。
lahwran

3
printf("%.5s", pointerToNonNullTerminatedString);

文字列の長さは5になります。


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;
}

私はコードを編集しましたが、別の方法があります:

#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;

}

多くの不要なバイト読み取り(バイトがほとんどのCPUでワード境界に整列されていないアドレスにある場合はパフォーマンスペナルティが発生します)と、フォーマットの解析と適用がすべての文字に対して行われるため、非常に悪いパフォーマンス。それをしないでください:-)解決策については私の答えを参照してください。
DarkDust

@DarkDust:ワード境界に揃えられていないバイト読み取りにペナルティを課すのは、病理学的マシンのみです。単語の読みが単語の境界に揃っていないことを考えていますか?またはいくつかの古代のミップがらくたですか?
R .. GitHub ICE HELPING ICEの停止

@R ..:x86が脳の損傷を受けて古くなっていると考えるなら、私は完全に同意します。x86には、非ワード境界整列メモリの読み取りと書き込みに対するペナルティがあるからです。ARMも同様です。たとえば、この質問またはこの質問を参照してください。問題は(私が正しく理解していれば)データがワードサイズのチャンクでメモリからフェッチされ、正しいバイトを取得することが別のマイクロオペレーションであるということです。大したことではありませんが、大きなループでは違いが生じる可能性があります。
-DarkDust

@DarkDust:バイト読み取りの場合は完全に間違っています。ベンチマークをしてみませんか?x86には完全にアトミックなバイト操作があり、常にそうでした。これはワードサイズのチャンクをフェッチしません(キャッシュレベルでは、はるかに大きなチャンクをフェッチし、アラインメントは関係ありませんが、すでにキャッシュされたデータについて話しています)。
R .. GitHub ICE HELPING ICEの停止

@DarkDust:PS3は、SPUでの非境界整列バイトの読み取りまたは書き込みをサポートしていません。実際には、スカラー型もサポートしていません。整列しなければならないのはベクトルのみです。コンパイラはそれらをエミュレートします。また、多くのARMプロセッサはバイトの読み取りまたは書き込みをサポートせず、ワードの読み取りまたは書き込みのみを実行します。
Sylvain Defresne 2011年
弊社のサイトを使用することにより、あなたは弊社のクッキーポリシーおよびプライバシーポリシーを読み、理解したものとみなされます。
Licensed under cc by-sa 3.0 with attribution required.