2012-06-29 21 views
5

Anladığım kadarıyla bir kaç gündür sorun yaşadım. Burada alamıyorum o karakter */char [] hakkında önemli bir şey var gibi hissediyorumarasındaki fark

void cut_str(char* entry, int offset) { 
    strcpy(entry, entry + offset); 
} 

char works[128] = "example1\0"; 
char* doesnt = "example2\0"; 

printf("output:\n"); 

cut_str(works, 2); 
printf("%s\n", works); 

cut_str(doesnt, 2); 
printf("%s\n", doesnt); 

// output: 
// ample1 
// Segmentation: fault 

: İşte benim bela.

+0

Bu soruya sık sorulan soru sorulmuştur. bakınız, örneğin, http://stackoverflow.com/questions/10186765/char-array-vs-char-pointer-in-c ve http://stackoverflow.com/questions/4090434/strtok-char-array-versus arasında -Char-işaretçi –

+0

olası yinelenen (http://stackoverflow.com/questions/1704407/what-is-the-difference-between [karakter s \ [\] ile char * s, C? arasındaki fark ne] -char-s-ve-char-s-in-c) –

cevap

11

Buradaki fark, doesnt dizgisinin bir sabit değere ait olan belleğe işaret etmesidir ve bu nedenle yazılabilir değildir.

bu

char works[128] = "example1\0"; 

derleyici kopya yazılabilir diziye olmayan yazılabilir dize içeriği yaptığınızda. Bu arada, \0 gerekli değildir. Ancak

Bunu

,

char* doesnt = "example2\0"; 

derleyici olmayan bir yazılabilir bellek bölüme işaret işaretçi bırakır. Tekrar, \0 derleyici tarafından eklenir.

gcc kullanıyorsanız, yazılabilir char *'u dize değişmezleriyle başlatacağınız konusunda sizi uyarmasını sağlayabilirsiniz. Bu seçenek -Wwrite-strings. aşağıdaki gibi doesnt işaretçisi ilan etmek

warning: initialization discards qualifiers from pointer target type 

uygun yolu: Sen şuna benzer bir uyarı alacak

const char* doesnt = "example2\0"; 
+0

"derleyici, yazılabilir olmayan bir dizenin içeriğini yazılabilir bir diziye kopyalar" - Tam olarak değil. "example1 \ 0" burada yazılabilir olmayan bir dize değil, bu dize değişmezidir - tamamen sözdizimsel bir öğe. Bu bağlamda başlatıcı olarak kullanılmaktadır. –

+0

"Char * doesnt = ... line" hakkında bir uyarı almalısınız - Hayır, gerçekten değil. Neyse ki hiçbir derleyici bunu yapmaz. –

+1

@JimBalter g ++ şunu yapar: "uyarı: dize sabitinden‘ char * ’yerine dönüştürülmüş dönüşüm." Bu tamamen bir C derleyicisi değil, ama ben yapmadım :) – dasblinkenlight

3

Bu yığın 128 bayt ayırır ve adını works kullanır onun adresine bakınız:

char works[128]; 

Yani works yazılabilir belleğe bir göstericidir.

Bu salt okunur bellekte olduğu değişmez bir dize oluşturur ve bunun adresine başvurmak için isim doesnt kullanır: bu bellek yazılabilir işaret ettiğinden

char * doesnt = "example2\0"; 

Sen works veri yazabilir. doesnt'a veri yazamazsınız, çünkü salt okunur belleğe işaret eder.

Ayrıca, dize değişmezlerini "\0" ile sona erdirmenize gerek olmadığını unutmayın, çünkü tüm dize değişmezleri örtülü olarak dizenin sonuna bir sıfır bayt ekler.

+0

Hayır, 'works' bir dizi nesnedir, işaretçi değildir. (Onun adı, çoğu bağlamda bir işaretçi ifadesine bozulur.) –

+0

"Bu, yığında 128 bayt ayırır" - depolama sınıfını bilmiyoruz; extern olabilir. Keith'in de belirttiği gibi, diziler işaretçi değildir. (Bir sonuç şu ki: sizeof (çalışır)! = Sizeof ((char *) çalışır) '). –

4

char[] ve char * türleri oldukça benzerdir, bu nedenle bu konuda haklısınız. Fark, türlerin nesneleri başlatıldığında ne olduğu ile ilgilidir. char[] tipindeki works nesnesinin, yığında bunun için ayrılmış 128 baytlık değişken depolama alanı vardır. char *, türündeki doesnt nesnesinin yığında saklama yok.doesnt dize depolandığı tam

C standardında belirtilmiştir, ancak program yürütme için yüklendiğinde yüklenen bir Değiştirilemez veri segmentinde depolanır büyük olasılıkla değil. Bu değişken depolama alanı değil. Böylece, onu değiştirmeye çalıştığınızda segfault.

+0

"Fark yatıyor" - Diziler ve işaretçiler arasında başka, önemli, farklılıklar vardır. Buradaki konu gerçekten bununla ilgili değil, ama bir dizgenin sabitini göstermediği ve standardın değiştirilmesinin sonuçlarının tanımlanmamış olduğu gerçeği hakkında. –