2017-09-23 5 views
0

sscanf fonctionne comme ceci:Existe-t-il une variante de sscanf avec un pointeur vers une chaîne d'entrée au lieu de tampons?

int main(const int argc, const char *argv[]) { 
    char buf1[1024] = {0}; 
    char buf2[1024] = {0}; 
    char buf3[1024] = {0}; 
    char *str = "abc, 123; xyz"; 
    sscanf(str, "%[^,], %[^;]; %s", buf1, buf2, buf3); 
    printf("'%s' '%s' '%s'", buf1, buf2, buf3); // Prints: "'abc' '123' 'xyz'" 
    return 0; 
} 

Je me demande s'il y a une fonction qui ne nécessite pas la copie du contenu de str dans les tampons (buf1, buf2, buf3), ni allouer une nouvelle mémoire. Au lieu de cela, il suffit de définir les pointeurs (ptr1, ptr2, ptr3) pour pointer sur les parties correspondantes dans str et de mettre fin à tout ce qui vient après la correspondance.

int main(const int argc, const char *argv[]) { 
    char *ptr1 = NULL; 
    char *ptr2 = NULL; 
    char *ptr3 = NULL; 
    char *str = "abc, 123; xyz"; 
    // 
    // str = "abc, 123; xyz\0" 
    // 
    _sscanf(str, "%[^,], %[^;]; %s", &ptr1, &ptr2, &ptr3); 
    // 
    // str = "abc\0 123\0 xyz\0" 
    //  ^ ^ ^
    //  ptr1 ptr2 ptr3 
    // 
    printf("'%s' '%s' '%s'", ptr1, ptr2, ptr3); // Prints: "'abc' '123' 'xyz'" 

    return 0; 
} 

Je sais qu'il ya des fonctions telles que strtok_r et la bibliothèque regex.h qui pourrait être utilisé, mais je pense que ce serait plus pratique dans les cas où la chaîne d'entrée peut être modifiée.

+0

Le problème est que ne peut pas * toujours * se terminer par l'entrée analysé par 'sscanf'! Le 'regex.h' renvoie * plages * des correspondances de sous-groupe - ce serait faisable. –

+0

Votre question est un non-sens comme si vous annulez la chaîne d'origine quelque part au milieu, vous ne serez plus jamais la même chaîne, car vous écraserez quelque chose BTW même si vous déplacez le reste de si la taille de la str sera augmentation et la réaffectation la plus probable sera nécessaire –

+0

Notez que j'ai dit dans certains cas. Dans certains cas, je me fiche de savoir si la chaîne d'entrée est modifiée. –

Répondre

4

Ce n'est pas joli mais le spécificateur %n peut être utilisé pour capturer l'index au début et à la fin des jetons. La vérification des erreurs serait assurez-vous que les index et les valeurs de fin ne sont pas -1

#include <stdio.h> 

int main(int argc, char *argv[]) { 
    int index1 = -1; 
    int end1 = -1; 
    int index2 = -1; 
    int end2 = -1; 
    int index3 = -1; 
    int end3 = -1; 
    char *str = "abc, 123; xyz"; 
    sscanf(str, " %n%*[^,]%n, %n%*[^;]%n; %n%*s%n", &index1, &end1, &index2, &end2, &index3, &end3); 
    printf("'%.*s' '%.*s' '%.*s'", end1, str + index1, end2 - index2, str + index2, end3 - index3, str + index3); // Prints: "'abc' '123' 'xyz'" 
    return 0; 
} 
1

Il n'y a pas une variante normalisée qui se termine avec des pointeurs vers char * pointant vers un emplacement de votre chaîne d'origine. Il existe une variante dans POSIX qui alloue de la mémoire et copie les données dans chaque élément de chaîne.

La fonctionnalité de sscanf() correspond à la fonctionnalité de fscanf() et les autres variantes, et dans des limites très larges, ce qui s'applique à une variante s'applique à tous. Ce que vous cherchez, cependant, n'a pas pu être appliqué aux variantes basées sur des fichiers, donc il n'existe pas.


Il existe une variante de sscanf() qui alloue de la mémoire pour les chaînes. C'est la variante POSIX 2008 de sscanf() et le modificateur m.

[CX] ⌦ Les %c, %s et %[ spécificateurs de conversion acceptent un caractère affectation d'allocation « m » en option, qui doit provoquer un tampon de mémoire à allouer à maintenir la chaîne convertie comprenant un caractère nul de terminaison . Dans ce cas, l'argument correspondant au spécificateur de conversion doit être une référence à une variable pointeur qui recevra un pointeur vers le tampon alloué. Le système doit allouer un tampon comme si malloc() avait été appelé. L'application sera responsable de libérer la mémoire après utilisation. S'il n'y a pas suffisamment de mémoire pour allouer un tampon, la fonction doit régler errno à [ENOMEM] et une erreur de conversion doit en résulter. Si la fonction renvoie EOF, toute mémoire allouée avec succès pour les paramètres utilisant le caractère d'allocation d'affectation 'm' par cet appel doit être libérée avant le retour de la fonction. ⌫

Les marques de notation [CX] cela comme une extension sur le standard de C (de sorte que le modificateur m ne fait pas partie de la norme C et il ne sera pas supporté partout) et la ⌦ et ⌫ symboles marquent la portée de l'extension. Ainsi, si votre implémentation le supporte (Linux ne le fait pas, par exemple, macOS Sierra), il y a une variante de sscanf() qui va allouer des tampons de taille correcte pour vous, et il faut char ** arguments.

La page de manuel sur Linux dit:

Un caractère 'm' en option. Ceci est utilisé avec les conversions de chaînes (%s, %c, %[), et soulage l'appelant de la nécessité d'allouer un tampon correspondant pour contenir l'entrée: à la place, scanf() alloue un tampon de taille suffisante et affecte l'adresse de ce tampon au argument pointeur correspondant, qui doit être un pointeur vers une variable char * (cette variable n'a pas besoin d'être initialisée avant l'appel). L'appelant doit ensuite libérer (3) ce tampon lorsqu'il n'est plus nécessaire.

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

int main(void) 
{ 
    char data[] = "The hills are alive with the sound of music"; 
    char *w[9]; 

    if (sscanf(data, "%ms %ms %ms %ms %ms %ms %ms %ms %ms", 
       &w[0], &w[1], &w[2], &w[3], &w[4], &w[5], &w[6], &w[7], &w[8]) != 9) 
    { 
     fprintf(stderr, "Oops!\n"); 
     return 1; 
    } 
    printf("Forwards: %s\n", data); 
    printf("Reversed:"); 
    for (int i = 8; i >= 0; i--) 
     printf(" %s", w[i]); 
    putchar('\n'); 
    for (int i = 0; i < 9; i++) 
     free(w[i]); 
    return 0; 
} 

Sortie:

Forwards: The hills are alive with the sound of music 
Reversed: music of sound the with alive are hills The 
+0

Cela copie toujours les chaînes, cependant. Il ne renvoie pas de pointeurs dans la chaîne d'entrée, ce que demande OP, – zwol

+0

@zwol: Oh, j'ai mal lu la question la première fois. J'ai révisé ma réponse en conséquence. –

+0

Le modificateur 'm' fonctionne également avec Posix' scanf' et 'fscanf'. (Je sais que vous le savez, mais votre réponse pourrait être mal interprétée, je pense.) – rici