Выделение памяти для динамического c массива - PullRequest
0 голосов
/ 24 апреля 2020

Я застрял в распределении памяти при решении упражнения.

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

Пример:

Input: "abc def gh-!" && "-"
Output: ["abc def gh", "!"]

Код:

#include<stdlib.h>
  typedef struct s_string_array {
    int size;
    char** array;
  } string_array;


string_array* my_split(char* a, char* b) {

  //Memory allocation part:

  string_array*ptr=(string_array*)malloc(sizeof(string_array));
  int count=0;
  for(int i=0;a[i]!='\0';i++)
  {
   if(a[i]==b[0])
   {
    count++;
   }
  }
  ptr->size=count+1;
  ptr->array=malloc(sizeof(char*)*ptr->size);
  int size2=0;
  int q=0;
  for(int i=0;i<ptr->size;i++)
  {
      for(;a[q]!=b[0];q++)
      {
       size2++;
      }
      ptr->array[i]=malloc(sizeof(char)*(size2+2));
      ptr->array[i][size2+1]='\0';
      q+=2;
  }

  //Filling the array:

  int c=0;
  for(int i=0;a[i]!='\0';i++)
  {
    if(a[i]!=b[0]){
     for(int j=i,r=0;a[j]!=b[0];j++,r++)
     {
      ptr->array[c][r]=a[j];
     }
     c++;
    }
  }
  return ptr;
}

Выдает ошибку. Может кто-нибудь объяснить, что я делаю не так?

Ответы [ 2 ]

1 голос
/ 24 апреля 2020

Для начала это объявление функции

string_array* my_split(char* a, char* b) {

не имеет большого смысла. Первый параметр должен иметь квалификатор const, поскольку переданная строка не изменяется в функции, а второй параметр не должен быть указателем. Также бессмысленно возвращать из функции указатель на объект типа string_array.

Функция должна быть объявлена ​​как минимум как

string_array my_split( const char *s, char c ) {

Это l oop

  int count=0;
  for(int i=0;a[i]!='\0';i++)
  {
   if(a[i]==b[0])
   {
    count++;
   }
  }

не считает количество подстрок, разделенных символом b[0], поскольку такие символы могут следовать друг за другом без промежуточных других символов. Так, например, эта строка

"---A-"

имеет только одну подстроку "A" при условии, что разделитель '-'.

Неясно, почему ptr->size установлено в значение count+1.

Поскольку исходная строка может начинаться с отдельного символа, то это l oop

  for(;a[q]!=b[0];q++)
  {
   size2++;
  }

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

  ptr->array[i]=malloc(sizeof(char)*(size2+2));

не имеет смысла.

И вам нужно повторно инициализировать переменную size_t в ноль во внешнем l oop

  int size2=0;
  int q=0;
  for(int i=0;i<ptr->size;i++)

Обратите внимание, что функции, выделяющие память, могут потерпеть неудачу , То есть они могут вернуть NULL. Вы должны обрабатывать такие ситуации.

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

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

struct substring_array 
{ 
    size_t total;
    size_t actual;
    char **p; 
} split( const char *s, char c )
{
    struct substring_array a = { .total = 0, .actual = 0, .p = NULL };

    //  count the total number of substrings
    for ( const char *t = s; *t; )
    {
        while ( *t == c ) ++t;

        if ( *t )
        {
            ++a.total;
            while ( *++t != '\0' && *t != c );
        }
    }

    //  extract substrings
    int success = 1;
    while ( success && *s )
    {
        while ( *s == c ) ++s;

        if ( *s )
        {
            const char *first = s;

            while ( *++s != '\0' && *s != c );

            size_t len = s - first;

            char *current = malloc( len + 1 );
            success = current != NULL;

            if ( success )
            {
                char **tmp = realloc( a.p, ( a.actual + 1 ) * sizeof( char * )  );

                success = tmp != NULL;

                if ( success )
                {
                    a.p = tmp;
                    strncpy( current, first, len );
                    current[len] = '\0';
                    a.p[a.actual++] = current;
                }
                else
                {
                    free( current );
                }
            }
        }
    }

    return a;
}

int main(void) 
{
    const char *s = "abc def gh-!";
    char c = '-';

    struct substring_array a =split( s, c );

    if ( a.total == a.actual )
    {
        printf( "There were extracted all %zu substrings\n", a.total );
    }
    else
    {
        printf( "There were extracted %zu substrings of total %zu substrings\n", 
                a.actual, a.total );
    }

    for ( size_t i = 0; i < a.actual; i++ ) puts( a.p[i] );

    while ( a.actual != 0 ) free( a.p[--a.actual] );
    free( a.p );

    return 0;
}

Программа вывод

There were extracted all 2 substrings
abc def gh
!
1 голос
/ 24 апреля 2020

Я думаю, вы движетесь в неправильном направлении. Когда я читаю это:

Функция должна возвращать массив, содержащий строку

, это говорит мне, что функция должна возвращать указатель на символ с нулем в конце массив символов (т. е. строка стиля C).

Другими словами, то, что вы пытаетесь вернуть, - это сложный путь.

Примерно так должно поступить:

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

char* my_split(const char* str, const char sep)
{
    const char* p = str;
    size_t len = 0;
    size_t words = 1;

    // Count the number of chars to copy and the number of words
    while (*p)
    {
        if (*p == sep) ++words; else ++len;
        ++p;
    }

    if (len == 0)
    {
        char* out = malloc(3);
        assert(out);
        strcpy(out, "[]");
        return out;
    }

    // Calculate required memory
    size_t total =
                    1 +              // termination
                    2 +              // [ and ]
                    2 * words +      // " and " around each word
                    2 * (words-1) +  // the , and space between words
                    len;             // the strings

    char* out = calloc(total, 1);
    assert(out);
    strcpy(out, "[\"");
    size_t index = 2;
    p = str;
    while(*p)
    {
        if (*p == sep)
        {
            // Word finished prepare the next word (if any)
            strcat(out, "\"");
            ++index;
            if (*(p+1))
            {
                strcat(out, ", \"");
                index +=3;
            }
        }
        else
        {
            out[index] = *p;
            ++index;
        }
        ++p;
    }
    strcat(out, "\"]");

    // Verify the malloc size
    assert((total-1) == strlen(out));

    return out;

}

int main()
{
  char* input1 = "abc def gh-!";
  char* output1 = my_split(input1, '-');
  printf("%s\n", output1);
  free(output1);

  char* input2 = "a-b-c-d-e-f-g";
  char* output2 = my_split(input2, '-');
  printf("%s\n", output2);
  free(output2);

  return 0;
}

Вывод:

["abc def gh", "!"]
["a", "b", "c", "d", "e", "f", "g"]
...