Разделение строки и возвращение массива строк

Проблема, с которой вы столкнулись, связана с перекрывающимися правилами.

Запрос www.mysite.nl/adminer

Соответствует обоим: traefik.frontend.rule=Host:mysite.nl, www.mysite.nl, cdn.mysite.net и traefik.frontend.rule=Host:www.mysite.nl;PathPrefixStrip:/adminer

Поэтому Traefik не знает, на какие запросы направлять.

Используйте метку traefik.frontend.priority, чтобы установить порядок соответствия (из https://docs.traefik.io/configuration/backends/ докер / # на контейнерах [/ д0])

1
задан payne 19 January 2019 в 21:08
поделиться

2 ответа

Решение:

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

char ** split(const char * str, const char * delim)
{
  /* count words */
  char * s = strdup(str);

  if (strtok(s, delim) == 0)
    /* no word */
    return NULL;

  int nw = 1;

  while (strtok(NULL, delim) != 0)
    nw += 1;

  strcpy(s, str); /* restore initial string modified by strtok */

  /* split */
  char ** v = malloc((nw + 1) * sizeof(char *));
  int i;

  v[0] = strdup(strtok(s, delim));

  for (i = 1; i != nw; ++i)
    v[i] = strdup(strtok(NULL, delim));

  v[i] = NULL; /* end mark */

  free(s);

  return v;
}

int main()
{
  char ** v = split("bob is  great", " ");

  for (int i = 0; v[i] != NULL; ++i) {
    puts(v[i]);
    free(v[i]);
  }

  free(v);
  return 0;
}

Как видите, я добавляю нулевой указатель в конце вектора в виде метки, но его можно легко изменить, чтобы он возвращал количество слов и т. Д.

Выполнение:

bob
is
great

Второе решение с учетом замечаний алка:

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

char ** split(const char * str, const char * delim)
{
  /* count words */
  char * s = strdup(str);

  if ((s == NULL) /* out of memory */
      || (strtok(s, delim) == 0)) /* no word */
    return NULL;

  size_t nw = 1;

  while (strtok(NULL, delim) != 0)
    nw += 1;

  strcpy(s, str); /* restore initial string modified by strtok */

  /* split */
  char ** v = malloc((nw + 1) * sizeof(char *));

  if (v == NULL)
    /* out of memory */
    return NULL;

  if ((v[0] = strdup(strtok(s, delim))) == 0) {
    /* out of memory */
    free(v);
    return NULL;
  }

  size_t i;

  for (i = 1; i != nw; ++i) {
    if ((v[i] = strdup(strtok(NULL, delim))) == NULL) {
      /* out of memory, free previous allocs */
      while (i-- != 0)
        free(v[i]);
      free(v);
      return NULL;
    }
  }

  v[i] = NULL; /* end mark */

  free(s);

  return v;
}

int main()
{
  const char * s = "bob is still great";
  char ** v = split(s, " ");

  if (v == NULL)
    puts("no words of not enough memory");
  else {
    for (int i = 0; v[i] != NULL; ++i) {
      puts(v[i]);
      free(v[i]);
    }

    free(v);
  }
  return 0;
}

Когда из памяти возвращается значение NULL (в предыдущем версия это была строка для разделения), конечно, есть и другие способы сигнализировать, что легко


Выполнение в valgrind:

==5078== Memcheck, a memory error detector
==5078== Copyright (C) 2002-2017, and GNU GPL'd, by Julian Seward et al.
==5078== Using Valgrind-3.13.0 and LibVEX; rerun with -h for copyright info
==5078== Command: ./a.out
==5078== 
bob
is
still
great
==5078== 
==5078== HEAP SUMMARY:
==5078==     in use at exit: 0 bytes in 0 blocks
==5078==   total heap usage: 7 allocs, 7 frees, 1,082 bytes allocated
==5078== 
==5078== All heap blocks were freed -- no leaks are possible
==5078== 
==5078== For counts of detected and suppressed errors, rerun with: -v
==5078== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 6 from 3)
0
ответ дан bruno 19 January 2019 в 21:08
поделиться

Подход к разделению строки с неизвестным количеством слов и обеспечению их доступности в ответе функции потребовал бы функции, которая возвращает указатель на указатель на символ . Это позволяет использовать настоящий динамический подход, при котором вы выделяете некоторое начальное количество указателей (скажем, 2, 4, 8 и т. Д.), Совершая один проход через строку, используя strtok, отслеживая количество используемых указателей, выделяя хранилище для каждого токена ( слово), когда вы идете и когда количество используемых указателей равно выделенному количеству, вы просто realloc сохраняете дополнительные указатели и продолжаете.

Краткий пример реализации функции splitstring(), которая делает это похожим на следующее:

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

#define NPTR    8   /* initial number of pointers to allocate */
#define MAXD   32   /* maximum no chars for delimiter */
#define MAXC 1024   /* maximum no chars for user input */

char **splitstring (const char *str, const char *delim, size_t *nwords)
{
    size_t nptr = NPTR,             /* initial pointers */
        slen = strlen (str);        /* length of str */
    char **strings = malloc (nptr * sizeof *strings),   /* alloc pointers */
        *cpy = malloc (slen + 1),   /* alloc for copy of str */
        *p = cpy;                   /* pointer to cpy */

    *nwords = 0;                    /* zero nwords */

    if (!strings) {     /* validate allocation of strings */
        perror ("malloc-strings");
        free (cpy);
        return NULL;
    }

    if (!cpy) {         /* validate allocation of cpy */
        perror ("malloc-cpy");
        free (strings);
        return NULL;
    }
    memcpy (cpy, str, slen + 1);    /* copy str to cpy */

    /* split cpy into tokens */
    for (p = strtok (p, delim); p; p = strtok (NULL, delim)) {
        size_t len;             /* length of token */
        if (*nwords == nptr) {  /* all pointers used/realloc needed? */
            void *tmp = realloc (strings, 2 * nptr * sizeof *strings);
            if (!tmp) {         /* validate reallocation */
                perror ("realloc-strings");
                if (*nwords)    /* if words stored, return strings */
                    return strings;
                else {          /* no words, free pointers, return NULL */
                    free (strings);
                    return NULL;
                }
            }
            strings = tmp;      /* assign new block to strings */
            nptr *= 2;          /* update number of allocate pointers */
        }
        len = strlen (p);       /* get token length */
        strings[*nwords] = malloc (len + 1);    /* allocate storage */
        if (!strings[*nwords]) {                /* validate allocation */
            perror ("malloc-strings[*nwords]");
            break;
        }
        memcpy (strings[(*nwords)++], p, len + 1);  /* copy to strings */
    }
    free (cpy);     /* free storage of cpy of str */

    if (*nwords)    /* if words found */
        return strings;

    free (strings); /* no strings found, free pointers */
    return NULL;
}

int main (void) {

    char **strings = NULL, 
        string[MAXC],
        delim[MAXD];
    size_t nwords = 0;

    fputs ("enter string    : ", stdout);
    if (!fgets (string, MAXC, stdin)) {
        fputs ("(user canceled input)\n", stderr);
        return 1;
    }

    fputs ("enter delimiters: ", stdout);
    if (!fgets (delim, MAXD, stdin)) {
        fputs ("(user canceled input)\n", stderr);
        return 1;
    }

    if ((strings = splitstring (string, delim, &nwords))) {
        for (size_t i = 0; i < nwords; i++) {
            printf (" word[%2zu]: %s\n", i, strings[i]);
            free (strings[i]);
        }
        free (strings);
    }
    else
        fputs ("error: no delimiter found\n", stderr);
}

(примечание : счетчик слов nwords передается как указатель на функцию splitstring(), позволяющий обновлять число слов внутри функции и возвращать их обратно в вызывающую функцию, возвращая при этом указатель на указатель на символ из самой функции )

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

$ ./bin/stringsplitdelim
enter string    : my dog has fleas and my cat has none and snakes don't have fleas
enter delimiters:
 word[ 0]: my
 word[ 1]: dog
 word[ 2]: has
 word[ 3]: fleas
 word[ 4]: and
 word[ 5]: my
 word[ 6]: cat
 word[ 7]: has
 word[ 8]: none
 word[ 9]: and
 word[10]: snakes
 word[11]: don't
 word[12]: have
 word[13]: fleas

(примечание : a ' ' (пробел) было введено в качестве разделителя выше, что приводит к delim содержит " \n" (именно то, что вы хотите) благодаря использованию функции линейно-ориентированного ввода fgets для пользовательского ввода)

Использование памяти / проверка ошибок [1124 ]

В любом написанном вами коде, который динамически распределяет память, у вас есть 2 обязанности в отношении любого выделенного блока памяти: (1) всегда сохраняет указатель на начальный адрес для блок памяти, таким образом, (2) он может быть освобожден ] когда он больше не нужен.

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

Для Linux valgrind является нормальным выбором. Есть похожие проверки памяти для каждой платформы. Все они просты в использовании, просто запустите вашу программу через него.

$ valgrind ./bin/stringsplitdelim
==12635== Memcheck, a memory error detector
==12635== Copyright (C) 2002-2015, and GNU GPL'd, by Julian Seward et al.
==12635== Using Valgrind-3.12.0 and LibVEX; rerun with -h for copyright info
==12635== Command: ./bin/stringsplitdelim
==12635==
enter string    : my dog has fleas and my cat has none and snakes don't have fleas
enter delimiters:
 word[ 0]: my
 word[ 1]: dog
 word[ 2]: has
 word[ 3]: fleas
 word[ 4]: and
 word[ 5]: my
 word[ 6]: cat
 word[ 7]: has
 word[ 8]: none
 word[ 9]: and
 word[10]: snakes
 word[11]: don't
 word[12]: have
 word[13]: fleas
==12635==
==12635== HEAP SUMMARY:
==12635==     in use at exit: 0 bytes in 0 blocks
==12635==   total heap usage: 17 allocs, 17 frees, 323 bytes allocated
==12635==
==12635== All heap blocks were freed -- no leaks are possible
==12635==
==12635== For counts of detected and suppressed errors, rerun with: -v
==12635== ERROR SUMMARY: 0 errors from 0 contexts (suppressed: 0 from 0)

Всегда подтверждайте, что вы освободили всю выделенную память и что ошибок памяти нет.

Посмотрите вещи и дайте мне знать, если у вас есть дополнительные вопросы.

0
ответ дан David C. Rankin 19 January 2019 в 21:08
поделиться
Другие вопросы по тегам:

Похожие вопросы: