首页 > 解决方案 > char* 在循环的最后一次迭代中被破坏

问题描述

因此,我正在尝试构建一个string_split函数来根据分隔符拆分 c 样式的字符串。

这是该函数的代码:

char** string_split(char* input, char delim)
{
    char** split_strings = malloc(sizeof(char*));
    char* charPtr;

    size_t split_idx = 0;
    int extend = 0;

    for(charPtr = input; *charPtr != '\0'; ++charPtr)
    {
        if(*charPtr == delim || *(charPtr+1) == '\0')
        {
            if(*(charPtr+1) == '\0') extend = 1; //extend the range by one for the null byte at the end
            char* string_element = calloc(1, sizeof(char));

            for(size_t i = 0; input != charPtr+extend; ++input, ++i)
            {
                if(string_element[i] == '\0')
                {
                    //allocate another char and add a null byte to the end
                    string_element = realloc(string_element, sizeof(char) * (sizeof(string_element)/sizeof(char) + 1));
                    string_element[i+1] = '\0';
                }
                string_element[i] = *input;
            }
            printf("string elem: %s\n", string_element);
            split_strings[split_idx++] = string_element;
            
            //allocate another c-string if we're not at the end of the input
            split_strings = realloc(split_strings, sizeof(char*) *(sizeof(split_strings)/sizeof(char*) + 1));    

            //skip over the delimiter 
            input++;
            extend = 0;
        }
    }
    free(charPtr);
    free(input);
    return split_strings;
}

本质上,它的工作方式是有两个char*,inputcharPtrcharPtr从输入字符串的开头开始input计数分隔符的下一个实例,然后从分隔符的前一个实例(或输入字符串的开头)开始计数,并将每个实例复制char到一个新的char*. 一旦构建了字符串,它就会被添加到char**数组中。

还有一些有趣的位用于跳过分隔符并处理输入字符串的端点。该函数是这样使用的:

int main()
{
    char* str = "mon,tue,wed,thur,fri";
    char delim = ',';
    char** split = string_split(str, delim);

    return 1;
}

无论如何,它在大多数情况下都有效,除了char*返回char**数组中的第一个已损坏,并且只是被随机垃圾占据。

例如打印splitfrom mainyield 的元素:

split: α↨▓
split: tue
split: wed
split: thur
split: fri

奇怪的是,返回所需标记split_strings[0]的数组的内容是char*monstring_split

split_strings[split_idx++] = string_element;

它将其内容从mon垃圾。任何帮助表示赞赏,谢谢。

标签: csplitc-stringsstring-literalsfunction-definition

解决方案


您的函数至少是不正确的,因为它试图释放传递的字符串

char** string_split(char* input, char delim)
{

    //...

    free(charPtr);
    free(input);
    return split_strings;
}

就您的程序而言,它是字符串文字

char* str = "mon,tue,wed,thur,fri";
char delim = ',';
char** split = string_split(str, delim);

您不能释放字符串文字。

并且第一个参数应具有限定符const

您的函数中还有许多其他错误。

例如sizeof(string_element)/sizeof(char)此语句中使用的表达式

string_element = realloc(string_element, sizeof(char) * (sizeof(string_element)/sizeof(char) + 1));

不会产生早期分配给指针指向的数组的字符数string_element。为每个新字符重新分配数组并没有什么意义。

例如,该函数可以如下面的方式显示,如下面的演示程序所示。

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

char ** string_split( const char *s, char delim )
{
    size_t n = 1;
    char **a = calloc( n, sizeof( char * ) );
    
    while ( *s )
    {
        const char *p = strchr( s, delim );
        
        if ( p == NULL ) p = s + strlen( s );
        
        if (  p != s )
        {
            char *t = malloc( p - s + 1 );
            
            if ( t != NULL ) 
            {
                memcpy( t, s, p - s );
                t[p-s] = '\0';
            }
            
            char **tmp = realloc( a, ( n + 1 ) * sizeof( char * ) );
            
            if ( tmp == NULL )
            {
                free( t );              
                break;
            }
            
            a = tmp;
            
            a[n-1] = t;
            a[n] = NULL;
            ++n;
        }
        
        s = p + ( *p != '\0' ); 
    }
    
    return a;
}

int main(void) 
{
    char* str = "mon,tue,wed,thur,fri";
    char delim = ',';

    char **split = string_split( str, delim );
    
    for ( char **p = split; *p != NULL; ++p )
    {
        puts( *p );
    }
    
    for ( char **p = split; *p != NULL; ++p ) free( *p );
    free( split );
    
    return 0;
}

程序输出为

mon
tue
wed
thur
fri

推荐阅读