Je comprends mal quelque chose de fondamental concernant les pointeurs en C.

Dans le code ci-dessous, si db_open( "name.db", dbP ) est invoqué depuis une autre fonction, la base de données est ouverte/créée mais dbP n'est pas reconnu par la suite dans build_schema mais est NULL. Si db_open est modifié pour ne pas avoir d'argument sqlite3 *db et fait référence au global dbP, alors dbP est reconnu dans build_schema et n'est pas NULL .

L'objectif est que db_open accepte n'importe quel nom de base de données et descripteur de base de données sqlite.

Pourriez-vous s'il vous plaît expliquer ce que je fais mal et malentendu?

Je vous remercie.


J'ai ajouté plus de code comme demandé. La base de données est créée avec succès et build_schema est invoqué mais l'instruction sqlite prepare renvoie un code d'erreur de 21 car dbP est null dans cette fonction si vous l'imprimez. Cependant, si alter db_open pour ne pas avoir le deuxième argument et référence dbP dans toutes les fonctions, build_schema réussit, les instructions SQL sont traitées, la base de données contient des tables et affiche dbP affiche quelque chose comme AL.

// function prototype
int db_open( char [], sqlite3 *db ); 

// Global variables.
sqlite3 *dbP;  // The primary database.    

int main( void )
  {
    int rc;   
    switch( rc = db_open( "path/db_name.db", dbP ) )
       {
         case 'c' :
              build_schema( &J[ i ] );  
              break;
         case 'o' :
            get_base( &J[ i ] ); 
            break;
         default: ...;
       }
    }

int db_open( char db_name[], sqlite3 *db )
  { 
    int rc; 
    // Attempt to open the database as if already existed; will fail if does not exist. 
    rc = sqlite3_open_v2( db_name, &db, SQLITE_OPEN_READWRITE, NULL );
    if ( rc == 14 )
      {
        // Error code of 14 is a generic "unable to open database." 
        // First, assume failed to open because database doesn't exist; and modify flags to attempt to create it anew. 
        rc = sqlite3_open_v2( db_name, &db, SQLITE_OPEN_READWRITE | SQLITE_OPEN_CREATE, NULL );
        // If rc > 0 then failed to create a database; otherwise, return "c" indicating successful creation of database.
        return rc ? 'e' : 'c';
      } 
    else if ( rc )
      // Correction of error codes other than 14 is not attempted, and user is informed. 
      return 'e';
    else
      // Existing database opened successfully.
      return 'o';
  } // close db_open

void build_schema( char *j )
  {
    sqlite3_stmt *stmt;
    char *sql;
    const char *tail;
    int rc;

    sql = "SQL statement_1 to create a table;"
          "SQL statement_2 to create a table;"
          "SQL statement_3; to create a table";

    while ( sqlite3_complete( sql ) )
      {
        rc = sqlite3_prepare_v2( dbP, sql, -1, &stmt, &tail );
        sqlite3_step( stmt );
        sql = tail;
      }

    sqlite3_finalize( stmt );
  }
0
Gary 13 nov. 2020 à 08:33

1 réponse

Meilleure réponse

Le problème que je vois est que vous transmettez la valeur de dbP plutôt que l'emplacement de dbP à votre fonction d'assistance qui prend alors l'emplacement de son argument lorsque la fonction sqlite3_open_v2 écrit. Il écrit à l'emplacement de l'argument de la fonction db_open db plutôt qu'à l'emplacement du dbP global.

int sqlite3_open_v2(
  const char *filename,   /* Database filename (UTF-8) */
  sqlite3 **ppDb,         /* OUT: SQLite db handle */
  int flags,              /* Flags */
  const char *zVfs        /* Name of VFS module to use */
);

db_open devrait prendre un sqlite3 ** et ensuite il devrait simplement le transmettre. Cela place alors le & au bon endroit. Alors voyez avoir un &dbP.

switch( rc = db_open( "path/db_name.db", &dbP ) )

int db_open( char db_name[], sqlite3 **db )

rc = sqlite3_open_v2( db_name, db, SQLITE_OPEN_READWRITE, NULL );
1
Dan D. 14 nov. 2020 à 00:53