C运行时错误中的拆分功能

时间:2013-12-14 20:31:20

标签: c pointers

运行C程序时出现运行时错误, 这是C源代码(parsing.h头代码稍低):

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include "parsing.h"
int main()
{
    printf("Enter text seperated by single spaces :\n");
    char *a = malloc(sizeof(char)*10);
    gets(a);
    char **aa = Split(a, ' ');
    int k = SplitLen(a, ' ');
    int i = 0;
    for(;i<k;i++)
    {
        printf("%s\n", aa[i]);
    }
    free(a);
    free(aa);
    return 0;
}

和parsing.h文件:

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

char** Split(char* a_str, const char a_delim)
{
    char** result    = 0;
    int count     = 0;
    char* tmp        = a_str;
    char* last_comma = 0;
    /* Count how many elements will be extracted. */
    while (*tmp)
    {
        if (a_delim == *tmp)
        {
            count++;
            last_comma = tmp;
        }
        tmp++;
    }
    /* Add space for trailing token. */
    count += last_comma < (a_str + strlen(a_str) - 1);

    /* Add space for terminating null string so caller
       knows where the list of returned strings ends. */
    count++;
    result = malloc(sizeof(char*) * count);

    if (result)
    {
        size_t idx  = 0;
        char* token = strtok(a_str, ",");

        while (token)
        {
            assert(idx < count);
            *(result + idx++) = strdup(token);
            token = strtok(0, ",");
        }
        assert(idx == count - 1);
        *(result + idx) = 0;
    }
    return result;
}

int SplitLen(char *src, char sep)
{
    int result = 0;
    int i;
    for(i = 0; i<strlen(src); i++)
    {
        if(src[i] == sep)
        {
            result += 1;
        }
    }
    return result;
}

我确信大部分代码都是不需要的,但我发布了全部内容,以防有一些相关性,这是运行时错误:

a.out: parsing.h:69: Split: Assertion `idx == count - 1' failed.
Aborted

在此先感谢并获取信息我没有对整个程序进行编程,但从某些地方拍摄了一些内容,但大多数是我的编程谢谢!。

2 个答案:

答案 0 :(得分:1)

assert函数的目的是,如果作为参数传递的条件为false,则会停止程序。这告诉你的是,当你在第69行运行你的程序idx != count - 1时。我没有花时间检查你的程序执行有什么导入,但显然(?){{1}那意味着等于idx

这有帮助吗?

答案 1 :(得分:0)

有很多问题。我忽略了分成两个文件的代码;我将其视为单个文件(请参阅提问题)。

  1. 请勿使用gets()。切勿使用gets()。不要使用gets()。我说了三次;一定是真的。请注意,gets()不再是标准C函数(它已从C11标准 - ISO / IEC 9899:2011中删除),因为它无法安全使用。请改用fgets()或其他安全功能。

  2. 您不需要为10个字符的字符串使用动态内存分配;使用局部变量(更简单)。

  3. 你需要一个更大的字符串 - 想想4096。

  4. 您不检查是否有任何数据;总是检查输入函数调用。

  5. 你没有释放main()末尾的所有子串,从而泄漏内存。

  6. 一个主要问题 Split()代码切片并切断输入字符串,以便SplitLen()无法为您提供Split()所做的相同答案字段数。 strtok()函数具有破坏性。它还将多个相邻分隔符视为单个分隔符。您的代码不会考虑差异。

  7. 另一个主要问题是您根据传递到Split()函数的分隔符分析字符串,但您使用strtok(..., ',')实际分割逗号。这与评论和名称更加一致,但完全误导你。这就是你的断言被解雇的原因。

  8. 除非您使用其提供的额外设施,否则无需包含<malloc.h>。你不是,所以你不应该包括它; <stdlib.h>完全声明malloc()free()

  9. 此代码适合我;我已经注释了我改变的大部分地方。

    #include <assert.h>
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    static int altSplitLen(char **array);
    static char **Split(char *a_str, const char a_delim);
    static int SplitLen(char *src, char sep);
    
    int main(void)
    {
        printf("Enter text separated by single spaces:\n");
        char a[4096];       // Simpler
        if (fgets(a, sizeof(a), stdin) != 0)    // Error checked!
        {
            char **aa = Split(a, ' ');
            int k = SplitLen(a, ' ');
            printf("SplitLen() says %d; altSplitLen() says %d\n", k, altSplitLen(aa));
    
            for (int i = 0; i < k; i++)
            {
                printf("%s\n", aa[i]);
            }
    
            /* Workaround for broken SplitLen() */
            {
            puts("Loop to null pointer:");
            char **data = aa;
            while (*data != 0)
                printf("[%s]\n", *data++);
            }
    
            {
            // Fix for major leak!
            char **data = aa;
            while (*data != 0)
                free(*data++);
            }
            free(aa);       // Major leak!
        }
        return 0;
    }
    
    char **Split(char *a_str, const char a_delim)
    {
        char **result    = 0;
        size_t count     = 0;
        char *tmp        = a_str;
        char *last_comma = 0;
    
        /* Count how many elements will be extracted. */
        while (*tmp)
        {
            if (a_delim == *tmp)
            {
                count++;
                last_comma = tmp;
            }
            tmp++;
        }
        /* Add space for trailing token. */
        count += last_comma < (a_str + strlen(a_str) - 1);
    
        /* Add space for terminating null string so caller
           knows where the list of returned strings ends. */
        count++;
        result = malloc(sizeof(char *) * count);
    
        if (result)
        {
            char delim[2] = { a_delim, '\0' };  // Fix for inconsistent splitting
            size_t idx  = 0;
            char *token = strtok(a_str, delim);
    
            while (token)
            {
                assert(idx < count);
                *(result + idx++) = strdup(token);
                token = strtok(0, delim);
            }
            assert(idx == count - 1);
            *(result + idx) = 0;
        }
        return result;
    }
    
    int SplitLen(char *src, char sep)
    {
        int result = 0;
        for (size_t i = 0; i < strlen(src); i++)
        {
            if (src[i] == sep)
            {
                result += 1;
            }
        }
        return result;
    }
    
    static int altSplitLen(char **array)
    {
        int i = 0;
        while (*array++ != 0)
            i++;
        return i;
    }
    

    示例运行:

    $ parsing
    Enter text separated by single spaces:
    a b c d e f gg hhh iii jjjj exculpatory evidence
    SplitLen() says 0; altSplitLen() says 12
    Loop to null pointer:
    [a]
    [b]
    [c]
    [d]
    [e]
    [f]
    [gg]
    [hhh]
    [iii]
    [jjjj]
    [exculpatory]
    [evidence
    ]
    $
    

    请注意fgets()保留换行符,gets()不换行,因此换行符中包含换行符。还要注意打印数据的printf()如何显示字符串的限制;这在很多场合都非常有用。