2016-02-01 2 views
0

так пусть говорят, что пользователь вводит «программу один два три». Я сохраняю это в массиве userTyped и передаю его функции parse(). я нужна функция синтаксического анализа(), чтобы сделать это так, чтобыC разделите строку на отдельные слова и сохраните отдельные слова в массиве

userargv [0] Программа

userargv [1] является одним

userargv [2] два

т.д.

Я могу сказать, что это должно быть что-то, связанное с указателями, но я не могу понять это. код ниже:

int main(int argc, char **argv) 
{ 
char userTyped[1000]; 

char* userargv[100];//this is where i need the parse() function to store the arguments to pass to execv 

printf("typesomething>"); 

fgets(userTyped, 1000, stdin); 

parse(userTyped, &userargv); 

return 0; 
} 



int parse(char* userTyped, char* userargv){ 

const char whitespace[2] = " "; //the deliminator 
char *strings; 

strings = strtok(userTyped, whitespace); 

while(strings != NULL) 
{ 
    strings = strtok(NULL, whitespace); 

} 
//THIS ALL WORKS, BUT I NEED TO DO SOMETHING LIKE userargv[i] = strings; 
//OR *userargv[i] = &strings; 
//OR SOMETHING LIKE THAT. 

return 0; 
} 
+2

Стандартная библиотечная функция 'strtok' может помочь вам с частью этого. –

+1

Это ощущение домашнего задания. –

+0

@DavidHoelzer да, это домашнее задание. но я просто прошу помощи с этой проблемой синтаксиса, а не с моим фактическим назначением (которое должно написать оболочку). – user3290724

ответ

0

вы должны Alloc массив строки (символ **), и выделить каждый из его элементов, а затем скопировать обратно в нем все найденные строки;

// nb: the function prototype has been slightly modified 
char** parse(char* userTyped, int *nargs){ 

    const char whitespace[2] = " "; //the deliminator 
    char *strings; 
    char **arr; 
    int n = 0; // initially no element allocated 

    strings = strtok(userTyped, whitespace); 

    while(strings != NULL) 
    { 
     if(n){ // if there are already allocated elements? 
      arr = realloc(arr, (n + 1) * sizeof(char**)); 
     }else{ 
      arr = malloc((n + 1) * sizeof(char*)); 
     } 

     if(!arr){ 
      perror("parse"); 
      exit(-1); 
     } 

     // duplicate strings 
     arr[ n ] = malloc(strlen(strings)+1); 

     if(!arr[ n ]){ 
      perror("parse"); 
      exit(-2); 
     } 
     strcpy(arr[ n ] , strings); // make a copy of the string 

     n++; 

     strings = strtok(NULL, whitespace); 

    } 


    // call freeStrArr when done with arr; 
    // 
    *nargs = n; // save array size; 
    return arr; // return string array 
} 

// this how to free the returned array; 
void freeStrArr(char ** strarr,int n){ 
    while(n){ 
     n--; 
     free(strarr[ n ]); 
    } 
    free(strarr); 
} 
0

Когда вы думаете о том, что вам нужно, чтобы получить от вашей функции синтаксического анализа, вы знаете, что вы хотите, массив указателей, указывающих на выделенные блоки памяти, содержащую отдельные слова в usertyped, но вы также должны знаете, сколько слов есть. Поскольку вы передаете массив указателей в качестве аргумента для работы самой функции, вам нужно только вернуть количество отдельных слов в заданной строке. Вы можете использовать что-то вида:

int parse (char **words, char *str); 

(примечание: пропусканием массив из указателей (100), вы ограничены только 100 отдельных слов, не давая возможности перераспределить если вы превысите это число. Вы можете передать указатель на указатель на символ * и перераспределить, если необходимо. Также обратите внимание, что если вы не возвращаете отрицательное число в качестве условия ошибки, выбор size_t для возврата может более целесообразным)

При использовании strtok, вы можете адаптировать, где и как strtok отдельные слова, пошив разделителейstrtok использует. (например, в предложении "This. Not that.", если просто разбивать на spaces, ваши разделенные слова будут включать в себя и символ '.'). Чтобы этого не произошло, вы можете указать символ '.' в строке разделителейstrtok. С этой точки зрения, она также имеет смысл передать список разделителей в качестве параметра для вашей parse функции, а также:

int parse (char **words, char *str, char *delims); 

Вы можете использовать первоначальный вызов strtok с исходной строкой, указанной в качестве аргумента, а затем закончить синтаксический анализ оставшихся строк в отдельном цикле, проходящий в качестве аргумента NULL. Или вы можете обрабатывать оба случая в одном цикле for. Это просто вопрос формы, либо это прекрасно.Пример:

int parse (char **words, char *str, char *delims) 
{ 
    int n = 0; 
    char *p; 

    for (p = strtok (str, delims); p; p = strtok (NULL, delims)) 
    { 
     words[n++] = strdup (p); /* allocate/copy */ 

     if (n == MAXW) { /* limit reached - realloc/break */ 
      fprintf (stderr, "warning: MAXW reached.\n"); 
      break; 
     } 
    } 

    return n; 
} 

Простой пример программы, указав разделители и передавая их функции parse вместе с массивом и строка может быть:

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

enum { MAXW = 100, MAXC = 1000 }; 

int parse (char **words, char *str, char *delims); 

int main (void) { 

    char usertyped[MAXC] = {0}; 
    char *userargv[MAXW] = {NULL}; 
    char *delims = " \t\n.,:;"; 
    int i, nwords = 0; 

    printf ("typesomething> "); 

    if (!fgets (usertyped, 1000, stdin)) { 
     fprintf (stderr, "error: invalid input.\n"); 
     return 1; 
    } 

    if (!(nwords = parse (userargv, usertyped, delims))) { 
     fprintf (stderr, "error: parsed no words.\n"); 
     return 1; 
    } 

    for (i = 0; i < nwords; i++) 
     printf ("userargv[%2d] : %s\n", i, userargv[i]); 

    for (i = 0; i < nwords; i++) 
     free (userargv[i]); 

    return 0; 
} 

int parse (char **words, char *str, char *delims) 
{ 
    int n = 0; 
    char *p; 

    for (p = strtok (str, delims); p; p = strtok (NULL, delims)) 
    { 
     words[n++] = strdup (p); /* allocate/copy */ 

     if (n == MAXW) { /* limit reached - realloc/break */ 
      fprintf (stderr, "warning: MAXW reached.\n"); 
      break; 
     } 
    } 

    return n; 
} 

Пример использования/вывода

$ ./bin/strtok_parse 
typesomething> a quick brown fox jumps over the laszy dog. 
userargv[ 0] : a 
userargv[ 1] : quick 
userargv[ 2] : brown 
userargv[ 3] : fox 
userargv[ 4] : jumps 
userargv[ 5] : over 
userargv[ 6] : the 
userargv[ 7] : laszy 
userargv[ 8] : dog 

Несколько дополнительных заметок. Обычно в C стиль избегает использования переменных camelCase. Таким образом, usertyped вместо userTyped выше. (другой вопрос только для формы). Поскольку strdup выделяет вам память, вы должны убедиться, что возврат не NULL (как и в случае с malloc или calloc) для защиты от исчерпания памяти. Также обратите внимание, что вы можете либо #define SOMECONST value, либо, как указано выше, использовать enum для определения констант. Дайте мне знать, если у вас возникнут дополнительные вопросы.

Смежные вопросы