2016-04-30 2 views
-8

Если у меня есть структура данных, такая как матрица или дерево, и я хочу отделить цикл for от очень большой функции, в которой включена указанная выше переменная, как должен выглядеть вызов? Я попробовал следующее, но получаю ошибку сегментации.Как выбрать типы для прототипа функции?

void write_command(int w, char *argv[], char *string[]) { 
    char *dest; 

    for (int r = 0; argv[r] != NULL; r++) { 
     dest = malloc(sizeof(char *) * strlen(argv[r]) + 1); 
     *dest = '0'; 
     strcpy(dest, argv[r]); 
     string[w][r] = *dest; 
     free(dest); 
    } 
} 

Я думаю, вы видите, что я пытаюсь сделать, но как объявить переменные? Я получаю segfault на string[w][r] = *dest;.

Я не думаю, что вы хотите посмотреть, что я рефакторинг, но это самая большая и самая нечитаемая функция.

static int runCmd(const char *cmd) { 
    const char *cp; 
    pid_t pid; 
    int status; 
    struct command structcommand[15]; 
    char **argv = 0; 
    int argc = 1; 
    bool pipe = false; 
    char *string[z][z]; 
    char *pString3[40]; 
    char *pString2[40]; 
    int n = 0; 
    char **ptr1; 
    char string1[z]; 
    bool keep = false; 
    char *pString1[z]; 
    char *pString[z]; 
    *pString1 = "\0"; 
    *pString = "\0"; 
    char *temp = {'\0'}; 
    int w = 0; 
    bool b = false; 
    int j = 0; 
    int i; 
    int p = 0; 
    char **ptr; 
    char *tmpchar; 
    char *cmdtmp; 
    bool b1 = false; 
    char *dest; 
    int y = 0; 
    i = 0; 
    int h = 0; 
    nullterminate(string); 
    if (cmd) { 
     for (cp = cmd; *cp; cp++) { 
      if ((*cp >= 'a') && (*cp <= 'z')) { 
       continue; 
      } 
      if ((*cp >= 'A') && (*cp <= 'Z')) { 
       continue; 
      } 
      if (isDecimal(*cp)) { 
       continue; 
      } 
      if (isBlank(*cp)) { 
       continue; 
      } 
      if ((*cp == '.') || (*cp == '/') || (*cp == '-') || 
       (*cp == '+') || (*cp == '=') || (*cp == '_') || 
       (*cp == ':') || (*cp == ',') || (*cp == '\'') || 
       (*cp == '"')) { 
       continue; 
      } 
     } 
    } 
    if (cmd) { 
     cmdtmp = malloc(sizeof(char *) * strlen(cmd) + 1); 
     strcpy(cmdtmp, cmd); 
     tmpchar = malloc(sizeof(char *) * strlen(cmd) + 1); 
     if (tmpchar == NULL) { 
      printf("Error allocating memory!\n"); /* print an error message */ 
      return 1; /* return with failure */ 
     } 
     strcpy(tmpchar, cmd); 
     ptr1 = str_split(pString3, cmdtmp, '|'); 
     if (strstr(cmd, "|") == NULL) {   /* not a pipeline */ 
      makeArgs(cmd, &argc, (const char ***) &argv, pipe, 0, 0); 
      for (j = 0; j < argc; j++) { 
       string[0][j] = argv[j]; 
       structcommand[i].argv = string[0]; /*process;*/ 
      } 
      n++; 
     } 
     else { 
      for (i = 0; *(ptr1 + i); i++) { /* tokenize the input string for each pipeline*/ 
       n++; /* save number of pipelines */ 
       int e = 0; /* a counter */ 
       *pString = "\0"; /* should malloc and free this? */ 
       strcpy(string1, *(ptr1 + i)); 
       if ((string1[0] != '\0') && !isspace(string1[0])) { /* this is neither the end nor a new argument */ 
        ptr = str_split(pString2, *(&string1), ' '); /* split the string at the arguments */ 
        h = 0; 
        for (j = 0; *(ptr + j); j++) { /* step through the arguments */ 
         /* the pipeline is in cmdtmp and the argument/program is in ptr[i] */ 
         if (ptr + j && !b && strstr(*(ptr + j), "'")) { 
          b = true; 
          strcpy(temp, *(ptr + j)); 
          if (y < 1) { 
           y++; 
          } 
         } 
         while (b) { 
          if (*(ptr + j) && strstr(*(ptr + j), "'")) { /* end of quote */ 
           b = false; 
           if (y < 1) { 
            string[i][j] = strcpy(temp, *(ptr + j)); 
           } 
           y = 0; 
          } 
          else if (*(ptr + j)) { /* read until end of quote */ 
           string[i][j] = temp; 
           continue; 
          } else { 
           b = false; 
           break; 
          } 
         } 
         if (ptr + j) { 
          if (*(ptr + j)[0] == '{') { 
           keep = true; 
          } 
          if (testFn(*(ptr + j))) { /* test for last char */ 
           string[i][j - p] = concat(*pString1, *(ptr + j)); 
           keep = false; 
           free(*pString1); 
           goto mylabel; 
          } 
          if (keep) { 
           *pString1 = concat(*pString1, *(ptr + j)); 
           *pString1 = concat(*pString1, " "); 
           p++; 
          } else { 
//        strcpy(temp, *(ptr + j)); 
           b1 = false; 
           int q = j; 
           for (e = 0; *(ptr + q + e); e++) { /* step through the string */ 
            b1 = true; 
            if (*(ptr + e + q)) { 
             *pString = concat(*pString, *(ptr + e + q)); 
             *pString = concat(*pString, " "); 
            } 
            j = e; 
           } 
           if (makeArgs(*pString, &argc, (const char ***) &argv, pipe, i, h)) { 

            write_command(&w, argv, string[w]); 

            /*for (int r = 0; argv[r] != NULL; r++) { 
             dest = malloc(sizeof(char *) * strlen(argv[r]) + 1); 
             *dest = '0'; 
             strcpy(dest, argv[r]); 
             string[w][r] = dest; 
            }*/ 
            w++; 


           } else { 
            if (!b1) { /* no args (?) */ 
             for (int r = 0; argv[r] != NULL; r++) { 
              string[i][r] = argv[r]; 
             } 

            } 
           } 

          } 
         } 
        } 
        mylabel: 
        free(ptr); 
        dump_argv((const char *) "d", argc, argv); 
       } 
      } 
      free(ptr1); 
      free(cmdtmp); 
      free(tmpchar); 
     } 
     for (i = 0; i < n; i++) { 
      for (j = 0; DEBUG && string[i][j] != NULL; j++) { 
       if (i == 0 && j == 0) printf("\n"); 
       printf("p[%d][%d] %s\n", i, j, string[i][j]); 
      } 
      structcommand[i].argv = string[i]; 
     } 
     fflush(NULL); 
     pid = fork(); 
     if (pid < 0) { 
      perror("fork failed"); 
      return -1; 
     } 
     /* If we are the child process, then go execute the string.*/ 
     if (pid == 0) { 
      /* spawn(cmd);*/ 
      fork_pipes(n, structcommand); 
     } 
     /* 
     * We are the parent process. 
     * Wait for the child to complete. 
     */ 
     status = 0; 
     while (((pid = waitpid(pid, &status, 0)) < 0) && (errno == EINTR)); 
     if (pid < 0) { 
      fprintf(stderr, "Error from waitpid: %s", strerror(errno)); 
      return -1; 
     } 
     if (WIFSIGNALED(status)) { 
      fprintf(stderr, "pid %ld: killed by signal %d\n", 
        (long) pid, WTERMSIG(status)); 

      return -1; 
     } 
    } 
    return WEXITSTATUS(status); 


} 
+1

is 'char * string []' туманный символ 'char * [z] [z]' экземпляр или другая переменная? – user3078414

+5

Нет, на самом деле, это * не ясно, что вы пытаетесь сделать. Мое лучшее предположение заключается в том, что вы пытаетесь сделать глубокую копию данного массива 'argv', но в этом случае не совсем ясно, как начиналось объявление переменной,' char * string [z] [z]; ', вписывается в изображение. Также неясно, почему вы освобождаете выделенную память внутри функции. –

+0

Я пытался реорганизовать большую функцию, вырвать for-loop в функцию и вызвать функцию, но я не привык к прохождению указателей, так как я OOP. Ключевым понятием было понять, что мне не нужно передавать матрицу в качестве параметра, передавая матрицу, можно сделать как массив. Теперь я пытаюсь передать 'struct' для моего следующего рефакторинга, и у меня возникает аналогичная проблема, потому что я не специалист по программированию C. –

ответ

3

Я собираюсь предположить, что вы пытаетесь сделать полную копию argv массива, с тем чтобы быть NULL -завершённым массивом строк, такие как второй параметр функции main() программы на языке С в. Представляемая вами функция предполагает, что вы уже выделили место для самого массива назначения; его работа кажется ограниченным копированием строк аргументов.

Прежде всего, тогда: давайте посмотрим на вызывающего абонента. Если вы делаете глубокую копию стандартного вектора аргументов, то тип целевой переменной должен быть совместим с типом argv (в разговорной форме «совместимый»). Если срок службы копии не нужно выходить за возвращение функцию хозяина, а затем массив переменной длины будет прекрасным выбором:

char *copy[argc + 1]; 

Это избавляет вас от ручного управления памятью самого массива, но а не управления памятью, однозначно распределенной по ее элементам. С другой стороны, если вам нужна копия, чтобы выжить возвращения из функции, в которой она объявлена, то вам придется использовать ручное распределение:

char **copy = malloc((argc + 1) * sizeof(*copy)); 
if (!copy) /* handle allocation failure */ ; 

В любом случае, вы можете передать результирующий массив или указатель непосредственно к вашей функции write_command(), и требуемый тип параметра одинаков. Бессмысленно передавать указатель на copy, поскольку эта функция не будет изменять указатель, который он получает в качестве аргумента; скорее, он изменит память, на которую он указывает.

Вот сигнатура функции вы, кажется, хотят:

void write_command(char *argv[], char *string[]) { 

Учитывая такую ​​подпись, вы могли бы назвать его как ...

write_command(argv, copy); 

....

Ключевой шаг, который вы, по-видимому, хотите выполнить внутри цикла:

string[r] = strdup(argv[r]); 

Вы можете выполнить одно и то же с malloc(), инициализировать последовательность, strcpy(), но это немного глупо, когда stdrup() готов к этой же задаче. Однако не забудьте проверить его возвращаемое значение (или в исходном коде, возвращаемое значение malloc()) в случае сбоя памяти. В любом случае, вы должны не освободить выделенную память в пределах write_command(), потому что это оставляет вас с недопустимыми указателями внутри вашего скопированного массива.


Кроме того, даже если вы действительно есть 2D массив char * в вызывающей, например, ...

char *copies[n][argc + 1]; 

... ничего не меняет с функцией write_command(). Ему не нужно знать или заботиться о том, является ли массив, в который он копирует, является элементом двумерного массива. Вы просто не называть его соответствующим образом, что-то вроде:

write_command(argv, copies[w]); 

Независимо от того, вы должны быть уверены, чтобы освободить скопированные строки аргументов, но только после того, как вы их больше не нужно. Опять же, вы не можете сделать это внутри функции write_command().

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