2010-01-31 13 views
5

से तारों की सरणी बनाना सी सी (+ सी ++ नहीं) में तारों की सरणी में एक सीमांकित स्ट्रिंग को परिवर्तित करने का एक प्रभावी तरीका क्या होगा? उदाहरण के लिए, मेरे पास हो सकता है:सी: सीमांकित स्रोत स्ट्रिंग

char *input = "valgrind --leak-check=yes --track-origins=yes ./a.out" 

स्रोत स्ट्रिंग हमेशा डेलीमीटर के रूप में केवल एक ही स्थान होगी। और मैं malloc'ed तार char *myarray[] ऐसा है कि की एक malloc'ed सरणी चाहते हैं:

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

संपादित मुझे लगता है करने के लिए तो मैं बस सीमित नहीं कर सकते inputString में टोकन की एक मनमाना संख्या देखते हैं कि राशि यह 10 या कुछ करने के लिए।

मैंने strtok के साथ एक गन्दा समाधान का प्रयास किया है और एक लिंक की गई सूची मैंने लागू की है, लेकिन वालग्रिंड ने इतनी शिकायत की है कि मैंने छोड़ दिया।

(अगर आप सोच रहे हैं, यह एक बुनियादी यूनिक्स शेल मैं लिखने के लिए कोशिश कर रहा हूँ के लिए है।)

+0

@ स्नीश: यह एक उत्कृष्ट उदाहरण है कि आप इसे सी में कैसे कर सकते हैं क्योंकि पुरानी कहावत है कि 'बिल्ली को त्वचा के कई तरीके हैं ...' +1। – t0mm13b

उत्तर

2

क्या की तरह कुछ के बारे में बताया गया है:

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

असल में मुझे लगता है कि तारों के पॉइंटर्स के 256 बफर का उपयोग करना इतना कचरा नहीं होगा, जब तक कि आपको वास्तव में स्मृति को संरक्षित करने की आवश्यकता न हो .. – Jack

+0

strtok() इनपुट स्ट्रिंग को संशोधित करता है, इसलिए स्ट्रिंग अक्षर पर इसका उपयोग कुछ पर दुर्घटनाग्रस्त हो जाएगा प्लेटफार्मों। – bk1e

+0

मुझे लगता है कि 'MAX_ARGS' 10,000 की तरह कुछ सुरक्षित है, लेकिन कोड को अभी भी 10,001 तर्कों के लिए काम करना चाहिए ... – yavoh

1

थे आप समाप्त अशक्त कि स्ट्रिंग के अंत के निशान के लिए एक अतिरिक्त बाइट malloc को याद?

+0

हां: 'char * singleToken = (char *) malloc (strlen (tokPtr) * sizeof (char) +1); 'जहां' tokPtr' 'strtok' का वापसी मान था। – yavoh

1

पर OSX strsep(3) मैनपेज से:

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

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

टोकन की मनमानी # के लिए संपादित:

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

या उस के पास कुछ। उपर्युक्त काम नहीं कर सकता है, लेकिन यदि नहीं, तो यह दूर नहीं है। एक लिंक्ड सूची बनाना लगातार realloc पर कॉल करने से अधिक कुशल होगा, लेकिन यह वास्तव में बिंदु के अलावा है - बिंदु यह है कि strsep का उपयोग करने के लिए सबसे अच्छा तरीका है।

+0

धन्यवाद। मैं यह उल्लेख करना भूल गया कि मुझे यह मानना ​​है कि 'इनपुटस्ट्रिंग' में टोकन की मनमानी संख्या है- उदाहरण के लिए मैं 10 नहीं मान सकता। – yavoh

2

आप input में इनपुट के सभी के साथ शुरू करने के लिए तो आप strlen(input) की तुलना में अधिक टोकन कभी नहीं हो सकता। यदि आप टोकन के रूप में अनुमति नहीं देते हैं, तो आपके पास कभी भी strlen(input)/2 टोकन से अधिक नहीं हो सकता है। तो जब तक inputविशाल आप सुरक्षित रूप से लिख सकते हैं।

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*)); 

एक और अनुकूलन के रूप में, आप के आसपास input रख सकते और बस \ 0 के साथ रिक्त स्थान की जगह और myArray [] में input बफर में संकेत डाल दिया। प्रत्येक टोकन के लिए अलग-अलग मॉलोक की आवश्यकता नहीं है जब तक कि आपको को की आवश्यकता न हो, अलग-अलग उन्हें मुक्त करने के लिए।

+0

अपने 'स्ट्रेलन (इनपुट)/2' विचार का उपयोग करना- धन्यवाद! – yavoh

0

सी में शुरुआती के लिए अन्य उत्तरों को देखते हुए, यह कोड के कड़े आकार के कारण जटिल लगेगा, मैंने सोचा था कि मैं इसे शुरुआती के लिए रखूंगा, वास्तव में स्ट्रिंग को पार्स करना आसान हो सकता है इस तरह strtok का उपयोग कर ... कुछ:

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

मैं थोड़ा यह आसान बनाने के लिए कोड को संशोधित किया। एकमात्र स्ट्रिंग फ़ंक्शन जिसका मैंने उपयोग किया था strncpy था ..सुनिश्चित करें कि यह थोड़ा लंबा हवादार है लेकिन यह हार्ड-कोडित MAX_ARGS का उपयोग करने के बजाय गतिशील रूप से तारों की सरणी को पुन: आवंटित करता है, जिसका अर्थ है कि डबल पॉइंटर पहले से ही 3 या 4 करने पर स्मृति को गले लगा रहा है, जो भी करेगा स्मृति उपयोग कुशल और छोटे, realloc का उपयोग करके, सरल पार्सिंग isspace को नियोजित करके कवर किया जाता है, क्योंकि यह सूचक का उपयोग करता है। जब कोई स्थान सामने आ जाता है, तो यह realloc डबल पॉइंटर को एट करता है, और malloc स्ट्रिंग को पकड़ने के लिए ऑफ़सेट होता है।

सूचना कैसे ट्रिपल संकेत resizeptr समारोह में किया जाता है .. वास्तव में, मैंने सोचा था कि यह एक सरल सी कार्यक्रम, संकेत, realloc, malloc का एक उत्कृष्ट उदाहरण में काम करेगा, गुजर-संदर्भ द्वारा, पार्स के बुनियादी तत्व एक स्ट्रिंग ...

उम्मीद है कि यह मदद करता है, सर्वश्रेष्ठ संबंध, टॉम।

संबंधित मुद्दे