IdentifiantMot de passe
Loading...
Mot de passe oublié ?Je m'inscris ! (gratuit)
Navigation

Inscrivez-vous gratuitement
pour pouvoir participer, suivre les réponses en temps réel, voter pour les messages, poser vos propres questions et recevoir la newsletter

C Discussion :

Retourner un string depuis une fonction en C


Sujet :

C

  1. #1
    Invité de passage
    Femme Profil pro
    Recherche scientifique
    Inscrit en
    Avril 2020
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Dordogne (Aquitaine)

    Informations professionnelles :
    Activité : Recherche scientifique
    Secteur : Industrie Pharmaceutique

    Informations forums :
    Inscription : Avril 2020
    Messages : 11
    Par défaut Retourner un string depuis une fonction en C
    Hello,

    Je suis programmeuse, plutôt anglophone ( oui je ne suis pas parfaite ) en C, j'ai des notions de base.
    J'ai quelques soucis avec le "return" d'un string ou d'un tableau depuis une function.
    Pour donner un exemple, je tente de simuler en C la function MID$ du basic.
    Pour remémorer, on a:

    Code BASIC : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
       string_2$ = MID$( string_1$, start% [, NBytes% ] )        function  .BASIC
       MID$( string_1$, start% [, NBytes% ] ) = string_2$        statement .BASIC

    Je laisse de côté la variante "statement" qui ne m'intéresse pas.
    Si j'utilise ( sans options ):

    Code C : Sélectionner tout - Visualiser dans une fenêtre à part
    void MID( const char * string_1, char * string_2, int start, int NBytes );

    Je récupère le résultat string_2 extrait du string_1.
    Pas de souci. Cela me semble propre.
    Si je veux copier le style MID$, cela se complique...
    Un exemple ( retourne le jour de la semaine ):

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    #include <ctype.h>
     
    void MID( const char * string_1, char * string_2, int start, int NBytes )
    /* char * MID( const char * string_1, int start, int NBytes ) */ {  /* => string_2 */
        int k = 0, l = 0;
        for( k = start; k < (start + NBytes); k++ )
        {
            string_2[l] = string_1[k ];
            l++;
        }
           string_2[l] = '\0';
    }
     
    int main()
    {
       char buf[64] = "SUNMONTUEWEDTHUFRISAT";
       char buf2[64] = ".....................";
       int i;
       for ( i = 0; i < 7; i++ ) {
          MID( buf, buf2, 3 * i, 3);
          printf( "%i => %s\n", i, buf2 );
       }
       return 0;
    }
    Pour le moment, pas de problème.
    Mais si je veux utiliser la fonction en tant que:


    avec un


    cela cafouille.

    Pas très étonnée, string_2 est un... string ! pas une variable.
    Mais si je veux mettre un


    cela fonctionne mais ce n'est pas le string_2 voulu !
    Un pointer... Pas trouvé comment faire ( si c'est possible ). À moins d'utiliser des string en global mais pas joli !
    Pourquoi cela fonctionne avec un string explicite et pas la variable correspondant au string ?
    La méthode bourrin utilisant getc et transférer lettre par lettre... Pas chaude du tout ( et vu la canicule... ).
    Bien sûr, je peux renoncer à la forme "function", mais j'aime comprendre.

    Mon but est d'aller plus loin dans l'exploitation de MID pour traiter des 1000-3000 lignes de données en ASCII dans un file séparé combinant diverses sortes de valeurs, int, double, char. De coder en préliminaire les doubles du fichier source en 8 bytes IEEE à décoder ensuite en double en lecture.

    Merci pour vos idées.

  2. #2
    Expert confirmé
    Homme Profil pro
    Responsable Données
    Inscrit en
    Janvier 2009
    Messages
    5 557
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 52
    Localisation : France, Hérault (Languedoc Roussillon)

    Informations professionnelles :
    Activité : Responsable Données

    Informations forums :
    Inscription : Janvier 2009
    Messages : 5 557
    Par défaut
    Bonjour,
    Il y a (très) longtemps que je n'ai pas fait de C, donc je vais peut-être sortir une annerie.
    Si ta fonction doit renvoyer une chaîne, il ne faut pas mettre CONST dans sa déclaration :
    Avec CONST et un return "ABCDEF" ça fonctionne puisque ici tu renvoies une constante.

    Mettre un CONST n'est d'ailleurs pas très logique pour une fonction qui renvoie une valeur "calculée", donc tout sauf une constante.

    Tatayo.

  3. #3
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 841
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 841
    Par défaut
    Il faut utiliser malloc pour allouer sur le tas 1 chaîne de caractères (et ne pas oublier la désallocation avec free )
    Lorsque tu quittes 1 fonction (qui est 1 bloc { /* ... */ } toutes les variables locales sont détruites.


    Voici du code:
    • tu as les 3 façons de faire : MID copie directement, MID_1 retourne 1 chaîne de caractères, MID_2 crée et retourne dans 1 paramètre sortie.
    • mon code n'est sûrement pas très propre, mais c'est l'idée
    • je préfère utiliser des unsigned char pour les chaînes de caractères mais toute la bibliothèque standard utilise des char. Et en C il n'y a pas de booléen (0 c'est faux, le reste est vrai) : donc soit 1 char soit 1 unsigned char (que j'utilise)
    • en C, il faut toujours avoir la taille d'une chaîne en même temps que la chaîne (tu peux englober tout cela avec 1 structure struct)


    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    56
    57
    58
    59
    60
    61
    62
    63
    64
    65
    66
    67
    68
    69
    70
    71
    72
    73
    74
    75
    76
    77
    78
    79
    80
    81
    82
    83
    84
    85
    86
    87
    88
    89
    90
    91
    92
    93
    94
    95
    96
    97
    98
    99
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    unsigned char MID(const /*unsigned*/ char* str, /*unsigned*/ char* copy, size_t str_len, size_t start, size_t NBytes) {
        unsigned char ret;
     
        if ((str != NULL) && (copy != NULL) && (start < str_len) && ((start + NBytes + 1) < str_len)) {
    //      strncpy(copy, (str + start), NBytes /* * sizeof(char)*/);
            memcpy(copy, (str + start), NBytes /* * sizeof(char)*/);
            copy[NBytes] = '\0';
     
            ret = 1;
        } else {
            ret = 0;
        }
     
        return ret;
    }
     
     
    /*unsigned*/char* MID_1(const /*unsigned*/ char* str, size_t str_len, size_t start, size_t NBytes) {
        char* ret;
     
        if ((str != NULL) && (start < str_len) && ((start + NBytes + 1) < str_len)) {
            ret = malloc((NBytes + 1) * sizeof(char));
     
            if (ret != NULL) {
                strncpy(ret, (str + start), NBytes /* * sizeof(char)*/);
    //          memcpy(ret, (str + start), NBytes /* * sizeof(char)*/);
                ret[NBytes] = '\0';
            }
        } else {
            ret = NULL;
        }
     
        return ret;
    }
     
     
    unsigned char MID_2(const /*unsigned*/ char* str, /*unsigned*/ char** copy, size_t str_len, size_t start, size_t NBytes) {
        unsigned char ret;
     
        if ((str != NULL) && (copy != NULL) && (start < str_len) && ((start + NBytes + 1) < str_len)) {
            (*copy) = malloc((NBytes + 1) * sizeof(char));
     
            if (((*copy) != NULL)) {
    //          strncpy((*copy), (str + start), NBytes /* * sizeof(char)*/);
                memcpy((*copy), (str + start), NBytes /* * sizeof(char)*/);
                (*copy)[NBytes] = '\0';
     
                ret = 1;
            } else {
                ret = 0;
            }
        } else {
            ret = 0;
        }
     
        return ret;
    }
     
     
    int main(int argc, char* argv[])
    {
        /*unsigned*/ char  buf[64]  = "SUNMONTUEWEDTHUFRISAT\0";
        /*unsigned*/ char  buf1[64] = ".....................\0";
        /*unsigned*/ char* buf2     = NULL;
     
        if ( MID(buf, buf1, 64, 6, 3) ) {
            printf("1) %3s\n", buf1);
        } else {
            printf("1) problem\n");
        }
     
        if ( MID(buf, buf1, 64, 9, 60) ) {
            printf("2) %3s\n", buf1);
        } else {
            printf("2) problem\n");
        }
     
        buf2 = MID_1(buf, 64, 9, 9);
     
        if (buf2 != NULL) {
            printf("3) %3s\n", buf2);
            free(buf2);
        } else {
            printf("3) problem\n");
        }
     
        if ( MID_2(buf, &buf2, 64, 12, 3) ) {
            printf("4) %3s\n", buf2);
            free(buf2);
        } else {
            printf("4) problem\n");
        }
     
        return EXIT_SUCCESS;
    }

  4. #4
    Membre prolifique Avatar de Artemus24
    Homme Profil pro
    Agent secret au service du président Ulysses S. Grant !
    Inscrit en
    Février 2011
    Messages
    7 533
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Paris (Île de France)

    Informations professionnelles :
    Activité : Agent secret au service du président Ulysses S. Grant !
    Secteur : Finance

    Informations forums :
    Inscription : Février 2011
    Messages : 7 533
    Par défaut
    Salut à tous.

    @ Tatayo : CONST sert uniquement à rendre la variable non modifiable.
    Dans le cas d'un tableau, cela ne sert strictement à rien. Autant ne pas l'utiliser dans ce contexte.

    Citation Envoyé par Fluorine
    Pour donner un exemple, je tente de simuler en C la function MID$ du basic.
    De quel BASIC parles tu ?

    Je suppose que la fonction MID$ extrait une sous-chaîne de caractères à partir d'une chaîne de caractères. Exemple :
    Code basic : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    A$ = "BONJOUR"
    B$ = MID$(A$, 4, 3)
    Dans B$ tu récupères "JOU". C'est juste un rappel de la fonction basic "MID()".

    Allouer de la mémoire pour retourner la valeur de la fonction est correcte.
    Mais elle a l'inconvénient qu'il faut la libérer ensuite, après l'avoir utilisé, ce qui alourdit la gestion de ton traitement.
    Et cela peut être sujet à des erreurs, ou à l'usage trop important de l'allocation de mémoire.
    Donc oui l'idée de Foetus est correcte mais je ne la préconise pas du tout.

    I) Voici la solution de Foetus :

    Soit ce que nous voulons tester :
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    int main(void)
    {
    	char buf[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    	char *p = MID(buf, 6, 3);
    	printf("%s\n", p);
    	free(p);
    	return 0;
    La fonction MID doit être de ce genre :
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    #include <stdlib.h>
    #include <string.h>
     
    char *MID(const char *src, int start, int len)
    {
    	char *dst = malloc(len + 1);
     
    	if (!dst)
    		return NULL;
     
    	memcpy(dst, src + start, len);
    	dst[len] = '\0';
    	return dst;
    }

    II) Solution avec allocation static :

    Au lieu d'un malloc, on utilise ici un "static char".
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    char *MID(const char *src, int start, int len)
    {
    	static char dst[256];
    
    	memcpy(dst, src + start, len);
    	dst[len] = '\0';
    
    	return dst;
    }
    Cela évite de faire à chaque fois une allocation mémoire, puis ensuite de la llibérer après l'appel de la fonction "MID()".
    L'inconvénient est qu'un second apppel de la fonction "MID()" écrase le résultat du premier appel.

    III) Ce que je préconise :

    Allouer la variable "dst" dans la section appelante.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    int main(void)
    {
    	char buf[] = "ABCDEFGHIJKLMNOPQRSTUVWXYZ";
    	char dst[256];
    
    	printf("%s\n", MID(buf, 6, 3, dst));
    	return 0;
    Cela oblige de modifier légèrement la fonction "MID()" en introduisant en tant que paramètre la variable "DST".
    Code c : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    {include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
    
    char *MID(const char *src, int start, int len, char *dst)
    {
    	memcpy(dst, src + start, len);
    	dst[len] = '\0';
    	return dst;
    }

    Il n'y a pas de solution propre pouvant simuler exactement la fonction basic "MID()".

  5. #5
    Membre Expert
    Avatar de edgarjacobs
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2011
    Messages
    850
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 66
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2011
    Messages : 850
    Par défaut
    Hello,

    En reprenant ton code, cela fonctionne parfaitement avec une fonction qui retourne un char * :
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    char *mid(const char *string_1, char *string_2, int start, int nbytes) {
    	int l=0;
    	for(int k=start; k<start+nbytes; k++)	{
    		string_2[l]=string_1[k];
    		l++;
    	}
    	string_2[l]='\0';
     
    	return(string_2);
    }
     
    int main(void) {
    	char buf[64]="SUNMONTUEWEDTHUFRISAT";
    	char buf2[64];
    	for(int i=0; i<7; i++)
    		printf("%i => %s\n", i, mid(buf, buf2, 3*i, 3));
     
    	return 0;
    }
    On écrit "J'ai tort" ; "tord" est la conjugaison du verbre "tordre" à la 3ème personne de l'indicatif présent ;)

  6. #6
    Invité de passage
    Femme Profil pro
    Recherche scientifique
    Inscrit en
    Avril 2020
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Dordogne (Aquitaine)

    Informations professionnelles :
    Activité : Recherche scientifique
    Secteur : Industrie Pharmaceutique

    Informations forums :
    Inscription : Avril 2020
    Messages : 11
    Par défaut Mes essais
    Hello,

    Merci à tous pour toutes ces infos très intéressantes.
    Je vois que finalement mon "petit" problème n'est pas simple.

    "Quel BASIC" ?
    Divers BASIC, tel que ceux de Microsoft : QB du MSDOS, QB 4.5 et... QB64.
    Je crois que c'est la même chose.
    Dans Excel ? Pas testé.
    PureBasic : c'est proche avec MID au lieu de MID$.
    Je note que la difficulté c'est pour passer le résultat en tant que résultat de MID, donc en utilisant la gauche de MID.

    Les diverses méthodes jouent sur ce point épineux.
    On peut changer ma boucle for en memcpy, c'est plus élégant.
    Un piège si l'on ne prévoit pas de place pour les données.
    char buf[256] = ".............."; j'ai mis au pif un remplissage pour initialiser.
    ou
    malloc
    servent beaucoup à cela.

    J'aime beaucoup la méthode élégant d'Artemus24 utilisant dst en plus.

    La méthode edgarjacobs...
    J'ai cherché un moment alors que cela ne fonctionnait pas avec moi.
    Le problème :
    Cela utilise un paramètre que l'on saute facilement:
    char *mid(const char *string_1, char *string_2, int start, int nbytes)
    On ne sait plus si le retour se fait en tant que fonction ( par le "char *" de tête ) ou en tant que sub
    Le :
    return string_2;
    n'a aucune action et peut être supprimé.
    Dommage, cela eusse été une solution confortable.
    On retombe ainsi sur ma première version, en supprimant le "return" inutile et le "char *"

    J'ai surtout deux solution qui me plaisent :
    - celle que j'ai au tout débu en mode SUB.
    - celle ajoutant le dst en mode fonction..

    Mon but est de réutiliser mes nombreux programmes en BASIC, dont j'ai conservé les sources.
    Des code source avec de nombreuses lignes de calcul... Mais rien de complexe la plupart du temps.
    Pour ne pas tout rectifier à la main, je lance une AI pour me traduire en robot le trivial, travail de fourmi.
    J'ai un peu honte demander cela à une AI alors que l'intelligence n'est guère sollicitée. Le marteau pour écrase un moucheron.

    Je pourrais passer en C++ ou autres plus évolués, mais je préfère garder un code simple qui puisse être facilement traduits dans d'autres langages sans avoir à se prendre la tête sur des subtilités. Tout cela afin que mes programmes ne finissent pas dans l'oubli étant inutilisables. Cela a failli être le cas pour mes programmes en BASIC, j'ai eu la bonne idée de garder mes sources. J'en ai aussi en C, au temps de MSDOS ( 16 bits... ). Le temps des diskettes...

    Merci à tous.

  7. #7
    Membre Expert
    Avatar de edgarjacobs
    Homme Profil pro
    Développeur informatique
    Inscrit en
    Mai 2011
    Messages
    850
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Âge : 66
    Localisation : Belgique

    Informations professionnelles :
    Activité : Développeur informatique

    Informations forums :
    Inscription : Mai 2011
    Messages : 850
    Par défaut
    Cela utilise un paramètre que l'on saute facilement:
    char *mid(const char *string_1, char *string_2, int start, int nbytes)
    Dans ce cas, le compilateur t'aurait averti du problème. Sans doute par une warning, et il faut toujours régler toutes les warnings d'un programme (à moins de savoir ce que l'on fait). Et si le compilateur n'a rien dit, c'est que les options de compilation -Wall et -Wextra ne sont pas présentes. Il faut toujours les activer pour avoir un maximum de messages lors de la compilation.
    On écrit "J'ai tort" ; "tord" est la conjugaison du verbre "tordre" à la 3ème personne de l'indicatif présent ;)

  8. #8
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 841
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 841
    Par défaut
    Citation Envoyé par Fluorine Voir le message
    La méthode edgarjacobs... […] Cela utilise un paramètre que l'on saute facilement
    C'est 1 truc classique en retournant le "pointeur résultat" cela permet de chaîner les fonctions (mais tu peux aussi ignorer le retour)

    En gros ici cela permet de faire 1 truc mid(mid(str, copy, 3, 12), copy2, 5, 7); (<- attention il faut sûrement que la fonction mid puisse travailler même si la source et la destination sont la même chaîne)

    1 truc classique parce la bibliothèque le fait Par exemple, memcpy retourne l'adresse du bloc de mémoire de destination, strncpy retourne l'adresse de la chaîne dupliquée


    Citation Envoyé par Fluorine Voir le message
    Je pourrais passer en C++ ou autres plus évolués, mais je préfère garder un code simple qui puisse être facilement traduits dans d'autres langages sans avoir à se prendre la tête sur des subtilités
    Que ce soit le C ou le C++, 1 "code simple facile traduisible sans se prendre la tête sur des subtilités" : tu as mal choisis tes langages Mais apparemment pour toi le C, c'est simple
    Surtout lorsqu'on parle de code simple pour 1 code qui manipule les chaînes de caractères le C n'a aucun type "chaîne de caractères", il ne gère que l'ASCII avec des tableaux d'entiers signés … et comme c'est du C il faut allouer/ désallouer les tableaux (à moins d'utiliser des tableaux statiques ou des buffers créés 1 seule fois)

    Après pour la gestion de l'UTF-16 il y a le type wchar_t et la bibliothèque wchar.h (<- lien cplusplus.com en anglais. Attention c'est 1 site pour le C et le C++: wchar.h c'est le C, cwchar c'est le C++. En C++, les entêtes C perdent l'extension .h et sont préfixés d'un c)
    Mais je ne sais pas si beaucoup de développeurs l'utilisent

    Je préfère utiliser les std::string en C++ qui permettent de créer de rien et de manipuler facilement les chaînes de caractères … mais cela reste de l'ASCII
    Le C++ moderne ajoute des types pour manipuler l'Unicode mais je ne sais pas si c'est "efficace"/ pratique et beaucoup utilisé.

  9. #9
    Invité de passage
    Femme Profil pro
    Recherche scientifique
    Inscrit en
    Avril 2020
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Dordogne (Aquitaine)

    Informations professionnelles :
    Activité : Recherche scientifique
    Secteur : Industrie Pharmaceutique

    Informations forums :
    Inscription : Avril 2020
    Messages : 11
    Par défaut
    Citation Envoyé par edgarjacobs Voir le message
    Dans ce cas, le compilateur t'aurait averti du problème. Sans doute par une warning, et il faut toujours régler toutes les warnings d'un programme (à moins de savoir ce que l'on fait). Et si le compilateur n'a rien dit, c'est que les options de compilation -Wall et -Wextra ne sont pas présentes. Il faut toujours les activer pour avoir un maximum de messages lors de la compilation.
    Oui. À condition de le lire... Un warning à décrypter qui n'est pas évident non plus.
    J'ai compris finalement où était le problème du warning.
    J'utilise Code::Block avec gnu options par défaut en mode debug.

  10. #10
    Invité de passage
    Femme Profil pro
    Recherche scientifique
    Inscrit en
    Avril 2020
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Dordogne (Aquitaine)

    Informations professionnelles :
    Activité : Recherche scientifique
    Secteur : Industrie Pharmaceutique

    Informations forums :
    Inscription : Avril 2020
    Messages : 11
    Par défaut
    Citation Envoyé par foetus Voir le message
    C'est 1 truc classique en retournant le "pointeur résultat" cela permet de chaîner les fonctions (mais tu peux aussi ignorer le retour)
    ...
    Que ce soit le C ou le C++, 1 "code simple facile traduisible sans se prendre la tête sur des subtilités" : tu as mal choisis tes langages Mais apparemment pour toi le C, c'est simple
    Surtout lorsqu'on parle de code simple pour 1 code qui manipule les chaînes de caractères le C n'a aucun type "chaîne de caractères", il ne gère que l'ASCII avec des tableaux d'entiers signés … et comme c'est du C il faut allouer/ désallouer les tableaux (à moins d'utiliser des tableaux statiques ou des buffers créés 1 seule fois)
    ...
    Je préfère utiliser les std::string en C++ qui permettent de créer de rien et de manipuler facilement les chaînes de caractères … mais cela reste de l'ASCII
    Le C++ moderne ajoute des types pour manipuler l'Unicode mais je ne sais pas si c'est "efficace"/ pratique et beaucoup utilisé.
    Je n'ai pas l'intention d'utiliser des complications telles que mid(mid(str, copy, 3, 12), copy2, 5, 7); et autres imbrications.

    Coder "simple" en C...
    Le C "simple" oui, c'est un rêve vu certains codes... Je veux surtout limiter dans ces cas MES acrobaties pour rester claire.
    Mon but est de réécrire en C des programmes anciens dont j'ai les codes sources en BASIC.

    "Mais apparemment pour toi le C, c'est simple"...
    J'ai envisagé traduire en Python. Cela ne me séduit pas. Je ne vois pas quel autre langage pour du "simple" dans mes connaissances.
    J'ai illustré avec un exemple fonctionnel de sub.
    Ce sont des programmes très mathématiques avec très peu de traitement ASCII, utilisés surtout pour les dialogues utilisateurs.
    Tenir compte des terminaisons de lignes '\0D' + '\0A' ou seul '\0A\' en plus d'une traduction.

    Mon intérêt était surtout théorique cherchant des alternatives pour contourner les difficultés de retourner un string depuis une fonction.
    Cela m'est venu lors de telles manipulations et j'ai voulu approfondir bien que j'eusse une solution par un "sub":
    Depuis un sub, cela repart en retour depuis les paramètres fournis, avec un pointeur.
    C'est ce que je fais. Veiller au '\00' terminal de string...
    Je ne prévois pas de vérifier le non dépassement dans les longueurs de string et autres contrôles. Ce sera au code appelant d'éviter le hors pistes.
    Je vois que d'utiliser un retour de fonction d'un string pose beaucoup de problèmes... J'ai ainsi diverses techniques.
    Même memcpy renvoie une adresse, mais cela ne retourne pas le string pour autant.
    Mon code C est une sorte de code C mais restant volontairement un "C basique" pour autrui.
    Je n'exclus pas d'utiliser du code C++, j'aime aussi.

    Pour mes sources en assembleur ou en UBASIC multiprécision, difficile de traduire en C.
    Je pourrais rester en BASIC, mais trop de variantes. PureBasic n'a pas la même syntaxe et les autres de même.
    QB64 n'est pas mauvais mais uniquement pour un .exe en 64 bits des anciennes sources QB.
    Probable de revoir mes anciennes sources en "vieux" C, des far malloc c'est très nostalgique...

    C'est lors de problèmes que l'on apprend... à condition de ne pas rester sur un échec et d'approfondir.
    J'ai beaucoup aimé vos messages très instructifs.

  11. #11
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 954
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 4 954
    Par défaut
    Hello,

    Je n'ai pas tout regardé mais votre premier code était à mon sens la meilleure pratique... J'ai pas tout lu, peut-être a-t-il déjà été proposé.

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
    40
    41
    42
    43
    44
    45
    46
    47
    48
    49
    50
    51
    52
    53
    54
    55
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    #define MID_B(src, start, len) (MID)(src, (char[256]){0}, start, len)
     
    char* MID(const char * string_1, char * string_2, int start, int NBytes);
     
    char* MID(const char * string_1, char * string_2, int start, int NBytes) {
        if (string_1 == NULL || string_2 == NULL || start < 0 || NBytes <= 0) {
            if (string_2 != NULL) string_2[0] = '\0';
            return string_2;
        }
     
        int len = (int)strlen(string_1);
        if (start >= len) {
            string_2[0] = '\0';
            return string_2;
        }
     
        int k = start;
        int l = 0;
     
        for( ; k < len && k < (start + NBytes); k++ ) {
            string_2[l++] = string_1[k];
        }
     
        string_2[l] = '\0';
        return string_2;
    }
     
    int main() {
        const char* dataset[] = {
            "1082-THOMAS    -00468.52-DEL",
            "5567-MARTIN    -00746.16-INJ",
            "2438-DURAND    -00213.65-INJ",
            "4235-RICHARD   -00245.00-DEL",
            "8626-MARTIN    -00387.83-ACT"
        };
        int num_lines = 5;
     
        for(int i = 0; i < num_lines; i++) {
            const char* line = dataset[i];
     
            int id = atoi(MID_B(line, 0, 4)); 
            const char* nom = MID_B(line, 5, 10);
            double prix = atof(MID_B(line, 16, 8));
            const char* statut = MID_B(line, 25, 3);
     
            printf("Record extrait -> ID: %d | Nom: %s | Prix: %8.2f € | Statut: %s\n", 
                   id, nom, prix, statut);
        }
     
        return 0;
    }
    Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
    La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

  12. #12
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 841
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 841
    Par défaut
    Citation Envoyé par fred1599 Voir le message
    Je n'ai pas tout regardé mais votre premier code était à mon sens la meilleure pratique... J'ai pas tout lu, peut-être a-t-il déjà été proposé.
    C'est la solution de @edgarjacobs

    Mais @Fluorine ne veut pas faire de tests et s'aperçoit que le retour "pointeur" n'est pas la philosophie du C

    Donc MID$ correspond à 1 appel à memcpy/ strncpy
    À la rigueur faire 1 define
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    #define MID(source, copy, start, NBytes) \
        memcpy(copy, (source + start), NBytes /* * sizeof(char) */); \
        copy[NBytes] = '\0';
     
    #define MID_defensif(source, copy, start, NBytes) \
        if ((source != NULL) && (copy != NULL) && (start > 0) && (NBytes > 0)) { \
            memcpy(copy, (source + start), NBytes /* * sizeof(char) */); \
            copy[NBytes] = '\0'; \
        }
    On ne met jamais le sizeof(char) parce qu'il vaudra toujours 1.
    Édit: fred1599 m'a dit que j'avais oublié le '\0' final

    Citation Envoyé par Fluorine Voir le message
    Même memcpy renvoie une adresse, mais cela ne retourne pas le string pour autant.
    La différence c'est que strncpy/ strcpy sont spécifiques "chaîne de caractères" et memcpy est + générique.
    Donc strncpy/ strcpy retourne 1 char * et memcpy 1 void *.
    D'ailleurs dans la documentation de memcpy on peut lire "contrairement à strcpy, aucun test sur une éventuelle valeur nulle n'est réalisé pour stopper la copie. Seule la taille du bloc sera considérée."

    Citation Envoyé par Fluorine Voir le message
    Cela ne me séduit pas. Je ne vois pas quel autre langage pour du "simple" dans mes connaissances.
    Je pense au Java … et encore j'ai fait du Java version 6 ou 8 et maintenant c'est à la version 25, donc peut-être 1 fausse bonne idée
    Mais le Java ressemble à du C et du C++ - c'est compilé, il y a des types, c'est objet
    Et contrairement au C/ C++:
    • tu as 1 grosse bibliothèque standard
    • si tu veux faire 1 application (tu parles de dialogues utilisateurs), il y a Java FX
    • si tu n'aimes pas trop le Java, tu peux appeler du code C avec la JNI. Mais c'est peut-être lent

  13. #13
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 954
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 4 954
    Par défaut
    Merci foetus pour votre retour et pour l'idée du memcpy !

    Cependant, utiliser memcpy directement pose un souci dans mon cas : la fonction n'ajoute pas le \0 de fin de chaîne, ce qui risque de générer des caractères parasites ou des plantages lors d'un printf ou d'un atoi. De plus, une macro contenant un if (comme votre MID_defensif) est une instruction et non une expression. Je ne peux donc pas l'imbriquer directement, par exemple dans un atoi(MID_defensif(...)).

    Mon objectif était vraiment d'avoir une syntaxe propre et "inline", sans devoir déclarer manuellement un char buffer[64] à chaque fois que je veux extraire une information.

    Comme certains l'ont suggéré plus haut, la solution idéale pour cela passe par les littéraux composés (Compound Literals) introduits en C99.

    Grâce à cette approche, le compilateur gère lui-même la durée de vie du buffer sur la pile à chaque appel de MID_B. C'est simple, robuste et très proche de la syntaxe d'origine que recherchait le PO je pense...

    EDIT : J'ai pu analyser le code de Edgarjacobs, et si je ne regarde pas la partie sécuritaire et vérification NULL, même s'il y a une ressemblance avec mon code proposé, si vous regardez son main, il est obligé de déclarer manuellement une variable intermédiaire : char buf2[64] et il doit la passer à chaque appel : mid(buf, buf2, ...), c'est exactement ce que l'on veut éviter ! Vous vouliez une syntaxe "inline" propre comme en BASIC. Grâce à ma macro MID_B et au littéral composé (char[256]){0}), vous vous passez totalement de cette étape fastidieuse.
    Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
    La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

  14. #14
    Invité de passage
    Femme Profil pro
    Recherche scientifique
    Inscrit en
    Avril 2020
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Dordogne (Aquitaine)

    Informations professionnelles :
    Activité : Recherche scientifique
    Secteur : Industrie Pharmaceutique

    Informations forums :
    Inscription : Avril 2020
    Messages : 11
    Par défaut
    Citation Envoyé par fred1599 Voir le message
    Hello,

    Je n'ai pas tout regardé mais votre premier code était à mon sens la meilleure pratique... J'ai pas tout lu, peut-être a-t-il déjà été proposé.
    ...
    Merci pour ces infos très détaillées.
    Je note au passage les tests pour ne pas dérailler, utiles surtout lorsque l'on programme par canicule ( dixit SNCF ).
    J'apprends toujours avec plaisir pour aller plus loin.
    Cela m'oblige à être stricte lors des appels.
    Mon exemple de mon premier message est une illustration.
    Je compte traiter des listes de string/chaînes telles que comportant des doubles sur 8 bytes/IEEE, des char pouvant êtres des petits +/- entiers, des textes courts.
    Mais à chaque fois des positions définies préalablement sur le string, donc chaque champ une longueur fixe stricte ( comme IEEE ), le tout sans séparateur.
    Ces string seront stockés dans des fichiers, avec des nombreux ( centaines ) de string de longueur fixe terminés par '\0D' + '\0A', ou '\0A' seul. Cela pour limiter l'encombrement du fichier et en mémoire.
    Mon exemple avec les 3 lettres des jours de la semaine en est un reflet. Cela n'irait pas avec les longueurs de noms complets variables.

    Je suis accessoirement une "matheuse", j'aime bien cela.
    J'ai une tendance à considérer les fonctions comme en maths : y = f( x1, x2, x3,...) sans qu'une valeurs ressorte du côté paramètres !!! Un peu de routine brisée... J'aime.
    Mes programmes sont axés maths, techniques de calcul. Je suis très exigeante sur la qualité de la méthode.

    Citation Envoyé par foetus Voir le message
    C'est la solution de @edgarjacobs

    Mais @Fluorine ne veut pas faire de tests et s'aperçoit que le retour "pointeur" n'est pas la philosophie du C

    Je pense au Java … et encore j'ai fait du Java version 6 ou 8 et maintenant c'est à la version 25, donc peut-être 1 fausse bonne idée
    Mais le Java ressemble à du C et du C++ - c'est compilé, il y a des types, c'est objet
    Et contrairement au C/ C++:
    • tu as 1 grosse bibliothèque standard
    • si tu veux faire 1 application (tu parles de dialogues utilisateurs), il y a Java FX
    • si tu n'aimes pas trop le Java, tu peux appeler du code C avec la JNI. Mais c'est peut-être lent
    Passer en Java est séduisant et je compte bien de le débuter.
    Les bibliothèques sont un + séduisant. Toutefois, prudence car j'ai déjà eu de mauvaises surprises telles que pertes de précision ou des acos(x), x = 1.0 + un petit epsilon d'arrondi. C'est le charme du tout prêt à l'emploi.
    Un exemple avec un ancien Excel. La fonction erf pour certaines valeurs d'argument n'a que 8 décimales correctes. Cela s'étend à d'autres fonctions utilisées en interne. J'ai fait un programme en C ( si cela intéresse...MP ) pour ce calcul et nombre de fonctions statistiques.

    J'aime le travail soigné. Les délais imposés, c'est non ! Vu la canicule, mes neurones sont en mode économique et c'est un peu plus long...
    Vu mon style de programmes, je préfère éviter les MID en substituant avec des macros à risques.
    Je pense que je vais utiliser la récupération du résultat par pointeur depuis les paramètres du sub.
    Ceux qui liront mes sources se débrouilleront...

    Finalement les variantes nécessitent un buf[256] pour faire atterrir le résultat quelque soit l'astuce utilisée; sans oublier le '\0' final, oubli classique moi aussi...
    Un buf[256] en variable globale, ce n'est pas à exclure finalement. Pas très élégant.

  15. #15
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 954
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 4 954
    Par défaut
    Votre vision mathématique y = f(x1, x2, x3) est justement la raison d'être de la solution que je vous ai proposée !

    En C classique, l'approche par pointeur oblige à écrire f(x1, y, x2, x3), où y est mélangé avec les paramètres d'entrée. C'est exactement ce problème que vient régler l'astuce du "littéral composé" : en laissant le compilateur gérer lui-même le buffer en arrière-plan, cela vous permet de retrouver une vraie fonction pure. On écrit tout simplement y = MID(x1, x2, x3) et le tour est joué.

    Cependant, puisque vous êtes très exigeante sur la qualité des méthodes, je me permets une petite alerte rouge concernant votre idée de variable globale buf[256]:

    C'est une fausse bonne idée très dangereuse en C. Si vous utilisez un buffer global (ou static), vous ne pourrez jamais extraire deux informations sur la même ligne de code. Par exemple, si vous écrivez : printf("Jour 1: %s, Jour 2: %s\n", mid_global(ligne, 0, 3), mid_global(ligne, 3, 3));L'ordinateur va écraser le buffer global lors du deuxième appel avant même que le printf n'ait eu le temps de s'afficher. Vous obtiendrez un affichage buggé du type : Jour 1: MAR, Jour 2: MAR.

    C'est là toute la beauté de la macro que je vous proposais : elle n'est pas une macro à risque. C'est une norme stricte (ISO C99). Chaque fois que vous écrivez MID(...), le compilateur crée un nouveau buffer indépendant à la volée. Vous pouvez donc enchaîner les MID(...) dans la même équation mathématique sans qu'ils ne se marchent dessus !

    Mais la beauté de la programmation, c'est que vous restez le maître à bord ! Si vous préférez la rigueur d'allouer explicitement votre char buf[256]; avant chaque traitement pour que vos relecteurs voient exactement la gestion mémoire, c'est une excellente pratique. Veillez simplement à le déclarer localement (dans votre boucle ou votre fonction) et non en global, pour éviter les chevauchements !
    Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
    La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

  16. #16
    Invité de passage
    Femme Profil pro
    Recherche scientifique
    Inscrit en
    Avril 2020
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Dordogne (Aquitaine)

    Informations professionnelles :
    Activité : Recherche scientifique
    Secteur : Industrie Pharmaceutique

    Informations forums :
    Inscription : Avril 2020
    Messages : 11
    Par défaut
    Citation Envoyé par fred1599 Voir le message
    Votre vision mathématique y = f(x1, x2, x3) est justement la raison d'être de la solution que je vous ai proposée !

    En C classique, l'approche par pointeur oblige à écrire f(x1, y, x2, x3), où y est mélangé avec les paramètres d'entrée. C'est exactement ce problème que vient régler l'astuce du "littéral composé" : en laissant le compilateur gérer lui-même le buffer en arrière-plan, cela vous permet de retrouver une vraie fonction pure. On écrit tout simplement y = MID(x1, x2, x3) et le tour est joué.

    Cependant, puisque vous êtes très exigeante sur la qualité des méthodes, je me permets une petite alerte rouge concernant votre idée de variable globale buf[256]:

    C'est une fausse bonne idée très dangereuse en C. Si vous utilisez un buffer global (ou static), vous ne pourrez jamais extraire deux informations sur la même ligne de code. Par exemple, si vous écrivez : printf("Jour 1: %s, Jour 2: %s\n", mid_global(ligne, 0, 3), mid_global(ligne, 3, 3));...
    Oui,

    J'ai repris mon premier code et transformé.
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    13
    14
    15
    16
    17
    18
    19
    20
    21
    22
    23
    24
    25
    26
    27
    28
    29
    30
    31
    32
    33
    34
    35
    36
    37
    38
    39
     
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    #define MID_B(src, start, len) (MID)(src, (char[256]){0}, start, len)
     
    char* MID(const char * string_1, char * string_2, int start, int NBytes);
     
    char* MID(const char * string_1, char * string_2, int start, int NBytes) {
        if (string_1 == NULL || string_2 == NULL || start < 0 || NBytes <= 0) {
            if (string_2 != NULL) string_2[0] = '\0';
            return string_2;
        }
        int len = (int)strlen(string_1);
        if (start >= len) {
            string_2[0] = '\0';
            return string_2;
        }
     
        int k = start;
        int l = 0;
     
        for( ; k < len && k < (start + NBytes); k++ ) {
            string_2[l++] = string_1[k];
        }
     
        string_2[l] = '\0';
        return string_2;
    }
     
    int main() {
        char buf[64] = "SUNMONTUEWEDTHUFRISAT";
        int i;
        for ( i = 0; i < 7; i++ ) {
          const char *buf2 = MID_B( buf, 3 * i, 3);
          printf( "%i => %s\n", i, buf2 );
       }
    }
    Cela fonctionne parfaitement.
    Le #define est plutôt tordu. Je n'avais pas compris la subtilité du (char[256]){0} pour créer un string "furtif". Je n'ai pas encore compris comment cela fonctionne pour le créer. Un buf de 256 '\0'.
    Pourquoi (MID) avec les parenthèses ? C'est quoi ces () ? J'ai testé sans, cela fonctionne en apparence.

    Cela permet d'écrire un superbe MID$ avec la même syntaxe qu'en BASIC.
    Certes, une "garniture" à ajouter. Cela pourrait provoquer des alopécies fulgurantes...
    Je doutais que ce soit possible. Mes félicitations. J'aime beaucoup. Merci.

    Les constantes globales, je n'aime pas.
    Trop de risques en effet mais... parfois la tentation lors des mises au point. Je triche un peu.

  17. #17
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 954
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 4 954
    Par défaut
    Je vais vous expliquer les deux "mystères" de ce code : le littéral composé et les parenthèses.

    1. Comment fonctionne la magie du (char[256]){0} ?

    C'est une fonctionnalité très puissante de la norme C99 appelée Littéral Composé (Compound Literal). Elle se lit en deux parties :

    (char[256]) : Cela indique au compilateur le type de donnée que l'on veut créer (un tableau de 256 caractères). En le mettant entre parenthèses, on demande au C : "Crée-moi une variable de ce type, là, tout de suite, à la volée, sans lui donner de nom". Cette variable "furtive" est allouée sur la pile (stack) et s'auto-détruira à la fin de la ligne de code (l'expression). Zéro fuite de mémoire !

    {0} : C'est la valeur d'initialisation. En C, si vous mettez un 0 entre accolades lors de la création d'un tableau, le langage comprend qu'il doit remplir la totalité des 256 cases avec des zéros. Et un zéro mathématique correspond au caractère de fin de chaîne '\0' ! Vous obtenez donc instantanément un buffer de 256 cases parfaitement vierge et sécurisé.

    2. Pourquoi les parenthèses autour de (MID) ?

    Bonne observation ! Si vous avez testé sans les parenthèses et que cela fonctionne, c'est tout à fait normal avec votre code actuel.

    Ces parenthèses sont une ruse très avancée du C pour contrer le préprocesseur. Imaginons que vous vouliez que votre macro s'appelle MID et que votre fonction s'appelle aussi MID. Le préprocesseur (qui gère les #define) va repérer le mot MID dans la définition de votre fonction et tenter de le remplacer, ce qui va faire exploser la compilation.

    Pour déclencher une macro, le standard C impose que le nom soit immédiatement suivi d'une parenthèse ouvrante "(". Si on déclare la fonction sous la forme char* (MID)(...), le préprocesseur lit une parenthèse fermante ")" juste après le D, se dit ce n'est pas la macro, et laisse le nom tranquille ! Cela permet de donner le même nom à la fonction et à la macro.

    Mais puisque vous avez judicieusement choisi d'appeler votre macro MID_B, il n'y a plus aucun conflit de nom avec la fonction MID ! Vous pouvez donc tout à fait retirer ces parenthèses et écrire l'en-tête très proprement : char* MID(const char * string_1, char * string_2, int start, int NBytes);Vous avez maintenant un MID$ robuste, propre, et aussi maniable qu'en BASIC. Bonne continuation dans vos projets !
    Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
    La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

  18. #18
    Expert confirmé
    Homme Profil pro
    Analyste/ Programmeur
    Inscrit en
    Juillet 2013
    Messages
    4 841
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Bouches du Rhône (Provence Alpes Côte d'Azur)

    Informations professionnelles :
    Activité : Analyste/ Programmeur

    Informations forums :
    Inscription : Juillet 2013
    Messages : 4 841
    Par défaut
    Citation Envoyé par Fluorine Voir le message
    Le #define est plutôt tordu. Je n'avais pas compris la subtilité du (char[256]){0} pour créer un string "furtif". Je n'ai pas encore compris comment cela fonctionne pour le créer. Un buf de 256 '\0'.
    En gros c'est du sucre syntaxique

    En reprenant le code de @fred1599 message #11

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
       for(int i = 0; i < num_lines; i++) {
            const char* line = dataset[i];
     
            int id = atoi(MID_B(line, 0, 4)); 
    /* ... */
        }
    devient
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    3
    4
    5
    6
    7
    8
    9
    10
    11
    12
    { // <- on crée 1 bloc de façon explicite
        char tmp[256]; // création et initialisation du buffer temporaire
        memset(tmp, '\0', 256 /* * sizeof(char) */);
     
        for(int i = 0; i < num_lines; i++) {
            const char* line = dataset[i];
     
            int id = atoi( MID(line, tmp, 0, 4) );  // le #define masque le buffer temporaire mais il est là
    /* ... */
        }
     
    } // <- fin du bloc et donc destruction des variables locales : ici le buffer
    Après pour la création du bloc je ne sais pas si dans l'exécutable final il y est ou pas, mais c'est 1 technique en C pour créer des grosses variables temporaires en mémoire sans allocation : on crée 1 bloc.

    Et avec les macros, on surparenthèse pour éviter les surprises parce que les macros sont très très basiques

  19. #19
    Invité de passage
    Femme Profil pro
    Recherche scientifique
    Inscrit en
    Avril 2020
    Messages
    11
    Détails du profil
    Informations personnelles :
    Sexe : Femme
    Localisation : France, Dordogne (Aquitaine)

    Informations professionnelles :
    Activité : Recherche scientifique
    Secteur : Industrie Pharmaceutique

    Informations forums :
    Inscription : Avril 2020
    Messages : 11
    Par défaut
    Citation Envoyé par fred1599 Voir le message
    Je vais vous expliquer les deux "mystères" de ce code : le littéral composé et les parenthèses.

    ...
    Vous avez maintenant un MID$ robuste, propre, et aussi maniable qu'en BASIC. Bonne continuation dans vos projets !
    Explication lumineuse...
    J'en suis encore à "The Langage C" de K&R. Un pavé de 1988 qui est fatigué.
    Je connais peu le C99. Je découvre les super possibilités.
    Heureusement je retrouve largement les possibilités du "vieux C".
    Il faudrait que j'investisse dans un manuel.

    Ou me perfectionner en C++, ce serait mieux, aussi pour MID$.
    J'aime le C, pas très envie de la quitter et je suis rodée.
    J'eus débuté en Fortran. J'ai détesté le COBOL !!!
    Je vise le multiprécision, cela doit exister avec les additifs. Moshier ?
    Des possibilité dans "The Numerical Recipes in C++".

    J'ai fort heureusement gardé mes codes sources de mes anciens programmes.
    Je n'avais naïvement pas prévu l'incompatibilité du 64 bits avec les anciens programmes. Bon la DOS-BOX...
    Cela me sert d'avertissement pour le futur.

    Merci beaucoup pour toutes ces super infos.
    Je laisse quelques jours pour les réponses tardives et je passe en "résolu".

  20. #20
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 954
    Détails du profil
    Informations personnelles :
    Sexe : Homme
    Localisation : France, Meurthe et Moselle (Lorraine)

    Informations professionnelles :
    Activité : Lead Dev Python
    Secteur : Arts - Culture

    Informations forums :
    Inscription : Juillet 2006
    Messages : 4 954
    Par défaut
    @foetus,

    Est-ce que ce type de ligne fonctionne ?

    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    printf("ID: %s, Nom: %s\n", MID(line, tmp, 0, 4), MID(line, tmp, 5, 10));
    avec votre code exemple ?
    Celui qui trouve sans chercher est celui qui a longtemps cherché sans trouver.(Bachelard)
    La connaissance s'acquiert par l'expérience, tout le reste n'est que de l'information.(Einstein)

Discussions similaires

  1. Retourner une valeur depuis une fonction
    Par Katden dans le forum Shell et commandes GNU
    Réponses: 2
    Dernier message: 15/04/2026, 21h44
  2. Retourner un load_html depuis une fonction
    Par Lekno dans le forum EDI, CMS, Outils, Scripts et API
    Réponses: 8
    Dernier message: 24/10/2013, 12h36
  3. Retourner un tableau depuis une fonction
    Par obalais dans le forum C++
    Réponses: 2
    Dernier message: 20/10/2005, 16h49
  4. Ecrire dans un tableau html depuis une fonction js ?
    Par botanica dans le forum Général JavaScript
    Réponses: 2
    Dernier message: 05/10/2005, 12h48
  5. convertir une string en une fonction
    Par danny_67 dans le forum XML
    Réponses: 2
    Dernier message: 26/08/2005, 13h55

Partager

Partager
  • Envoyer la discussion sur Viadeo
  • Envoyer la discussion sur Twitter
  • Envoyer la discussion sur Google
  • Envoyer la discussion sur Facebook
  • Envoyer la discussion sur Digg
  • Envoyer la discussion sur Delicious
  • Envoyer la discussion sur MySpace
  • Envoyer la discussion sur Yahoo