N
N
newmersedez2020-11-15 19:10:35
C++ / C#
newmersedez, 2020-11-15 19:10:35

Parsing a string not via strtok in C. What is the error?

Hello, a problem has arisen, and, due to my inexperience, I have been scratching my head for two hours why this is happening.

There is an input file with operations. For example, the following content:
myvar=15;
bg=25;
ccc=bg+myvar;
print ccc;
bg=ccc*myvar;
print;

At this stage, I need to parse the string so that, for example, it turns out "myvar" "=" "15";

In the parse_string() function, I describe the parsing process itself, but for some reason the top program does not work, it just hangs. As I found out, the reason is in the free(buf) lines, but I don't understand why. I know that the string can be parsed with strtok, but I want to keep the operation signs.

Here's the code itself

#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
 
typedef struct memoryCell
{
    char    *name;
    int     data;
}memoryCell;
 
int     variable_processing(FILE *file, memoryCell *variables);
char    **parse_string(char string[]);
 
int     main(int argc, char *argv[])
{
    int         result;
    FILE        *file;
    memoryCell  *variables;
 
    if(argc != 2)
    {
        perror("Arguments error");
        exit(-1);
    }
    if(!(file = fopen(argv[1], "r")))
    {
        perror("File error");
        exit(-2);
    }
    result = variable_processing(file, variables);
    if(result != 0)
    {
        printf("Error in line %d!\n", result);
        return (-1);
    }
    fclose(file);
    return 0;
}
 
/*task - variables processing
returns 1 if correct*/
int     variable_processing(FILE *file, memoryCell *variables)
{
    char    **parsed_string;
    char    buf[BUFSIZ];
    int     size;
 
    size = 0;
    variables = NULL;
    while(!feof(file))
    {
        fgets(buf, sizeof(buf), file);
        strtok(buf, "\n");
        parsed_string = parse_string(buf);
    }
 
    return (0);
}
 
char    **parse_string(char string[])
{
    int     i;
    int     j;
    int     k;
    int     size;
    char    **parsed_string = NULL;
    char    *buf = NULL;
 
    size = 0;
    k = 0;
    for(i = 0; i < strlen(string); i++)
    {
        if(isdigit(string[i]) || isalpha(string[i]))
        {
            j = i;
            while(isdigit(string[j]) || isalpha(string[j]))
            {
                buf = (char *)realloc(buf, ++k * sizeof(char));
                buf[k - 1] = string[j];
                j++;
            }
            parsed_string = (char **)realloc(parsed_string, ++size * sizeof(char *));
            parsed_string[size - 1] = (char *)malloc(strlen(buf) * sizeof(char));
            strcpy(parsed_string[size - 1], buf);
            free(buf);
            k = 0;
            i = j - 1;
        }
        else
        {
        buf = (char *)malloc(sizeof(char));
        buf[0] = string[i];
        parsed_string = (char **)realloc(parsed_string, ++size * sizeof(char *));
        parsed_string[size - 1] = (char *)malloc(strlen(buf) * sizeof(char));
        strcpy(parsed_string[size - 1], buf);
        free(buf);
        }
    }
    for(i = 0; i < size; i++)
        printf("%s ", parsed_string[i]);
    printf("\n");
    return (parsed_string);
}

Answer the question

In order to leave comments, you need to log in

2 answer(s)
J
jcmvbkbc, 2020-11-15
@newmersedez

sizeof(char)

Always equal to 1 according to the standard, save us and yourself time.
while(isdigit(string[j]) || isalpha(string[j]))
            {
                buf = (char *)realloc(buf, ++k * sizeof(char));
                buf[k - 1] = string[j];
                j++;
            }

After this loop, buf is not closed by the 0-terminator, so it cannot be treated as a string.
parsed_string[size - 1] = (char *)malloc(strlen(buf) * sizeof(char));
strcpy(parsed_string[size - 1], buf);

Buffer overflow because strcpy copies strlen(buf) characters of the string + 1 null byte.

N
newmersedez, 2020-11-15
@newmersedez

Hello again. Why doesn't it work if you add free(buf) to else? Without it, everything works, parses without errors and crashes

char    **parse_string(char string[], int *size)
{
    int     i;
    int     j;
    int     k;
    char    **parsed_string = NULL;
    char    *buf = NULL;

    *size = 0;
    k = 0;
    for(i = 0; i < strlen(string); i++)
    {
        if(isdigit(string[i]) || isalpha(string[i]))
        {
            j = i;
            while(isdigit(string[j]) || isalpha(string[j]))
            {
                buf = (char *)realloc(buf, ++k * sizeof(char) + 1);
                buf[k - 1] = string[j];
                j++;
            }
            buf[k] = '\0';
            parsed_string = (char **)realloc(parsed_string, ++(*size) * sizeof(char *));
            parsed_string[(*size) - 1] = (char *)malloc(strlen(buf));
            strcpy(parsed_string[(*size) - 1], buf);
            free(buf);
            k = 0;
            i = j - 1;
        }
        else
        {
            buf = (char *)malloc(2);
            buf[0] = string[i];
            buf[1] = '\0';
            parsed_string = (char **)realloc(parsed_string, ++(*size) * sizeof(char *));
            parsed_string[(*size) - 1] = (char *)malloc(strlen(buf));
            strcpy(parsed_string[(*size) - 1], buf);
            // free(buf);
        }
    }
    for(i = 0; i < *size; i++)
        printf("'%s' ", parsed_string[i]);
    printf("\n");
    return (parsed_string);
}

Didn't find what you were looking for?

Ask your question

Ask a Question

731 491 924 answers to any question