2010-01-31 28 views
5

Sınırlandırılmış bir dizeyi C dizgesinde (C++ değil) bir dizeye dönüştürmenin verimli bir yolu ne olurdu? Örneğin, ben olabilir: Kaynak dize her zaman sınırlayıcı olarak yalnızca tek bir alana sahip olacaktır. Ve malloc'ed dizeleri char *myarray[] öyle ki bir malloc'ed dizi istiyorum: EditC: Sınırlandırılmış kaynak dizgisinden dizgiler dizisi oluşturma

myarray[0]=="valgrind" 
myarray[1]=="--leak-check=yes" 
... 

Ben sadece sınırlandıramazsınız inputString içinde jeton keyfi bir sayı olduğunu varsaymak zorundayız 10 ya da bir şey.

strtok ile bir dağınık çözüm denedim ve uyguladığım bir bağlantılı liste, ancak valgrind vazgeçmemden çok şikayet etti.

(Eğer merak ediyorsanız, bu şimdiye yazmaya çalışıyorum temel Unix kabuk içindir.)

+0

@Sneesh: Bu, C'deki eski atasözün 'Bir kediyi cildin birçok yolu var' diye benden nasıl yapabileceğinize dair mükemmel bir örnektir. – t0mm13b

cevap

2

: genel olarak başlangıçta input yılında girdi tüm varsa

char* string = "valgrind --leak-check=yes --track-origins=yes ./a.out"; 
char** args = (char**)malloc(MAX_ARGS*sizeof(char*)); 
memset(args, 0, sizeof(char*)*MAX_ARGS); 

char* curToken = strtok(string, " \t"); 

for (int i = 0; curToken != NULL; ++i) 
{ 
    args[i] = strdup(curToken); 
    curToken = strtok(NULL, " \t"); 
} 
+0

Aslında sanırım gerçekten bellek saklamak gerekmiyorsa dizeleri için 256 arabellek işaretçisi kullanmak böyle bir israf olmaz, .. – Jack

+0

strtok() bir giriş dizesini kullanarak, bir dizede bunu kullanarak değişecek platformlar. – bk1e

+0

'MAX_ARGS' 10,000 gibi güvenli bir şey olduğunu varsayabiliriz, ancak kod hala 10.1001 hatalar için çalışmalıdır ... – yavoh

1

sen dize sona erdiğini sonlandırıcı boş ekstra bayt Malloc hatırlamak mıydı? OSX'te strsep(3) manpage itibaren

+0

Evet: 'char * singleToken = (char *) malloc (strlen (tokPtr) * sizeof (char) +1);' tokPtr '' strtok'un dönüş değeriydi. – yavoh

1

: jeton keyfi için #

char **ap, *argv[10], *inputstring; 

    for (ap = argv; (*ap = strsep(&inputstring, " \t")) != NULL;) 
      if (**ap != '\0') 
        if (++ap >= &argv[10]) 
          break; 

Düzenlendi:

char **ap, **argv, *inputstring; 

int arglen = 10; 
argv = calloc(arglen, sizeof(char*)); 
for (ap = argv; (*ap = strsep(&inputstring, " \t")) != NULL;) 
    if (**ap != '\0') 
     if (++ap >= &argv[arglen]) 
     { 
      arglen += 10; 
      argv = realloc(argv, arglen); 
      ap = &argv[arglen-10]; 
     } 

Ya da yakın bir şey. Yukarıdakiler çalışmayabilir, ancak değilse de uzak değildir. Bağlantılı bir liste oluşturmak, realloc numaralı telefonu sürekli aramaktan daha verimli olacaktır, ancak bu noktadan başka bir şey değildir - en iyi nokta, strsep'dan en iyi şekilde yararlanmanızdır. Böyle bir konuda ne var

+0

Teşekkürler. Örneğin, inputString'de rastgele bir sayı işareti olduğunu varsaymak zorunda olduğumu söylemeyi unutmuşum. – yavoh

2

o zaman strlen(input) fazla belirteçleri var olamaz. "" Olarak bir simge olarak izin vermezseniz, asla strlen(input)/2 jetondan daha fazlasına sahip olamazsınız. Yani inputbüyük ise güvenli bir şekilde yazabilirsiniz.

char ** myarray = malloc((strlen(input)/2) * sizeof(char*)); 

int NumActualTokens = 0; 
while (char * pToken = get_token_copy(input)) 
{ 
    myarray[++NumActualTokens] = pToken; 
    input = skip_token(input); 
} 

char ** myarray = (char**) realloc(myarray, NumActualTokens * sizeof(char*)); 

bir başka optimizasyon olarak, etrafında input tutabilir ve sadece \ 0 boşlukların yerine ve myarray [] içine input tampon içine işaretçileri koydu. 'a ihtiyaç duymadıkça, her bir simge için ayrı bir malloğa gerek yoktur.

+0

Strlen (giriş)/2' fikrinizi kullanarak - Teşekkürler! – yavoh

0

Diğer cevaplara bakıldığında, C'deki yeni başlayanlar için, kodun sıkı boyutundan dolayı karmaşık görünebilirdi, bunu yeni başlayanlar için koyabileceğimi düşündüm, bunun yerine dizgeyi aslında ayrıştırmak daha kolay olabilir böyle ... şey strtok kullanarak: Ben biraz daha kolay hale getirmek için kod modifiye

 
#include <stdio.h> 
#include <stdlib.h> 
#include <string.h> 
#include <ctype.h> 

char **parseInput(const char *str, int *nLen); 
void resizeptr(char ***, int nLen); 

int main(int argc, char **argv){ 
    int maxLen = 0; 
    int i = 0; 
    char **ptr = NULL; 
    char *str = "valgrind --leak-check=yes --track-origins=yes ./a.out"; 
    ptr = parseInput(str, &maxLen); 
    if (!ptr) printf("Error!\n"); 
    else{ 
     for (i = 0; i < maxLen; i++) printf("%s\n", ptr[i]); 
    } 
    for (i = 0; i < maxLen; i++) free(ptr[i]); 
    free(ptr); 
    return 0; 
} 

char **parseInput(const char *str, int *Index){ 
    char **pStr = NULL; 
    char *ptr = (char *)str; 
    int charPos = 0, indx = 0; 
    while (ptr++ && *ptr){ 
     if (!isspace(*ptr) && *ptr) charPos++; 
     else{ 
      resizeptr(&ptr, ++indx); 
      pStr[indx-1] = (char *)malloc(((charPos+1) * sizeof(char))+1); 
      if (!pStr[indx-1]) return NULL; 
      strncpy(pStr[indx-1], ptr - (charPos+1), charPos+1); 
      pStr[indx-1][charPos+1]='\0'; 
      charPos = 0; 
     } 
    } 
    if (charPos > 0){ 
     resizeptr(&pStr, ++indx); 
     pStr[indx-1] = (char *)malloc(((charPos+1) * sizeof(char))+1); 
     if (!pStr[indx-1]) return NULL; 
     strncpy(pStr[indx-1], ptr - (charPos+1), charPos+1); 
     pStr[indx-1][charPos+1]='\0'; 
    } 
    *Index = indx; 
    return (char **)pStr; 
} 

void resizeptr(char ***ptr, int nLen){ 
    if (*(ptr) == (char **)NULL){ 
     *(ptr) = (char **)malloc(nLen * sizeof(char*)); 
     if (!*(ptr)) perror("error!"); 
    }else{ 
     char **tmp = (char **)realloc(*(ptr),nLen); 
     if (!tmp) perror("error!"); 
     *(ptr) = tmp; 
    } 
} 

. Kullandığım tek dize işlevi strncpy idi.biraz uzun-sarılmış olduğundan emin olun, ancak sabit kodlanmış bir MAX_ARGS kullanmak yerine dizilerin dizisini dinamik olarak yeniden tahsis eder, yani çift işaretçinin sadece 3 ya da 4 olduğunda zaten bellek biriktirdiği anlamına gelir. bellek kullanımı verimli ve küçük, realloc kullanarak, basit ayrıştırma işaretçisi kullanarak yinelemeye olarak, isspace çalıştırılarak kaplıdır. Bir boşlukla karşılaşıldığında, çift işaretçi realloc ve dize tutmak için malloc ofset.

Üçlü işaretleyicilerin resizeptr işlevinde nasıl kullanıldığına dikkat edin. Aslında, bunun basit bir C programı, işaretçiler, realloc, malloc, başvuru başına gönderme, ayrışmanın temel öğesi için mükemmel bir örnek olacağını düşündüm. dize ...

Bu yardımcı olur umarım, Saygılarımızla, Tom.