Membpy

2016-03-20 19 views
-2

sonra printf garip davranışı C içinde bir dize yazdırma ile ilgili bir sorunum var (iyi, *ptr işaret ettiği dize).Membpy

Aşağıdaki kod var:

char *removeColon(char *word) { 
    size_t wordLength; 
    char word1[MAXLENGTH]; 

    wordLength = strlen(word); 
    wordLength--; 
    memcpy(word1, word, wordLength); 
    printf("word1: %s\n", word1); 
    return *word1; 
} 

Ben kelime ile bu koştum = "MAIN:" (kelimenin değeri dosyadan okunan bir ipe strtok gelir). printf sonucuna kadar iyi çalışır, buradaki sonuç şu şekildedir:

word1: MAIN╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ ╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠ 12

ve sonra bir istisna vardır ve her şey bozulur.

Herhangi bir düşünce? Her dize ASCII değeri 0'dır, C. \0 yazıldığından Ayrıca mem... yerine fonksiyonların str... ailesini kullandığınız bir sonlandırma karakteri vardır çünkü

+4

null terminator, (tahmin) –

+0

Daha fazla bilgi verebilir misiniz? Word1'in sonuna '\ 0' eklemeyi denedim, ancak yardımcı olmadı. –

+0

Değilse, daha sonra soruyu okuyabilirim. –

cevap

0
wordLength = strlen(word); 

Sen beri uzunluğunda boş terminatör eklemek zorunda eski boş sonlandırılmış dizeler için tasarlanmıştır, ancak diziler için ikincisi. Ayrıca, yerel bir yığın ayrılmış dizi döndüremezsiniz. Fonksiyonun koduna göre, son karakteri kaldırıyormuşsunuz gibi geliyor. Durum buysa,

void remlast(char *str) 
{ 
    str[strlen(str) - 1] = '\0'; 
} 

Bunun boş dizeler üzerinde çalışmadığını unutmayın.

+1

hadi, "revize edilmiş fonksiyon" hala birçok hata içeriyor. Ayrıca 'remlast' boş dizeleri kırıyor. –

+0

fixed @ M.M [16 karakter] – stackptr

+0

@stackptr: gerçekten düzeltilmemiş ;-) hatayı düzeltmek için maliyeti düzeltmek için daha az maliyete sahip olur. – chqrlie

0

wordLength bayt üzerinden kopyalayın, ancak boş sonlandırıcı bayt ekleyemezsiniz. Bu kopyadan önce word1 başlatılmamış olduğundan, kalan baytlar tanımsızdır.

printf dizeyi yazdırmaya çalıştığında, boş bir sonlandırıcı bulamaz ve dizinin sınırlarının dışında bir boş bayt bulana kadar okumaya devam eder. Bu tanımlanmamış bir davranış.

memcpy(word1, word, wordLength); 
word1[wordLength] = '\0'; 

Ayrıca, yerel bir değişkene gösterici dönüyoruz:

bayt kopyaladıktan sonra, el boş terminatör eklemeniz gerekir. İşlev döndüğünde, bu değişken kapsam dışıdır ve işaretçinin de tanımlanmamış bir davranış olduğunu belirtir.

Aksine word1 yerel dizisi yapmak yerine, bunun için dinamik bellek ayırabilir: Bunu yaparsanız, çağıran işlevinde bir yere free bu hafızayı gerekir

char *word1 = malloc(strlen(word)); 

. Diğer seçenek uygun boyutta bir tampon içerisinde arayan geçmek sahip olmaktır:

void removeColon(char *word, char *word1) { 
1

Sen yapmalıdır emin (1) her dize nul-sonlandırılmış ve (2) Bir değiştirmeye teşebbüs değildir string-literal. Yapabileceğin birçok yaklaşım var. Basit bir yaklaşım strlen ile son karakterini (herhangi bir karakter) kaldırmak için:

char *rmlast (char *s) 
{ 
    if (!*s) return s;  /* return if empty-string */ 
    s[strlen (s) - 1] = 0; /* overwrite last w/nul */ 
    return s; 
} 

(ayrıca strchr() 0 ararken string.h işlevlerini kullanabilirsiniz geçtiyseniz, strrchr(), hedef Char ararken, strpbrk .. vb (birkaç karakterlerinizle ararken) ve son karakteri bulmak için)

Yoksa işaretçiler ile aynı şeyi yapabilirsiniz:

char *rmlast (char *s) 
{ 
    if (!*s) return s; /* return if empty-string */ 
    char *p = s; 

    for (; *p; p++) {} /* advance to end of str */ 
    *--p = 0;   /* overwrite last w/nul */ 

    return s; 
} 

Ayrıca, belirli bir karaktere kaldırma işlemini sınırlandırmak ve nil sonlandırıcı karakteri ile üzerine yazmadan önce işlevde basit bir karşılaştırma yapmak istiyorsanız, ilgili son karakteri de geçirebilirsiniz.

Her ikinize de bakın ve herhangi bir sorunuz olursa lütfen bildirin.

+0

0 değil (tam sayı) '\ 0'dan farklı mı? – RastaJedi

+0

Hayır, nul karakteri '' \ 0 ''' 0' ASCII değerine sahiptir - hiçbir fark yoktur. Sadece '0' 'karakterini yazmak için daha fazla yazmanız yeterli' '' ':' ' –

+0

Bu sadece karakter gösterimi. Tamsayı sıfırın bir şekilde "boş bayt" dan başka bir şeyle temsil edilip edilmediğinden emin değildim. Açıkçası, '0' tamamen farklıdır, ancak belirtilmesi gerekmemiştir. – RastaJedi

1

İşleviniz removeColon ya

  • yerinde faaliyet gösteren ve hedef tampon verildi ve buna kısaltılmış dize kopyalamak veya
  • kısaltılmış için bellek ayrılamadı edilecek bir tartışma
  • olarak geçirilen dize değiştirmelisiniz dize ve buna geri dön.

Yerel dizide değil, boş sonlandırıcı içine sadece karakterleri kopyalamak, ne de printf("%s", ...) bu dizi geçen tampon bir tane set yapmak tanımsız davranışı hatırlar: printf bir '\0' bulana kadar tampon içeriğini baskı devam ediyor Bayt, hatta dizinin sonunun ötesine geçer, tanımlanmamış davranışları çağırır, çöp yazdırır ve sonunda bir kazada ölür.

Otomatik bir diziye işaretçi döndüremezsiniz, çünkü bu dizi işlev döndükçe kullanılamaz duruma gelir. İşaretçiyi daha sonra iptal etmek, tanımlanmamış davranışları çağırır.İşte

yerde çalışan bir işlevdir:

İşte
char *removeColon(char *word) { 
    if (*word) word[strlen(word) - 1] = '\0'; 
    return word; 
} 

bir hedef tampon için kopyalar, yeterince uzun olduğu varsayılır biri olan:

İşte
char *removeColon(char *dest, const char *word) { 
    size_t len = strlen(word); 
    memcpy(dest, word, len - 1); 
    dest[len - 1] = '\0'; 
    return dest; 
} 

bellek ayırır biridir:

char *removeColon(const char *word) { 
    size_t len = strlen(word); 
    char *dest = malloc(len); 
    memcpy(dest, word, len - 1); 
    dest[len - 1] = '\0'; 
    return dest; 
}