0

我在解决练习时被困在内存分配中。

练习要求:创建一个根据分隔符拆分字符串的函数。第二个参数是唯一的字符分隔符。该函数应返回一个包含分隔符之间的字符串的数组。

例子:

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;
}

它给了我一个错误。有人可以解释我做错了什么吗?

4

2 回答 2

1

对于初学者来说,这个函数声明:

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

没有多大意义。第一个参数应具有限定符 const,因为传递的字符串在函数中没有被更改,第二个参数不应是指针。从函数返回指向类型对象的指针也是没有意义的string_array

该函数应至少声明为

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

这个循环

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

不计算由字符分隔的子字符串的数量,b[0]因为这些字符可以相互跟随而无需中间的其他字符。所以例如这个字符串

"---A-"

"A"如果分隔符是.则只有一个子字符串'-'

目前尚不清楚为什么ptr->size设置为 value count+1

由于源字符串可以从单独的字符开始,所以这个循环

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

不会因为这个内存分配而迭代

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

没有意义。

而且您必须在外循环中将变量 size_t 重新初始化为零

  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
!
于 2020-04-24T16:29:33.140 回答
1

我认为你正朝着错误的方向前进。当我读到这个:

该函数应返回一个包含字符串的数组

它告诉我该函数应返回一个指向以零结尾的字符数组(即 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"]
于 2020-04-24T12:40:15.033 回答