应用函数后出现分段错误:!dataValida

Segmentation fault after aplying the function : !dataValida

提问人:HelpMe 提问时间:11/15/2023 最后编辑:HelpMe 更新时间:11/15/2023 访问量:87

问:

在我实现函数 dataValida 后,该函数检查 csv 列上的日期是否设置为 dd/mm/yyyy(唯一可能发生的错误如下:25/12/2010 15:01:56 或 1978|04|30),程序给出分段错误。

当我运行程序时,它显示以下内容:(在此之前,它曾经以正确的方式显示printf,包括示例)

File opened with success
Parsing Concluded
Segmentation fault

我已经尝试以不同的方式重做该函数,但它仍然出现相同的错误。除此之外,当我尝试执行其他功能来检查“estado”是处于活动状态还是非活动状态时,也会发生这种情况。

谁能帮我?

(“contemArrobba”和“paisValido”工作正常)

法典:

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

typedef struct {
    char* id;
    char* nome;
    char* email;
    char* tele;
    char* data;
    char sexo;
    char* passaporte;
    char* pais;
    char* morada;
    char* cria_conta;
    char* pagamento;
    char* estado;
} User;

void freeUser(User *user) {
    // Esta função libera todos os campos de string alocados dinamicamente de um User->
    free(user->id);
    free(user->nome);
    free(user->email);
    free(user->data);
    free(user->passaporte);
    free(user->pais);
    free(user->morada);
    free(user->cria_conta);
    free(user->pagamento);
    free(user->estado);
}

int dataValida(const char *data) {
    if (strlen(data) != 10) return 0; // Verifica o comprimento da string

    // Verifica se os caracteres nas posições corretas são barras ('/')
    return data[2] == '/' && data[5] == '/';
}

int contemArroba(const char *str) {
    return strchr(str, '@') != NULL; // Retorna 1 se contém '@', senão retorna 0
}

int paisValido(const char* country) {
    return (strcmp(country, "PT") == 0); // Retorna 1 se o país for "PT", caso contrário 0
}

//  while (!feof(file))
User** organizaUser(FILE *file, int* n_user_out){
    char *linha = NULL;
    size_t tamanho = 0;
    ssize_t valido;

    int linhas = 0;
    User **users = NULL;
    int n_user = 0;

    while ((valido = getline(&linha, &tamanho, file)) != -1) {

        if(linhas == 0) {
            linhas++;
            continue;
        }
        //  user = realloc(users, (n_user + 1) * sizeof(User));

        char *token = strtok(linha, ";");
        if (token == NULL) continue;

        User *newUser = malloc(sizeof(User)); // Aloca memória para um novo User
        if (newUser == NULL) {
            // Tratar erro de alocação
            break;
        }
        *newUser = (User){0};
        newUser->id = strdup(token);
        
        token = strtok(NULL, ";");

        if (token == NULL) {
            free(newUser->id);
            continue;
        }

        newUser->nome = strdup(token);

        token = strtok(NULL, ";");
        if (token == NULL) {
            free(newUser->id);
            free(newUser->nome);
            continue;
        }

        newUser->email = strdup(token);

        token = strtok(NULL, ";");
        if (token == NULL || !contemArroba(newUser->email)) {
            freeUser(newUser);
            free(newUser);
            continue;
        }

        newUser->tele = strdup(token);

        token = strtok(NULL, ";");
        if (token == NULL|| !dataValida(token) ) {
            freeUser(newUser);
            free(newUser);
            continue;
        }

        newUser->data = strdup(token);

        token = strtok(NULL, ";");
        if (token == NULL) {
            freeUser(newUser);
            free(newUser);
            continue;
        }
        newUser->sexo = token[0];

        token = strtok(NULL, ";");
        if (token == NULL) {
            freeUser(newUser);
            free(newUser);
            continue;
        }
        newUser->passaporte = strdup(token);

        token = strtok(NULL, ";");
        if (token == NULL) {
            freeUser(newUser);
            free(newUser);
            continue;
        }
        newUser->pais = strdup(token);

        token = strtok(NULL, ";");
        if (token == NULL || !paisValido(newUser->pais)) {
            freeUser(newUser);
            free(newUser);
            continue;
        }
        newUser->morada = strdup(token);

        token = strtok(NULL, ";");
        if (token == NULL) {
            freeUser(newUser);
            free(newUser);
            continue;
        }    
        newUser->cria_conta = strdup(token);

        token = strtok(NULL, ";");
        if (token == NULL) {
            freeUser(newUser);
            free(newUser);
            continue;
        }   
        newUser->pagamento = strdup(token);

        token = strtok(NULL, ";");
        if (token == NULL ) {
            freeUser(newUser);
            free(newUser);
            continue;
        }            
        newUser->estado = strdup(token);

  
        User **temp = realloc(users, (n_user + 1) * sizeof(User*));
        if (temp == NULL) {
            // Se realloc falhar, libere os recursos alocados e retorne
            // Aqui você deve liberar os campos de newUser que já foram alocados
            freeUser(newUser);
            free(newUser);
            break;
        }
        users = temp;
        // Prosseguir com a atribuição dos demais campos de newUser (nome, email, data, sexo, passaporte, pais, morada, cria_conta, pagamento, status)
        users[n_user] = newUser;

        if (n_user == 11) {
            printf("Usuer 12 (estado): %s\n", newUser->estado);
        }


        n_user++;
        linhas++;

        *n_user_out = n_user;
    }

    free(linha); // Liberar a memória alocada pela getline

    return users; // Retorna o ponteiro para o array de User
} 

int main(void) {

    FILE *file = fopen("/home/rafaelsilva/Projeto/dataset/data/users.csv", "r");

    if (file == NULL) {
        printf("Couldn't open the file.\n");
        return 1;
    } else {
        printf("File opened with sucess.\n");
    }

    int num_users;

    User **users = organizaUser(file, &num_users);

    fclose(file);
    printf("Parsing Concluded.\n");

    printf("The id of the user 9301 : %s\n", users[9300]->id);    

    for (int i = 0; i < num_users; i++) {
        freeUser(users[i]);
        free(users[i]);
    }
    free(users);

    return 0;    
}
c 解析 分段故障

评论

0赞 Retired Ninja 11/15/2023
我的建议是在调试器中运行代码,当它崩溃时,检查调用堆栈和变量以找出原因。
0赞 TheNomad 11/15/2023
调试后你发现了什么?
0赞 HelpMe 11/15/2023
@TheNomad如何调试它?
0赞 HelpMe 11/15/2023
@RetiredNinja如何调试它?
1赞 Barmar 11/15/2023
或者只是学习使用调试器。调用后在块中放置一个断点。然后你可以打印看看它是什么。ifdataValida()token

答:

1赞 Allan Wind 11/15/2023 #1
  1. 您的程序在行上出现段错误:

    printf("The id of the user 9301 : %s\n", users[9300]->id);    
    

    这是因为为 NULL。 为 NULL,因为返回日期为 0,例如,这与预期的格式不匹配。您可以使用以下方法解决此问题:usersusersdataValida()1979/11/27data[2] == '/' && data[5] == '/';

    int dataValida(const char *data) {
        if (strlen(data) != 10) return 0;
        return data[4] == '/' && data[7] == '/';
    }
    
  2. 在此更改之后,程序在同一位置出现段错误,但现在是因为示例输入文件包含 11 条记录,并且您尝试越界访问数组 (9300 > 10)。如果我将 print 语句更改为:

     printf("The id of the user 9301 : %s\n", users[num_users-1]->id);    
    

    它现在可以正确打印出最后一条记录的 ID。

  3. 奖励:您可以通过添加以下内容来修复内存泄漏:free(user->tele)freeUser()

    void freeUser(User *user) {
        free(user->id);
        free(user->nome);
        free(user->email);
        free(user->data);
        free(user->passaporte);
        free(user->pais);
        free(user->morada);
        free(user->cria_conta);
        free(user->pagamento);
        free(user->estado);
        free(user->tele);
    }
    

评论

0赞 HelpMe 11/16/2023
谢谢艾伦!它真的帮助了我很多:)
0赞 Allan Wind 11/16/2023
别客气。如果这回答了您的问题,请单击它旁边的复选标记来接受它。