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从分隔符的上一个实例(或输入字符串开头)算起,并复制每个{ {1}}改成新的char。构建字符串后,会将其添加char*数组中。

还有一些第二个位,用于跳过定界符并处理输入字符串的端点。该功能用法如下:

char**

无论如何,它大部分工作,除了返回的int main() { char* str = "mon,tue,wed,thur,fri"; char delim = ','; char** split = string_split(str,delim); return 1; } 数组中的第一个char*已损坏,而只是被随机垃圾占据。

例如,从char**打印split的元素将产生:

main

奇怪的是,split: α↨▓ split: tue split: wed split: thur split: fri 内容split_strings[0]的数组返回了所需的标记)是char*,就本例而言,一直到最后循环mon函数中主要for循环的内容,特别是其行:

string_split

会将其内容split_strings[split_idx++] = string_element;变为垃圾邮件。谢谢您的任何帮助。

解决方法

任何人都想知道的最终功能应该是非常简单的证明。

char** string_split(char* input,char delim,bool skip_delim)
{
    assert(*input != '\0');

    char** split_strings = malloc(sizeof(char*));
    char* charPtr;

    size_t split_idx             = 0;
    size_t num_allocated_strings = 1;
    size_t 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
                char* temp = realloc(string_element,sizeof(char) * (strlen(string_element) + 1));
                if(temp == NULL)
                {
                    free(string_element);
                    free(split_strings);
                    break;
                }
                string_element = temp;
                string_element[i+1] = '\0';
            }
            string_element[i] = *input;
            }
            split_strings[split_idx++] = string_element;
            num_allocated_strings++;
            
            //allocate another c-string
            char** temp = realloc(split_strings,sizeof(char*) * num_allocated_strings);    
            if(temp == NULL)
            {
                free(string_element);
                free(split_strings);
                break;
            }
            split_strings = temp;

            //skip over the delimiter if required
            if(skip_delim) input++;
            extend = 0;
        }
    }
    split_strings[num_allocated_strings-1] = NULL;
    return split_strings;
}
,

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

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,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