Contenu | Rechercher | Menus

Annonce

Si vous avez des soucis pour rester connecté, déconnectez-vous puis reconnectez-vous depuis ce lien en cochant la case
Me connecter automatiquement lors de mes prochaines visites.

À propos de l'équipe du forum.

#1 Le 14/02/2013, à 12:12

kboo

C++: chaine de caractères... (et NetCDF)

Bonjour,
Je cherche à faire des chaines de caractères de longueurs non constantes, par exemple:

Ce cas là fonctionne bien:

static const int NX = 12;
static const int NY = 7;
NcFile dataFile("simple_xy.nc", NcFile::Replace);
NcDim* xDim = dataFile.add_dim("x", NX);
NcDim* yDim = dataFile.add_dim("y", NY);
NcVar *monChar = dataFile.add_var("monChar", ncChar, xDim, yDim);
char* monCharUn[] = {"aaaaaa","bbbbbb","cccccc","dddddd", "eeeeee", "ffffff", "gggggg", "hhhhhh", "iiiiii", "jjjjjj", "kkkkkk", "llllll"};
monChar->put(&monCharUn[0][0], NX, NY);

J'obtiens dans le NetCDF:

 monChar =
  "aaaaaa",
  "bbbbbb",
  "cccccc",
  "dddddd",
  "eeeeee",
  "ffffff",
  "gggggg",
  "hhhhhh",
  "iiiiii",
  "jjjjjj",
  "kkkkkk",
  "llllll" ;

Par contre si je fais :

static const int NX = 12;
static const int NY = 7;
NcFile dataFile("simple_xy.nc", NcFile::Replace);
NcDim* xDim = dataFile.add_dim("x", NX);
NcDim* yDim = dataFile.add_dim("y", NY);
NcVar *monChar = dataFile.add_var("monChar", ncChar, xDim, yDim);
char* monCharUn[] = {"aaaaaa","bbb","cccccc","dddddd", "eeeeee", "ffffff", "gggggg", "hhhhhh", "iiiiii", "jjjjjj", "kkkkkk", "llllll"};
monChar->put(&monCharUn[0][0], NX, NY);

ça me donne:

 monChar =
  "aaaaaa",
  "bbb\000ccc",
  "ccc\000ddd",
  "ddd\000eee",
  "eee\000fff",
  "fff\000ggg",
  "ggg\000hhh",
  "hhh\000iii",
  "iii\000jjj",
  "jjj\000kkk",
  "kkk\000lll",
  "lll\000\000\000*" ;

snif, comment faire pour avoir des éléments de longueurs différentes, sachant que quand je fais le NetCDF à la main (ncgen) ça marche bien hmm

merci d'avance!!

Hors ligne

#2 Le 14/02/2013, à 12:27

pingouinux

Re : C++: chaine de caractères... (et NetCDF)

Bonjour,
Il faudrait savoir comment est utilisé monCharUn lors de cet appel monChar->put(&monCharUn[0][0], NX, NY);

Hors ligne

#3 Le 14/02/2013, à 13:49

nicolas66

Re : C++: chaine de caractères... (et NetCDF)

Petite remarque : le C++ gère très bien les chaînes de caractères avec la classe std::string. Pas besoin de se compliquer la vie. Sinon, on parle bien de C et non de C++.


"The computer was born to solve problems that did not exist before." (B. Gates)

Hors ligne

#4 Le 14/02/2013, à 14:10

kboo

Re : C++: chaine de caractères... (et NetCDF)

nicolas66 a écrit :

Petite remarque : le C++ gère très bien les chaînes de caractères avec la classe std::string. Pas besoin de se compliquer la vie. Sinon, on parle bien de C et non de C++.

Exact sauf que la bibliothèque NetCDF(3) veut du char * et pas de string :-(

Hors ligne

#5 Le 14/02/2013, à 14:12

kboo

Re : C++: chaine de caractères... (et NetCDF)

Merci pour vos réponse,j 'ai un peu avancé mais c'est moche moche moche: J'ai ajouté des \0 pour compléter la longueur de la chaîne

static const int NX = 12;
static const int NY = 7;
NcFile dataFile("simple_xy.nc", NcFile::Replace);
NcDim* xDim = dataFile.add_dim("x", NX);
NcDim* yDim = dataFile.add_dim("y", NY);
NcVar *monChar = dataFile.add_var("monChar", ncChar, xDim, yDim);
char* monCharUn[] = {"aaaaaa","bbb\0\0\0","cccccc","dddddd", "eeeeee", "ffffff", "gggggg", "hhhhhh", "iiiiii", "jjjjjj", "kkkkkk", "llllll"};
monChar->put(&monCharUn[0][0], NX, NY);

ça fonctionne, je ne l'explique pas mais je trouve ça hyper laid... vous en pensez quoi?

Dernière modification par kboo (Le 14/02/2013, à 14:15)

Hors ligne

#6 Le 14/02/2013, à 15:03

pingouinux

Re : C++: chaine de caractères... (et NetCDF)

Ma remarque du #2 est toujours valable. Il faudrait avoir des informations supplémentaires.

Hors ligne

#7 Le 14/02/2013, à 15:14

eiger

Re : C++: chaine de caractères... (et NetCDF)

Salut,

Je n'ai jamais utilisé la bibliothèque en question, mais es-tu sûr qu'il n'y a pas erreur de ta part sur l'utilisation que tu en fais ?
Je m'explique :

kboo a écrit :
NcVar *monChar = dataFile.add_var("monChar", ncChar, xDim, yDim);

Dans la description de l'API, on trouve :

NcVar* add_var(NcToken varname, NcType type, const NcDim*, ...)
Add a variable named varname of the specified type (ncByte, ncChar, ncShort, ncInt, ncFloat, ncDouble) to the open netCDF file. The variable is defined with a shape that depends on how many dimension arguments are provided. A scalar variable would have 0 dimensions, a vector would have 1 dimension, and so on. Supply as many dimensions as needed, up to 5. If more than 5 dimensions are required, use the n-dimensional version of this member function instead.

D'après ceci, avec la ligne de code ci-dessus, tu ajoutes une variable de type "ncChar" à 2 dimensions (une matrice donc). Ce qui n'a rien à voir avec des chaînes de caractères. C'est juste une matrice de "ncChar". J'imagine que ncChar est un simple alias pour "char", mais sans garantie.


Bref, vérifie quand même qu'il est possible de gérer des chaînes avec cette bibliothèque.

Hors ligne

#8 Le 14/02/2013, à 16:02

kboo

Re : C++: chaine de caractères... (et NetCDF)

eiger a écrit :

Salut,

Je n'ai jamais utilisé la bibliothèque en question, mais es-tu sûr qu'il n'y a pas erreur de ta part sur l'utilisation que tu en fais ?
Je m'explique :

kboo a écrit :
NcVar *monChar = dataFile.add_var("monChar", ncChar, xDim, yDim);

Dans la description de l'API, on trouve :

NcVar* add_var(NcToken varname, NcType type, const NcDim*, ...)
Add a variable named varname of the specified type (ncByte, ncChar, ncShort, ncInt, ncFloat, ncDouble) to the open netCDF file. The variable is defined with a shape that depends on how many dimension arguments are provided. A scalar variable would have 0 dimensions, a vector would have 1 dimension, and so on. Supply as many dimensions as needed, up to 5. If more than 5 dimensions are required, use the n-dimensional version of this member function instead.

D'après ceci, avec la ligne de code ci-dessus, tu ajoutes une variable de type "ncChar" à 2 dimensions (une matrice donc). Ce qui n'a rien à voir avec des chaînes de caractères. C'est juste une matrice de "ncChar". J'imagine que ncChar est un simple alias pour "char", mais sans garantie.


Bref, vérifie quand même qu'il est possible de gérer des chaînes avec cette bibliothèque.

Merci pour ton aide,
en effet tu m'as mis le doute donc j'ai essayé mais c'est pas encore ça :-(

static const int NX = 12;
NcDim* xDim = dataFile.add_dim("x", NX);
NcVar *monChar2 = dataFile.add_var("monChar2", ncChar, xDim);
char* monCharDeux[] = {"aaaaa","bbbbb","ccccc","ddddd", "eeeee", "fffff", "ggggg", "hhhhh", "iiiii", "jjjjj", "kkkkk", "lllll"};
monChar2->put(&monCharDeux[0][0], NX);

Résultat:

monChar2 = "aaaaa\000bbbbb" ;

de plus avec ma technique des \0 ça donne des résultats étranges, du genre si je créé un autre tableau à côté ça fausse les résultats (décalage !)

Hors ligne

#9 Le 14/02/2013, à 16:14

kboo

Re : C++: chaine de caractères... (et NetCDF)

pingouinux a écrit :

Bonjour,
Il faudrait savoir comment est utilisé monCharUn lors de cet appel monChar->put(&monCharUn[0][0], NX, NY);

Comment savoir? je sèche hmm

Hors ligne

#10 Le 15/02/2013, à 09:48

eiger

Re : C++: chaine de caractères... (et NetCDF)

kboo a écrit :

[
Merci pour ton aide,
en effet tu m'as mis le doute donc j'ai essayé mais c'est pas encore ça :-(

static const int NX = 12;
NcDim* xDim = dataFile.add_dim("x", NX);
NcVar *monChar2 = dataFile.add_var("monChar2", ncChar, xDim);
char* monCharDeux[] = {"aaaaa","bbbbb","ccccc","ddddd", "eeeee", "fffff", "ggggg", "hhhhh", "iiiii", "jjjjj", "kkkkk", "lllll"};
monChar2->put(&monCharDeux[0][0], NX);

Résultat:

monChar2 = "aaaaa\000bbbbb" ;

de plus avec ma technique des \0 ça donne des résultats étranges, du genre si je créé un autre tableau à côté ça fausse les résultats (décalage !)

Il me semble que tu n'as pas compris ma remarque.
En lisant la doc de ta bibliothèque NetCDF, moi j'ai vraiment l'impression qu'elle n'est pas capable de gérer des chaînes, mais seulement des scalaires.

Ton premier exemple crée une matrice 12x7 d'éléments de type "char".
Ton deuxième exemple crée un vecteur de 12 éléments de type "char".
Rien de tout ceci n'est une chaîne de caractères.

Pour que ta bibliothèque gère les chaînes, il faudrait qu'elle gère le type "char *", ce qui ne semble pas être le cas.

Hors ligne

#11 Le 15/02/2013, à 10:13

kboo

Re : C++: chaine de caractères... (et NetCDF)

Bonjour,

Eiger, j'ai trouvé une solution, pour ce qui concerne la bibliothèque NetCDF, elle ne gère pas le type string ni les char** mais par contre aucun problème avec les char*.
Voici la solution toute cradote mais le principe y est :-)

     #include <iostream>
     #include <netcdfcpp.h>
     #include <vector>
     
     using namespace std;
     
     static const int NX = 12;
     static const int NY = 6;
     static const int NC_ERR = 2;

int main(void)
     {
        int dataOut[NX][NY];
     
        for(int i = 0; i < NX; i++)
           for(int j = 0; j < NY; j++)
               dataOut[i][j] = i * NY + j;
     
        NcFile dataFile("chaine.nc", NcFile::Replace);
     
        if (!dataFile.is_valid())
        {
           cout << "Couldn't open file!\n";
           return NC_ERR;
        }
     
        NcDim* xDim = dataFile.add_dim("x", NX);
        NcDim* yDim = dataFile.add_dim("y", NY);

        NcVar *monChar1 = dataFile.add_var("monChar1", ncChar, xDim, yDim);

        vector<string> dataOut1Vec;
        string str = "az";
        str.resize(6);
        dataOut1Vec.push_back(str);
        str = "aa";
        str.resize(6);
        dataOut1Vec.push_back(str);
        str = "aaa";
        str.resize(6);
        dataOut1Vec.push_back(str);
        str = "aaaa";
        str.resize(6);
        dataOut1Vec.push_back(str);
        str = "aaa";
        str.resize(6);
        dataOut1Vec.push_back(str);
        str = "aa";
        str.resize(6);
        dataOut1Vec.push_back(str);
        str = "a";
        str.resize(6);
        dataOut1Vec.push_back(str);
        str = "1aaaa";
        str.resize(6);
        dataOut1Vec.push_back(str);
        str = "aa";
        str.resize(6);
        dataOut1Vec.push_back(str);
        str = "aa";
        str.resize(6);
        dataOut1Vec.push_back(str);
        str = "aa";
        str.resize(6);
        dataOut1Vec.push_back(str);
        str = "aa";
        str.resize(6);
        dataOut1Vec.push_back(str);
        for(int i=0 ; i<12 ;i++)
            monChar1->put_rec(xDim, &(dataOut1Vec[i][0]), i);

        return 0;
     }

Merci encore :-)

Hors ligne

#12 Le 18/02/2013, à 04:39

grim7reaper

Re : C++: chaine de caractères... (et NetCDF)

Salut,

J’arrive un peu tard, mais bon…

En NetCDF-3 je pense que la solution de padder avec des bytes nuls pour avoir une taille constante reste la meilleure solution.
En effet, le NetCDF-3 ne gère pas ce que tu veux faire, en partie à cause du Fortran.

https://www.unidata.ucar.edu/software/netcdf/old_docs/docs_4_1_2/netcdf-c/Classic-Strings.html a écrit :

Character strings are not a primitive netCDF external data type, in part because FORTRAN does not support the abstraction of variable-length character strings (the FORTRAN LEN function returns the static length of a character string, not its dynamic length). As a result, a character string cannot be written or read as a single object in the netCDF interface. Instead, a character string must be treated as an array of characters, and array access must be used to read and write character strings as variable data in netCDF datasets. Furthermore, variable-length strings are not supported by the netCDF interface except by convention; for example, you may treat a zero byte as terminating a character string, but you must explicitly specify the length of strings to be read from and written to netCDF variables.

Par contre si tu peux passer au NetCDF-4, il y a un type qui pourrait te convenir : les VLEN Types.

https://www.unidata.ucar.edu/software/netcdf/docs/netcdf/User-Defined-Types.html#User-Defined-Types a écrit :

Variable length arrays can be used to create a ragged array of data, in which one of the dimensions varies in size from point to point.

An example of VLEN use would the to store a 1-D array of dropsonde data, in which the data at each drop point is of variable length.

There is no special restriction on the dimensionality of VLEN variables. It's possible to have 2D, 3D, 4D, etc. data, in which each point contains a VLEN.

A VLEN has a base type (that is, the type that it is a VLEN of). This may be one of the atomic types (forming, for example, a variable length array of NC_INT), or it can be another user defined type, like a compound type.

With VLEN data, special memory allocation and deallocation procedures must be followed, or memory leaks may occur.

Compression is permitted but may not be effective for VLEN data, because the compression is applied to structures containing lengths and pointers to the data, rather than the actual data.

For more information on creating and using variable length arrays, see Variable Length Arrays in The NetCDF C Interface Guide.

La doc est .

Au passage, si tu joue avec NetCDF et C++, il faut savoir que l’interface par défaut (celle fourni par Ubuntu par exemple) se fait vieille et est vraiment limité.
Une nouvelle existe, elle est un peu plus C++ dans son interface et elle gère le NetCDF-4.
La nouvelle (et l’ancienne interface) sont disponible ici. La doc’ est .

Hors ligne