[C] Allocation dynamique chaîne caractère, sprintf() et chaîne vide

Chaîne dynamiquement allouée vide

L’auteur de ce sujet a trouvé une solution à son problème.
Auteur du sujet

Bonsoir,

Après avoir relu différentes parties du cours C de ZdS et effectué quelques recherches, je ne trouve pas la soultion à mon problème.

J’ai fait un petit gestionnaire d’erreurs qui intègre une allocation dynamique d’une chaine de caractères. Une fonction est chargée de cela, une autre fonction qui gère l’affichage verra sa variable assignée du retour de la fonction allouante.

L’allocation dynamique se passe correctement, sa libération de même, aucun segfault, aucune erreur et aucun warning de la part de GCC, ni même de la part de GDB (Pas utilisé Valgrind pour voir une fuite :-° )

Seulement, lorsque la fonction d’affichage de l’erreur rentre dans la danse, elle affiche une chaîne vide o_O Cette chaîne dynamiquement allouée passe par argument dans un sprintf() ou il y est copié une autre chaîne de caractère.

Voici le code:

errorsHandler.c (Le header ne contient que des prototypes et une enum)

/*
    SHADOW MAN - SOURCE CODE
    
    AUTHOR: P4RADOX
    BEGIN DATE: 12/17/2018
    LICENSE: GNU GPLv3
    FILE: errorsHandler.c
*/

#include "errorsHandler.h"

char* allocateMsg()
{
    char* msg = NULL;

    msg = malloc(sizeof(char) * 0x200);

    if(msg == NULL)
        return NULL;
    else
        return msg;
}

void freeMsg(char* msgText)
{
    free(msgText);
}

void displayError(enum errorType errType)
{
    char* errorMsg = allocateMsg();

    if(errorMsg == NULL)
        fprintf(stderr, "[MEMORY]\terrorsHandler message allocation failed !\n");
    else
    {
        sprintf(errorMsg, SDL_GetError()); /* 
                                                    Refers to the first SDL error encountered in case of fallback to avoid only SDL MessageBox display error
                                                    occured after what interest us due to SDL last error handling system.
                                                 */

        /* 
            Enum will determinate which error type is: SDL for SDL2 troubleshooting or GAME for game troubleshooting like bas image path.
            SDL MessageBox will fail if it can't display itself, so we're displaying instead errors in stderr (Fallback)
         */

        switch(errType)
        {
            case SDL:
                if(SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Shadow Man - SDL Error", errorMsg, NULL) < 0)
                {
                    fprintf(stderr, "[SDL]\tCan\'t display messagebox: %s\n", SDL_GetError());
                    fprintf(stderr, "[SDL]\t%s\n", errorMsg);
                }

                break;

            case GAME:
                if(SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Shadow Man - Game Error", errorMsg, NULL) < 0)
                {
                    fprintf(stderr, "[SDL]\tCan\'t display messagebox: %s\n", SDL_GetError());
                    fprintf(stderr, "[GAME]\t%s\n", errorMsg);
                }

                break;

            default:
                break;
        }

        freeMsg(errorMsg);
    }
}

Merci d’avance ! (Moi, je vais bercer mon cerveau au lit car il commence à penser à des solutions farfelues et pas propres…)

Cette réponse a aidé l’auteur du sujet

Une manière propre de recoder la première fonction est simplement :

char* allocateMsg(void)
{
    return malloc(sizeof(char) * 512);
}

Sinon, pour ton problème, essaye ceci :

        sprintf(errorMsg, "Error : [%s]", SDL_GetError());

C’est un peu plus propre car on utilise le format "%s". En même temps, on vérifie que SDL_GetError retourne bien une valeur valide. Ici, j’ai surtout l’impression que cette fonction retourne une chaine vide.


J’ai fais un petit code d’exemple :

#include <stdlib.h>
#include <stdio.h>
#include <SDL2/SDL.h>

enum errType_e {
    SDL, GAME
};

char* allocateMsg(void) {
    return malloc(512);
}

void freeMsg(char* msgText) {
    free(msgText);
}
void handleError(void) {
    char* errorMsg = allocateMsg();

    if(errorMsg == NULL)
        fprintf(stderr, "[MEMORY]\terrorsHandler message allocation failed !\n");
    else
    {
        sprintf(errorMsg, SDL_GetError()); /* 
                                              Refers to the first SDL error encountered in case of fallback to avoid only SDL MessageBox display error
                                              occured after what interest us due to SDL last error handling system.
                                              */

        /* 
           Enum will determinate which error type is: SDL for SDL2 troubleshooting or GAME for game troubleshooting like bas image path.
           SDL MessageBox will fail if it can't display itself, so we're displaying instead errors in stderr (Fallback)
           */

        int errType = 11;

        if(SDL_ShowSimpleMessageBox(SDL_MESSAGEBOX_ERROR, "Shadow Man - SDL Error", errorMsg, NULL) < 0)
        {
            fprintf(stderr, "[SDL]\tCan\'t display messagebox: %s\n", SDL_GetError());
            switch(errType) {
                case SDL:
                    fprintf(stderr, "[SDL]\t%s\n", errorMsg);
                break;
                case GAME:
                    fprintf(stderr, "[GAME]\t%s\n", errorMsg);
                break;
                default:
                    fprintf(stderr, "[OTHER]\t%s\n", errorMsg);
                break;
            }
        }

        freeMsg(errorMsg);
    }
}

int main(void) {
    if (SDL_Init(SDL_INIT_EVERYTHING) != 0) {
        handleError();
        return 1;
    }

    SDL_SetError("The cake is a lie");
    handleError();

    return EXIT_SUCCESS;
}

Ça marche bien, donc je pense que le problème vient d’ailleurs.

ache.one                 🦹         👾                                🦊

+2 -0
Auteur du sujet

Bonsoir,

Merci à toi, j’aime beaucoup ta façon de programmer, en effet retourner directement l’allocation est quelque chose que j’ai déjà fait dans d’autres programmes mais cela fait un moment que je n’ai plus codé (C’est pas comme le vélo, on oublie un peu tout lol)

J’ai trouvé d’où provient mon problème de chaîne de caractère : SDL_GetError() renvoie la dernière erreur survenue. Vu que l’initialisation se passe bien, il n’y a pas d’erreur avant celle du problème d’affichage de la messagebox. Que renvoie SDL_GetError() quand il n’y a pas d’erreurs ? QUE DALLE :euh: . Donc ma chaîne de caractère doit bel et bien être vide…

Ce qui s’est passé, c’est que j’ai intentionellement modifié la valeur de la condition pour que l’initialisation lève une erreur (SDL_Init < 1 au lieu de SDL_Init < 0, celle-ci renvoyant une valeur négative en cas de problème). Mais au final, il n’y a pas vraiment d’erreur, je simule une erreur pour tester mon gestionnaire personnel.

Je pense acheter un saumon de 15kg pour m’ouvrir la tête du coup là… :honte:

En tout cas, cela m’a permis de réfléchir et d’avoir encore une fois tes précieux conseils @ache

EDIT:

Juste deux petits points :

Un:

sprintf(errorMsg, "Error : [%s]", SDL_GetError());

Je suppose que la partie Error : [] va ajouter 10 caractères à la longueur de la chaîne contenant l’erreur puisque la fonction sprintf() écrit une chaîne source dans un buffer. Si jamais l’erreur fait exactement 502 caractères de long ou plus, cela provoque donc un buffer overflow ?

Deux:

De quoi pourrait venir le problème d’affichage de SDL_ShowSimpleMessageBox ? Car chez moi la MessageBox ne s’affiche pas et mon gestionnaire affiche donc No message system available. Je tourne sous Archlinux, environnement Deepin et de ce que j’ai consulté dans la doc SDL2, la librairie utilise X11 pour claquer ses MessageBox et non GTK+ ni Qt, sachant que Deepin tourne sous Qt. Je pense qu’il me manque un paquet quelque part.

Édité par p4radox

Vous devez être connecté pour pouvoir poster un message.
Connexion

Pas encore inscrit ?

Créez un compte en une minute pour profiter pleinement de toutes les fonctionnalités de Zeste de Savoir. Ici, tout est gratuit et sans publicité.
Créer un compte