0

I get a runtime error when running a C program, Here is the C source (parsing.h header code a little lower):

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

and the parsing.h file:

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

I'm sure most of the code is unneeded but I posted the whole lot in case there is some relevance, Here is the runtime error:

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

Thanks in advance and for info I didn't program the whole lot but took some pieces from some places but most is my programming Thanks!.

7
  • 1
    Welcome to Stack Overflow. Please read the About page soon. Allocating 10 bytes with malloc() is pitifully small (use 4096, for example), and modestly pointless (a local variable is simpler). Then using gets() to read data is a disaster — never, never, never, never use gets()! (It is no longer a part of standard C11.) Not even in toy programs. You get some compensatory kudos for using an assertion at all. You will need to learn either how to use a debugger or how to insert print statements to provide you with the information you need to see what is going wrong. Commented Dec 14, 2013 at 20:34
  • 2
    Have you heard of a debugger? It will be quicker than posting lots of code Commented Dec 14, 2013 at 20:34
  • 1
    Also, while we're at it, header files should not normally contain function definitions; when they do, they should be static inline functions only. You put declarations in a header (parsing.h) and the definitions in a separate source file (parsing.c) and compile both the main program file and the parsing.c file separately and link them together. While you can get away with it in this context, what you are doing is not scalable (as soon as more than one source file needs to use the functions, you're in a losing position). Commented Dec 14, 2013 at 20:40
  • I am now using scanf() and I get no error but nothing gets displayed. Commented Dec 14, 2013 at 20:44
  • @JonathanLeffler So you now (and hopefully otherwise too) understand my frustration ;-) Commented Dec 14, 2013 at 20:51

2 Answers 2

1

The purpose of the assert function is that is will stop your program if the condition passed as an argument is false. What this tells you is that when you ran your program, idx != count - 1 at line 69. I didn't take the time to check what import that has on the execution of your program, but apparently (?) idx was intended to equal count - 1 there.

Does that help?

Sign up to request clarification or add additional context in comments.

3 Comments

No C compiler can confuse the expression in assert. It simply isn't a C compiler if it does get confused. The parentheses are unnecessary.
If I comment the assert line then a Segmentation Fault occurs after it prints two values, But I burrowed a bit of the Split() Code so I don't quite know how it all works, going to read a tutorial on exactly this subject soon I hope. Thanks for giving insight into the question.
@JonathanLeffler Alright, thanks! I removed that part of the answer now.
0

There are many problems. I'm ignoring the code split into two files; I'm treating it as a single file (see comments to question).

  1. Do not use gets(). Never use gets(). Do not ever use gets(). I said it three times; it must be true. Note that gets() is no longer a Standard C function (it was removed from the C11 standard — ISO/IEC 9899:2011) because it cannot be used safely. Use fgets() or another safe function instead.

  2. You don't need to use dynamic memory allocation for a string of 10 characters; use a local variable (it is simpler).

  3. You need a bigger string — think about 4096.

  4. You don't check whether you got any data; always check input function calls.

  5. You don't free all the substrings at the end of main(), thus leaking memory.

  6. One major problem the Split() code slices and dices the input string so that SplitLen() cannot give you the same answer that Split() does for the number of fields. The strtok() function is destructive. It also treats multiple adjacent delimiters as a single delimiter. Your code won't account for the difference.

  7. Another major problem is that you analyze the strings based on the delimiter passed into the Split() function, but you use strtok(..., ',') to actually split on commas. This is more consistent with the commentary and names, but totally misleading to you. This is why your assertion fired.

  8. You don't need to include <malloc.h> unless you are using the extra facilities it provides. You aren't, so you should not include it; <stdlib.h> declares malloc() and free() perfectly well.

This code works for me; I've annotated most of the places I made changes.

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

Sample run:

$ 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
]
$

Note that fgets() keeps the newline and gets() does not, so the newline was included in output. Note also how the printf() printing the data showed the limits of the strings; that is enormously helpful on many occasions.

4 Comments

Thank you so much!, it worked and I could have rated your answer but I have only 1 rating :(. Thank you anyway:):)
the only problem was that you re using declerations inside the for loops and my compiler is not C99.:)
Curious: your code has a printf() statement before char *a = malloc(10);, so I assumed it was safe — it seemed that you must be using a C99 compiler for that to be legitimate. However, maybe you're on Windows with MSVC. In that case, you have to move things around a little, but the changes are minor. If you are stuck with a compiler that only supports a 20+ year old standard, instead of the 10+ year old standard or the couple of years old standard, it is worth pointing this out (or at least mentioning it). Most companies manage to fix things so that they are not two decades out of date.
Im on linux with GCC. or on 'Fedora'. So that's strange.

Your Answer

By clicking “Post Your Answer”, you agree to our terms of service and acknowledge you have read our privacy policy.

Start asking to get answers

Find the answer to your question by asking.

Ask question

Explore related questions

See similar questions with these tags.