Есть ли способ разбить массив строк на подстроку строк на токене - PullRequest
2 голосов
/ 09 июня 2019

В принципе, есть ли способ разбить массив строк на массивы строк до и после токена ("|") в C.

Пример показан ниже.

char *input[] = {"hello","I","am","|","a","cool","|","guy"}

//code

и в результате получается 3 массива, содержащих

{"Hello","I","am"}
{"a","cool"}
{"guy"}

Я пытался strtok, но похоже, что строка разбивается на части, а не массив строк на новые, отдельные подмассивы строк. Я также не знаю точно, сколько токенов "|" будет присутствовать, и мне потребуется неизвестное количество новых массивов (можно сказать, что их будет меньше 10). Они будут переданы в execvp, поэтому не будет работать с одной строкой и запоминать, где начинать и останавливать поиск.

Ответы [ 3 ]

1 голос
/ 10 июня 2019

Они будут переданы в execvp

Предполагая, что строки содержат программу, которая должна быть выполнена (1-й параметр до execvp()), и строки будут использоваться в порядке появления в соответствии с этим массивом указателей

char *input[] = {"hello","I","am","|","a","cool","|","guy"}

тогда возможное простое решение без дублирования может выглядеть так:

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

char * input[] = {"hello", "I", "am", "|", 
                  "a", "cool", "|",
                  "guy", "|"}; /* note the additional trailing `"|"`. */

int main(void)
{
  char ** pcurrent = input;
  char ** pend = pcurrent + sizeof input / sizeof *input;

  while (pcurrent < pend)
  {
    {
      char ** ptmp = pcurrent;
      while (ptmp < pend && **ptmp != '|')
      {
        ++ptmp;
      }

      *ptmp = NULL;
    }

    {
      pid_t pid = fork();
      if ((pid_t) -1) == pid)
      {
        perror("fork() failed");
        exit(EXIT_FAILURE);
      }

      if ((pid_t) 0) == pid) /* child */
      {
        execvp(pcurrent[0], pcurrent);
        perror("execvp() failed");
        exit(EXIT_FAILURE);
      }

      /* parent */
      pcurrent = ptmp + 1;
    }
  }  /* while (pcurrent < pend) */
}  /* int main(void) */
0 голосов
/ 09 июня 2019

Вот решение, которое не включает динамическое выделение памяти.

Прежде чем углубляться в детали ...

Я думаю, что для решения такой проблемы полезно подумать о том, как «строки» хранятся в памяти. Это может выглядеть примерно так, как на картинке. (Адреса памяти совершенно нереалистичны - и в конце каждой строки будут нулевые терминаторы - но вы поняли).

enter image description here

Как показано на рисунке, жизненно важная информация, которая нам нужна для каждого «подмассива», может храниться в паре <char **, int>. char ** - это адрес первой «строки» в подмассиве; int - это количество строк в нем.

Мы можем использовать struct string_array_t для хранения этой информации.

typedef struct {
    // Pointer to first string in sub-array
    char **p;
    // Number of strings in sub-array
    int count;
} string_array_t;

Мы размещаем массив этих в стеке ; таким образом, нет необходимости в malloc() или free() - до тех пор, пока мы выделяем достаточно подмассивов.

    string_array_t string_arrays[MAX_SUB_ARRAYS] = {0};
    char *input[] = {"hello", "I", "am", "|", "a", "cool", "|", "guy"};
    // Pointer to current sub-array
    string_array_t *cur = NULL;
    size_t n_sub_arrays = 1;

Инициализировать наши счетчики и указатели:

    int i = 0, j = 0, k = 0;

    cur = &string_arrays[0];
    size_t n_strings_total = sizeof(input) / sizeof(input[0]);

Затем переберите массив.

    for (i = 0; i < n_strings_total; i++) {
        if (!strcmp(input[i], "|")) {
            // Store total number of strings in this sub-array
            cur->count = k;
            k = 0;
            // Switch to next sub-array
            cur = &string_arrays[++j];
            if (j >= MAX_SUB_ARRAYS) {
                fprintf(stderr, "Not enough sub-arrays allocated ...\n");
                break;
            }
            n_sub_arrays++;
            continue;
        }
        if (k == 0) {
            cur->p = &input[i];
        }
        k++;
    }
    cur->count = k;

Распечатать результаты.

    printf("Found %zu sub arrays ...\n", n_sub_arrays);
    for (i = 0; i < n_sub_arrays; i++) {
        string_array_t *cur = &string_arrays[i];
        for (j = 0; j < cur->count; j++) {
            printf("%s ", *(cur->p++));
        }
        printf("\n");
    }
0 голосов
/ 09 июня 2019

Вам нужно вручную разбить входной массив. И динамически выделять новое место для хранения результата. Например. как:

#include <stdio.h>
#include <stdbool.h>

int main()
{
    char *input[] = {"hello","I","am","|","a","cool","|","guy"};

    int inputLength = sizeof(input)/sizeof(input[0]);
    printf("inputLength - %d\n", inputLength);
    const char ***result2DimArray = malloc(sizeof(char**) * inputLength);
    int *result2DimArrayLengths = malloc(sizeof(int) * inputLength);
    memset(result2DimArrayLengths, 0, sizeof(int) * inputLength);

    const char **currentSection = 0;
    int nextSectionNumber = 0;
    for(int inputIndex = 0; inputIndex < inputLength; inputIndex++)
    {
        if(input[inputIndex][0] == '|')
        {
            currentSection = 0;
        }
        else
        {
            if(!currentSection)
            {
                currentSection = malloc(sizeof(char*) * inputLength);
                result2DimArray[nextSectionNumber] = currentSection;
                nextSectionNumber++;
            }

            *currentSection = input[inputIndex];
            currentSection++;
            result2DimArrayLengths[nextSectionNumber-1]++;
        }
    }

    /*Checking the result*/
    printf("total sections - %d\n", nextSectionNumber);
    for(int i=0; i<nextSectionNumber;i++)
    {
        for(int j=0;j<result2DimArrayLengths[i];j++)
        {
            printf(result2DimArray[i][j]);
            printf(", ");
        }
        puts("");
    }

    return 0;
}
Добро пожаловать на сайт PullRequest, где вы можете задавать вопросы и получать ответы от других членов сообщества.
...