Printf'i boş olmayan sonlandırılmış bir dizeyle kullanma


108

Diyelim ki nullsonlandırılmamış bir dizge var ve onun tam boyutunu biliyorsunuz, öyleyse bu dizgiyi printfC ile nasıl yazdırabilirsiniz ? Böyle bir yöntemi hatırlıyorum ama şimdi bulamıyorum ...


9
In Cbağlamda, bütün dizeleri boş sonlandırılmış bulunmaktadır. İçlerinde boş değer bulunmayan karakter dizileri dizge değildir ... bunlar karakter dizileridir :)
pmg


Yanıtlar:


176

Printf ile bir olasılık var, şöyle:

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

Hiçbir şeyi kopyalamaya gerek yok, orijinal dizeyi veya tamponu değiştirmeye gerek yok.


10
Ama yine de tehlikeli, birisi bir gün bu dizgiyi% s ile
yazdıracak

6
@Pmod: Tamponun dış dünyaya açık olmaması şart değildir. Aynı zamanda bir dizenin (elbette boş sonlandırılmış olabilir) parçalarını yazdırmak da çok kullanışlıdır . Bunu gerçekten çalışırken görmek istiyorsanız, OpenSER / Kamailio SIP proxy'sine bir göz atın, bu teknikten dolayı çok fazla şey kopyalamaktan kaçınırlar (ayrıca sprintf kullanarak).
DarkDust

6
başka bir +1. printf~ On yıldan sonra bile temel şeyler hakkında bir şeyler öğrendiğimde bunu seviyorum ... :)
Hertzel Guinness

1
Benim için, bir API'den boş olmayan sonlandırılmış bir dizge aldığımda (bazı Windows API'leri bunu yapar!) Ve onu 'makul' bir şekilde döndürmek zorunda olduğumda çok kullanışlıdır. Öyleyse:%. * S'ye uzun ömür (veya%. * S, sizin için UNICODE <-> TEK-BYTE!))
FrizzTheSnail

3
@ user1424739: Sizin durumunuzda printf11 karaktere kadar veya NULL ile karşılaşana kadar, hangisi önce gelirse yazdıracaktır ; örneğinizde NULL önce gelir. Bir maksimum uzunluğun belirtilmesi, NULL'un "dizge sonu" anlamını kaybetmesine neden olmaz printf.
DarkDust

31

İşte nasıl %.*sçalıştığı ve nerede belirtildiği ile ilgili bir açıklama .

Bir printf şablon dizesindeki dönüştürme belirtimleri genel biçime sahiptir:

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

veya

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

İkinci biçim, argüman listesinden kesinliği elde etmek içindir:

Ayrıca '*' hassasiyetini de belirtebilirsiniz. Bu, bağımsız değişken listesindeki bir sonraki bağımsız değişkenin (yazdırılacak gerçek değerden önce) kesinlik olarak kullanıldığı anlamına gelir. Değer bir int olmalıdır ve negatifse yok sayılır.

-  glibc kılavuzunda çıktı dönüştürme sözdizimi

İçin %sdize biçimlendirme, hassas özel bir anlamı vardır:

Yazılacak maksimum karakter sayısını belirtmek için bir kesinlik belirtilebilir; aksi takdirde, sonlandırıcı boş karaktere kadar olan ancak içermeyen dizedeki karakterler çıktı akışına yazılır.

-  glibc kılavuzundaki diğer çıktı dönüşümleri

Diğer kullanışlı varyantlar:

  • "%*.*s", maxlen, maxlen, val önce boşluklar ekleyerek sağa yaslanır;
  • "%-*.*s", maxlen, maxlen, val sola yaslanacak.

Doğru anlarsam, aşağıdakiler çıktıyı doldurur, ancak yine de bir dize taşmasını önler mi? "%-*.*s", padding, str_view.size(), str_view.data()
scx

20

Stdout için bir fwrite () kullanabilirsiniz!

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

Bu şekilde ilk karakterleri (number_of_chars değişkeninde tanımlanan sayı) bir dosyaya, bu durumda stdout'a (standart çıktı, ekranınız) çıkaracaksınız!


2
Dizeler ve sıfırlar içeren uzun bir tamponu incelemek istediğinizde çok yardımcı olur!
Elist

13

printf("%.*s", length, string) çalışmayacak.

Bu, hangisi önce gelirse, UP TO uzunluk bayt YA DA boş bayt yazdırmak anlamına gelir. Boş sonlandırılmamış karakter dizisi, uzunluktan ÖNCE boş baytlar içeriyorsa, printf bu baytlarda duracak ve devam etmeyecektir.


4
Ve bu, OP'nin sorusuna nasıl bir cevap olabilir?
Shahbaz

12
null ile sonlandırılmamışsa, null dizenin içereceği geçerli bir karakterdir. bu hala dizinin boş olarak sonlandırıldığını düşünür, sadece onu alt seçtiği daha uzun bir dizi olarak ele alır - bu, içinde boş değerler olan bir dizeniz varsa, bu sorunlara neden olacağı anlamına gelir.
lahwran

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

Dize uzunluğu 5 olacaktır.


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

Kodu düzenledim, işte başka bir yol:

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

}

Çok sayıda gereksiz bayt okuması nedeniyle çok kötü performans (bayt çoğu CPU'da kelime hizalı bir adreste değilse performans cezasıyla birlikte gelir) ve ayrıca her karakter için biçimlendirme ayrıştırma ve uygulama yapılır. Bunu yapma :-) Çözüm için cevabıma bakın.
DarkDust

@DarkDust: Yalnızca patolojik bir makine, kelime sınırlarına hizalanmamış bayt okumalarını cezalandırır. Kelime sınırlarına uymayan kelime okumalarını mı düşünüyorsunuz? Ya da eski mips saçmalığı falan?
R .. GitHub BUZA YARDIM ETMEYİ DUR

@R ..: X86'nın beyin hasarlı ve eski olduğunu düşünüyorsanız, kesinlikle katılıyorum. Çünkü x86, sözcük hizalanmamış belleği okuma ve yazma cezasına sahiptir. ARM de öyle. Örneğin bu soruya veya bu soruya bakın . Mesele şu ki (bunu doğru anladıysam), veriler bellekten kelime büyüklüğünde parçalar halinde getiriliyor ve doğru baytı elde etmek başka bir mikro işlem. Önemli değil, ancak büyük bir döngüde bir fark yaratabilir.
DarkDust

@DarkDust: Bayt okumaları konusunda tamamen yanılıyorsunuz. Neden bir kıyaslama yapmıyorsun? x86 tamamen atomik bayt işlemlerine sahiptir ve her zaman vardı. Kelime boyutunda yığınlar getirmez (çok daha büyük parçaları getiren ve hizalamanın önemsiz olduğu önbellek düzeyi hariç, ancak önceden önbelleğe alınmış verilerden bahsediyorum).
R .. GitHub BUZA YARDIM ETMEYİ DURDUR

@DarkDust: PS3, SPU'da hizalanmamış bayt okuma veya yazmayı desteklemez. Aslında skaler türleri desteklemiyor bile, hizalanması gereken sadece vektör var. Derleyici bunları taklit eder. Ve birçok ARM işlemcisi bayt okuma veya yazmayı desteklemez, sadece kelime okuma veya yazma yapar.
Sylvain Defresne
Sitemizi kullandığınızda şunları okuyup anladığınızı kabul etmiş olursunuz: Çerez Politikası ve Gizlilik Politikası.
Licensed under cc by-sa 3.0 with attribution required.