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. #21
    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
    Est-ce que ce type de ligne fonctionne ? […] avec votre code exemple ?
    Oui et non tu en as parlé avant (et moi aussi) : il a chevauchement des données/ multi-appels sur la même donnée.

    Il faut coder
    Code : Sélectionner tout - Visualiser dans une fenêtre à part
    1
    2
    printf("ID: %s", MID(line, tmp, 0, 4)); // ici on peut faire %4s
    printf(", Nom: %s\n", MID(line, tmp, 5, 10));  // ici on peut faire %12s
    Après je peux être taquin moi aussi Avec le littéral composé (sans parler qu'il faut compiler en C99 ou +)
    • quand est-ce que la variable temporaire est détruite ? avec 1 bloc explicite on le sait facilement (accolade fermante) Parce que si à chaque litteral composé on crée 1 variable locale, ton code message #11 crée 4 variables locales par tour de boucle
    • où est créée la variable : pile (stack) ou tas (heap) ? avec 1 variable locale, on sait que c'est sur la pile ... et donc on est limité en taille (char[8000]){0} explose comment ? avec 1 stack overflow ?

  2. #22
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 930
    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 930
    Par défaut
    Sur les printf découpés : C'est exactement ce que je voulais éviter ! Le but de mon approche était de retrouver l'ergonomie du BASIC, où l'on peut construire une ligne fluide du type y = MID(...) + MID(...). Devoir tronçonner mon affichage en plusieurs lignes pour faire plaisir au buffer tmp casse cette dynamique.

    Quand la variable furtive est-elle détruite ? (L'accumulation) La norme C99 (paragraphe 6.5.2.5) est très stricte là-dessus : un littéral composé possède une "durée de vie automatique liée à son bloc englobant". Concrètement, dans mon code, leur bloc englobant, c'est le bloc de la boucle for() { ... }. À chaque fois que le programme arrive à l'accolade fermante } de la boucle, pouf ! Les 4 variables furtives sont instantanément détruites. Au tour de boucle suivant, le compilateur réutilise exactement le même espace mémoire. Il n'y a donc aucune fuite, et la mémoire n'augmente jamais. Le coût constant est de 4 × 256 = 1024 octets pour toute l'exécution.

    Pile (Stack) ou Tas (Heap) ? Et si on demande 8000 ? C'est alloué très exactement au même endroit que ton char tmp[256] manuel : sur la Pile (Stack). Si on demande un littéral de (char[8000]){0}, que se passe-t-il ? Absolument rien de grave, ça passe sans trembler. La pile (sur Linux/Windows) fait généralement 8 Mégaoctets (8 000 000 octets). 8000 octets, c'est une goutte d'eau.

    En revanche, si on s'amusait à demander (char[10000000]){0}, oui, ça exploserait avec un magnifique Stack Overflow. Mais tu aurais strictement le même crash instantané avec ta méthode en déclarant un char tmp[10000000]; !

    Le "sucre syntaxique" ne change rien à la physique de l'ordinateur. Il demande simplement au compilateur de faire le sale boulot de déclaration et de remise à zéro à notre place, pour que nos yeux puissent se concentrer sur l'algorithme.

    D'ailleurs, j'ai passé mon code sous l'analyseur Valgrind, et tout est vert : 0 leak, 0 accès invalide. La "magie" opère bien !
    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)

  3. #23
    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 527
    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 527
    Par défaut
    En repartant de ma troisième solution, il suffit de créer une macro :
    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
    15
    16
    17
    18
    19
    20
    #include <stdio.h>
    #include <string.h>
    
    char *FMID(const char *src, int start, int len, char *dst)
    {
    	memcpy(dst, src + start, len);
    	dst[len] = '\0';
    	return dst;
    }
    
    #define MID(src, start, len) \
    	FMID(src, start, len, (char[(len)+1]){0})
    
    int main(void)
    {
    	printf("%s %s\n",
    		MID("BONJOUR", 1, 2),
    		MID("BONJOUR", 3, 4));
    	return 0;
    }
    La contrainte de cette solution est la durée de vie de ces deux tableaux temporaires, limitée au bloc de code { ... }.
    Par contre, en dehors du bloc, ces deux tableaux n'existent plus. Autrement dit, le comportement est sililaire à une variable locale.

    Je pense que vous prenez votre problème BASIC, Fluorine, dans le mauvais sens.
    A savoir, retrouver en 'C' le même comportement de votre fonction MID$ basic.
    Le mieux est de modifier vos programmes BASIC afin de les adapter à la contrainte du 'C'.
    On nomme cela une migration ! Et donc une réadaptation de vos programmes BASIC est nécessaire.

    Ou mieux, enfin si vous pouvez le faire, trouver un compilateur BASIC pour faire tourner vos anciens programmes.

  4. #24
    Expert confirmé
    Avatar de fred1599
    Homme Profil pro
    Lead Dev Python
    Inscrit en
    Juillet 2006
    Messages
    4 930
    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 930
    Par défaut
    Je pense que vous prenez votre problème BASIC, Fluorine, dans le mauvais sens.
    A savoir, retrouver en 'C' le même comportement de votre fonction MID$ basic.
    Le mieux est de modifier vos programmes BASIC afin de les adapter à la contrainte du 'C'.
    On nomme cela une migration ! Et donc une réadaptation de vos programmes BASIC est nécessaire.
    Oui je suis totalement d'accord, mais... sur le coup là, on a réussi à tordre le coup du langage pour rendre du code élégant, donc pourquoi s'en priver

    Ton astuce du littéral avec taille dynamique (char[(len)+1]){0} est vraiment superbe, je l'adopte ! En revanche, je ne peux pas garder ton memcpy. C'est beaucoup trop risqué si on lit un fichier mal formaté : si je demande 100 caractères sur une source qui n'en a que 5, ton memcpy va faire une lecture hors limites (Buffer Over-read) très dangereuse. De plus, la fonction crashe immédiatement sur un pointeur NULL ou si le calcul de la taille devient négatif.

    Je vais donc mélanger nos deux idées

    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
    #include <stdio.h>
    #include <stdlib.h>
    #include <string.h>
     
    // La macro hybride : L'idée du forum (tableau dynamique VLA) + votre sécurité anti-crash (taille >= 1)
    #define MID_B(src, start, len) MID(src, (char[((len) > 0 ? (len) : 0) + 1]){0}, start, len)
     
    // Prototype de la fonction
    char* MID(const char * string_1, char * string_2, int start, int NBytes);
     
    // Implémentation sécurisée
    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;
    }
     
    // Le test de l'extraction multiple
    int main(void) {
        const char* dataset[] = {
            "1082-THOMAS    -00468.52-DEL",
            "5567-MARTIN    -00746.16-INJ",
            "2438-DURAND    -00213.65-INJ"
        };
        int num_lines = 3;
     
        printf("=== EXTRACTION MULTIPLE SUR UNE SEULE LIGNE (INLINE) ===\n");
     
        for(int i = 0; i < num_lines; i++) {
            const char* line = dataset[i];
     
            // L'épreuve du feu : Deux appels sur la même ligne !
            // Aucun risque que le statut n'écrase le nom.
            printf("Le statut de '%s' est '%s'\n", 
                   MID_B(line, 5, 10), 
                   MID_B(line, 25, 3));
        }
     
        printf("\n=== CALCULS MATHÉMATIQUES SIMULTANÉS ===\n");
     
        // Extrait deux nombres et les additionne directement sur une ligne
        const char* ligne_nombres = "0025-0015";
        int total = atoi(MID_B(ligne_nombres, 0, 4)) + atoi(MID_B(ligne_nombres, 5, 4));
     
        printf("Addition inline : %s + %s = %d\n", 
               MID_B(ligne_nombres, 0, 4), 
               MID_B(ligne_nombres, 5, 4), 
               total);
     
        return 0;
    }
    Tout passe sans erreur, valgrind nickel...
    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