Çoğu dil size kendi uzunluğunu bilen bir string türü verir. C vermez. C'de metin, yalnızca ona eklenmiş tek bir kuralı olan bir char dizisidir: metni, değeri sıfır olan, '\0' yazılan ve boş sonlandırıcı denen bir bayt izler. C metinleriyle ilgili diğer her şey o tek gelenekten çıkar.
Metin, Char Dizisi Artı '\0'dır
Bir metni, bir char dizisine bir sabitten ilk değer vererek tanımlayın:
Dizi üç değil dört bayt gibi görünür:
name: +-----+-----+-----+------+
| 'A' | 'd' | 'a' | '\0' |
+-----+-----+-----+------+
indeks: 0 1 2 3
sizeof(name) 4'tür. Derleyici karakterleri saydı, sonlandırıcı için bir ekledi ve diziyi sizin için boyutlandırdı. char name[3] = "Ada";'nın olmayı bekleyen bir hata olmasının sebebi o fazladan bayttır - metin sığar ama sonlandırıcı sığmaz, dolayısıyla sonraki hiçbir şey metnin nerede bittiğini söyleyemez.
İçeriği daha sonra değiştirmek için yer istediğinizde boyutu kendiniz verin ve pay bırakın:
char name[32] = "Ada"; /* 3 karakter, bir sonlandırıcı, 28 bayt boş */
Kullanılmayan baytlar ilk değer tarafından sıfırla doldurulur ki bu zararsızdır.
Sonlandırıcı Neden Önemli
Hiçbir C fonksiyonu bir uzunluk almaz. printf("%s", s)'ye tek bir adres verilir ve '\0' ile karşılaşana dek baytları yazdırarak ileri yürür. Dolayısıyla sonlandırıcısı olmayan bir char dizisi bir metin değildir ve ona öyle davranmak, ardından gelen bellekte ne varsa onu okur.
Ezberlenecek kural: sizeof size depolamayı, strlen metni verir. char buf[32] = "Ada" için sizeof buf 32, strlen(buf) 3'tür. Farklı soruları yanıtlarlar ve onları karıştırmak en yaygın C hatalarından biridir.
Metin Sabitleri ile Char Dizileri
Bu iki satır benzer görünür ve çok farklı davranır:
char a[] = "hello"; /* sahibi olduğunuz, sabitten ilk değer almış bir dizi */
char *p = "hello"; /* sabitin kendisine yöneltilmiş bir gösterici */
a, metnin özel bir kopyasını tutan 6 baytlık bir dizidir. Onu değiştirebilirsiniz. p, programın salt okunur metin verisinin içini gösterir; sabit paylaşılır ve p üzerinden yazmak, tipik olarak derleme zamanında değil çalışma zamanında çökerten tanımsız davranıştır.
Bir gösterici bir sabiti hedeflediğinde const char * yazın. Derleyici o zaman yazmayı bir çökmeye dönüşmesine izin vermek yerine derleme zamanında reddeder. İkisi arasında seçim yapmak aslında göstericiler ve diziler sayfasında ele alınan bir gösterici-dizi sorusudur.
Bilmeye değer bir fark daha: sizeof a 6'dır, ama sizeof p, metnin uzunluğundan bağımsız olarak bir göstericinin boyutudur (çoğu sistemde 8).
Metinleri Yazdırmak ve Okumak
%s bir metin yazdırır; %c tek bir karakter yazdırır.
Girdi için gets'ten tamamen kaçının - güvenle kullanılamadığı için dilden kaldırıldı. Tampon boyutunu alan ve taşmayacak olan fgets'i kullanın:
fgets, bastığınız satır sonunu korur ki bu neredeyse hiçbir zaman metinde istediğiniz şey değildir. strcspn satırı ilk '\n''i bulur ve üzerine bir sonlandırıcı yazar - onu kırpmanın derli toplu, standart bir yolu.
Bir Metni Karakter Karakter Dolaşmak
Son sayılmak yerine işaretlendiği için deyimsel döngü karakterin kendisini test eder:
text[i] != '\0' koşulu çoğu zaman yalnızca text[i]'ye kısaltılır, çünkü '\0' sıfırdır ve dolayısıyla yanlıştır. İkisi de doğrudur; açık biçim öğrenirken daha kolay okunur.
Bir indeks yerine bir göstericiyle de dolaşabilirsiniz ki bu da eşit derecede deyimsel C'dir:
toupper'ı çağırmadan önceki unsigned char dönüşümü bir süs değildir: <ctype.h> fonksiyonları negatif değerler için tanımsızdır ve düz bir char, 127'nin üzerindeki baytlar için negatif olabilir.
Bir Metni = ile Kopyalayamazsınız
Her yeni gelenin çarptığı duvar budur:
char a[10];
a = "hello"; /* hata: dizi tipli ifadeye atama */
char b[10] = "hi";
char c[10];
c = b; /* hata - aynı sebep */
Bir dizi adı değiştirilebilir bir değer değildir, dolayısıyla ='in yapacak bir şeyi yoktur. Kısayolun çalıştığı tek yer bildirimde ilk değer vermektir ki bu, derleyicinin gerçekleştirdiği farklı bir işlemdir.
Çalışma zamanında kopyalamak için baytları <string.h>'deki strcpy ile kopyalayın:
Aynı mantık, =='in neden metinleri karşılaştırmadığını açıklar. if (a == b) iki adresi karşılaştırır, dolayısıyla aynı metni tutan iki farklı dizi için yanlıştır. Bunun yerine strcmp(a, b) == 0 kullanın. Her iki fonksiyon ve daha güvenli akrabaları metin fonksiyonları sayfasında ele alınıyor.
Metin Dizileri
Bir metin listesi ya bir gösterici dizisidir (yalnızca okuduğunuz sabit metin için) ya da iki boyutlu bir char dizisidir (her kaydın değiştirilebilir olması gerektiğinde):
Gösterici dizisi salt okunur sabitlere üç adres saklar - derli toplu ama değiştirilemez. char[3][16] biçimi kendi belleğinizden 48 bayt ayırır, dolayısıyla her satır yeniden yazılabilir.
Sık Yapılan Hatalar
- Sonlandırıcının baytını unutmak.
char s[5] = "hello"'nun'\0'için yeri yoktur.strlen + 1için boyutlandırın. strlenkastettiğiniz yerdesizeofkullanmak. Bir göstericidesizeof, metnin uzunluğunu değil göstericinin boyutunu verir.- Bir sabite giden
char *üzerinden yazmak. Bu tür göstericilericonst char *bildirin. ==ile karşılaştırmak. Bu adresleri karşılaştırır.strcmpkullanın.scanf("%s", buf)ile okumak. Boyut sınırı yoktur ve memnuniyetle taşar;fgets'i tercih edin.
Sıkça Sorulan Sorular
C'de bir metin nasıl tanımlanır?
Bir char dizisi olarak: char name[] = "Ada";. C'nin yerleşik bir metin türü yoktur - o dizi 'A', 'd', 'a' ve sonu işaretleyen gizli dördüncü bir bayt olan '\0''ı tutar. Metni daha sonra değiştirmek için yer istiyorsanız diziye açık bir boyut verin: char name[32] = "Ada";.
C'de boş sonlandırıcı nedir?
Bir metnin nerede bittiğini işaretleyen '\0' (değeri sıfır) baytıdır. Her standart fonksiyon - printf("%s"), strlen, strcpy - o baytı bulana dek ileri okur. Onsuz bir char dizisi bir metin değildir ve onu bu fonksiyonlara geçirmek belleğinizin sonunun ötesini okur.
C'de bir metni neden = ile atayamam?
Çünkü dizi, = ile kopyalayabileceğiniz bir değer değildir. char a[10]; a = "hi"; derlenmez. Bunun yerine karakterleri <string.h>'deki strcpy(a, "hi") ile kopyalayın ya da bildirimde ilk değer verin - char a[10] = "hi"; - kısayolun çalıştığı tek yer burasıdır.
C'de char * ile char [] arasındaki fark nedir?
char s[] = "hi", metnin özel bir kopyasını tutan değiştirilebilir bir dizi yapar. char *p = "hi", salt okunur bellekte yaşayan bir metin sabitine gösterici yapar - onu okumak sorunsuzdur, üzerinden yazmak çökertir. Değiştirmek istediğinizde diziyi, yalnızca okuduğunuzda göstericiyi kullanın.