嵌入式数据库 SQLite 浅析

6人阅读 评论(0) 收藏 举报
分类:
SQLite是一个非常轻量级自包含(lightweight and self-contained)的DBMS,它可移植性好,很容易使用,很小,高效而且可靠。SQLite嵌入到使用它的应用程序中,它们共用相同的进程空间,而不是单独的一个进程。从外部看,它并不像一个RDBMS,但在进程内部,它却是完整的,自包含的数据库引擎。
       嵌入式数据库的一大好处就是在你的程序内部不需要网络配置,也不需要管理。因为客户端和服务器在同一进程空间运行。SQLite 的数据库权限只依赖于文件系统,没有用户帐户的概念。SQLite 有数据库级锁定,没有网络服务器。它需要的内存,其它开销很小,适合用于嵌入式设备。你需要做的仅仅是把它正确的编译到你的程序。
下面将介绍SQLite的使用:
一、创建SQLite数据库
1、手工创建
使用sqlite3 工具,通过手工输入SQL命令完成数据库创建,用户在Linux 的命令行界面中输入 sqlite3 可启动 sqlite3工具。
2、代码创建
在代码中动态创建数据库。
在程序执行过程中,当需要进行数据库操作时,应用程序会首先尝试打开数据库,此时如果数据库并不存在,程序会自动建立数据库,然后打开数据库。

二、SQLite常用命令介绍
1、sqlite3 指令(通常以 . 开头)
1)创建或打开一个数据库文件
       在终端下运行 sqlite3 < *.db > 指令:

<*.db> 是要打开的数据库文件。若该文件不存在,则自动创建。

2)显示当前打开的数据库文件
sqlite > .database

可以看到当前打开的数据库文件正是刚刚建立的 test.db文件;

3)显示数据库中所有表名
sqlite > .tables

可以看到当前用户下有一个名为 stu 的表;

4)查看表的结构
sqlite > .schema <table_name>

其实这里显示的正是我们创建新表时输入的命令;

5)显示所有命令
sqlite > .help

6) 退出 sqlite3
sqlite > .quit


7) 修改 .header和 .mode
sqlite>.header on
sqlite>.mode column


2、SQL命令
       每个命令以 ;结束
1)创建新表
      sqlite > create table <table_name> (f1 type1, f2 type2,...);

type为数据类型:

NULL 标识一个NULL值
INTERGER 整数类型int
REAL 浮点型,float,doubale
TEXT 字符串
CHAR 字符型
BLOB 二进制010101

注意:若未指定类型,默认是字符串,向表中添加新纪录时要加 " ";

2)删除表
 sqlite > drop table <table_name>;

可以看到原来有两个表 stu与stu2 ,使用 drop  table stu2 后可以看到 只剩下 stu;

3)向表中添加新纪录
sqlite >insert into <table_name> <(f1, f2, f3)> values(value1,value2,...);

或 (id, name, score)可省略不写

可以看到最新的记录被添加进去;
4)查询表中所有记录
 sqlite >select * from <table_name>;

5)按指定条件查询表中记录
sqlite >select * from <table_name> where <expression>;

这里的条件是 score >90 ,可以看到 score > 90 的数据被挑选出来;

这里的条件是 score >90 and score <95,可以看到 score >90 and score <95 的数据被挑选出来;

6)查询student表中指定的字段
select name, id from stduent;

7)限制输出数据记录数量
select * from table_name limit val;

8)升序输出数据记录
select * from table_name order by f1 asc;

9)降序输出数据记录
select * from table_name order by f1 desc;

10)按指定的条件删除表中记录
sqlite >delete from <table_name> where <expression>;

可以看到 id=1003 的被删除;
不加判断条件则清空所有数据记录

11) 更新表中记录
sqlite > updata <table_name> set <f1=value1>,<f2=value2>... where <expression>;

可以看到 id=1003 的数据被更新。
再次提醒,未定义类型的记录默认是字符串,添加时一定要用 " "

12)在表中添加字段
sqlite > alter table <table> add column <field><type> defalut... ;

可以看到 sex 被添加进去;

13)删除指定字段(列)
step1: alter table info rename to temp; //备份为temp
step2: create table info (id, name, age); //创建新表
step3: inset into info select id, name, age from temp; //导出到新表


14)数据库备份
在命令提示符中使用.dump命令来导出完整的数据库在一个文本文件中,如图所示
sqlite3 test.db .dump > testDB.sql
上面命令将转换整个test.db数据库的内容到SQLite的语句中,并将其转储到ASCII文本文件中testDB.sql中。可以通过简单的方式从生成的testDB.sql恢复。
sqlite3 test.db < testDB.sql

三、SQLite 编程接口
1、打开sqlite 数据库 sqlite3_open
函数原型:
   int sqlite3_open(
const char *fileName, 
sqlite3 **ppDB
); 
函数功能:打开一个数据库;若该数据库文件不存在,则自动创建。打开或者创建数据库的命令会被缓存,直到这个数据库真正被调用的时候才会被执行。 
输入参数:fileName,待打开的数据库文件名称,包括路径,以’\0’结尾;特别说明:SQLite支持内存数据库,内存方式存储使用文件名“:memory:” 
输出参数ppDB,返回打开的数据库句柄;
返回值:执行成功返回SQLITE_OK,否则返回其他值;

2、关闭 sqlite 数据库sqlite3_close
 函数原型:
int sqlite3_close(sqlite3 *pDB);  
函数功能:关闭一个打开的数据库;
输入参数:pDB,打开的数据库句柄
输出参数:无 
返回值:执行成功返回SQLITE_OK,否则返回其他值

3、sqlite3_errmsg
函数原型:
const char *sqlite3_errmsg(sqlite3 *pDB);  
函数功能:获取最近调用的API接口返回的错误说明,这些错误信息UTF-8的编码返回,并且在下一次调用任何SQLiteAPI函数时被自动清除;
输入参数:pDB,打开的数据库句柄
输出参数:
返回值:错误说明的字符串指针

4、sqlite3_exec
函数原型:
int sqlite3_exec(
sqlite3 *pDB,
const char *sql, 
int (*callback)(void*, int, char**, char**),
void *para,
char **errMsg
);  
函数功能:编译和执行零个或多个SQL语句,查询的结果返回给回调函数callback
输入参数:
pDB, 数据库句柄;
sql,待执行的SQL语句字符串,以’\0’结尾;
callback, 回调函数,用来处理查询结果,
如果不需要回调(比如做insert或者delete操作时),可输入NULL;
para, 用户传入的参数,可以为NULL,该参数指针最终会被传给回调函数callback,
供用户在回调函数中使用, 是回掉函数的第一个参数;
输出参数:errMsg, 返回错误信息,注意是指针的指针。
返回值:执行成功返回SQLITE_OK,否则返回其他值。
5、回调函数sqlite_callback介绍
定义: 在一个函数里调用指定的另一个函数的方式(格式规定) 。
本质: 你想让别人的代码执行你的代码, 而别人的代码你又不能动。
函数格式:
int(*callback)(
void *para,
int columnCount,    
char **columnValue,
char **columnName
);  
函数功能:传给sqlite3_exec的回调函数,用来显示用户处理查询的结果。  
对每一条查询结果调用一次该回调函数。
输入参数:
para sqlite3_exec传入的第四个参数指针
column_size 查询到的这条记录有多少字段(即表头的列数)。
column_value 查询出来的数据都保存在这里。实际上是一维数组(不是二维数组)
column_name 表示结果字段的名称。(与column_value是对应的)
输出参数:无
返回值:执行成功返回SQLITE_OK,否则返回其他值。
1 :中断查找  
0 :继续列举查询到的数据   (SQLITE_OK

【回掉函数特殊说明】
通常情况下,callback在select操作中会使用到,尤其是处理每行记录数。
返回的结果每一行记录都会调用下“回掉函数”。
如果回掉函数返回了非0,那么sqlite3_exec将返回SQLITE_ABORT,并且之后的回掉函数也不会执行,同时未执行的子查询也不会继续执行。
对于更新、删除、插入等不需要回掉函数的操作,sqlite3_exec的第三、第四个参数可以传入0或NULL。

【例】:
回调函数的格式如下:  
int (*callback)(  
     void* pv,     /* 由 sqlite3_exec() 的第四个参数传递而来 */  
     int argc,        /* 表的列数 */  
     char** argv,     /* 指向查询结果的指针数组 */  
     char** col       /* 指向表头名的指针数组 */  
);  
示例表:  
+-----------------------------------+  
|  id  |  pic   |  data(16进制数据)  |  
|-----------------------------------|  
|   1  |  a.jpg |      00 00 00 ... |  
|-----------------------------------|  
|   2  |  b.jpg |     XX XX XX      |  
+-----------------------------------+  
对第一行数据:  
    argc=3 即 [0]...[2]  
    argv[0]="1", argv[1]="a.jpg", argv[2]="00 00 00..."(实际16进制数据,非这里显示的字符串形式)  
    col[0]="id", col[1]="pic", col[2]="data"  
说明】:  
sqlite3_exec() 的回调函数必须按照此格式,当然形参的名字任意。 
如果某列的数据类型不是char*, 则可以对结果执行相关的转换, 如:用atoi()把结果转换为整数(integer);
如果是二进制数据, 则可以直接强制类型转换, 如:(void*)argv[i] 。
该回调函数有两种返回值类型.  
1. 返回零 : sqlite3_exec()将继续执行查询.  (成功即返回SQLITE_OK)
2. 返回非零: sqlite3_exec()将立即中断查询, 且 sqlite3_exec() 将返回 SQLITE_ABORT。 
【示例】:  
     int i;  
     for(i=0; i<argc; i++)  
     {  
         printf("%s\t%s\n\n", col[i], argv[i]);  
     }  

下面是对数据库增删查改的简单实例练习 < sqlite3_IDSU.c >
#include <stdio.h>
#include <sqlite3.h>

int main(int argc, const char *argv[])
{
	sqlite3 *db;
	int ret = -1;
	ret = sqlite3_open("test.db",&db);
	if (0 != ret)
	{
		perror("open");
		return -1;
	}
	
	char *sql = "create table if not exists student (name text, age interger, id  interger);";
	char *errmsg;
	ret = sqlite3_exec(db, sql, NULL, NULL, &errmsg);
	if (0 != ret)
	{
		fprintf(stderr, "%s", sqlite3_errmsg(db));
		fprintf(stderr, "errmsg = %s",errmsg);
		return -1;
	}
	
	char sqlbuf[1024] = "\0";
	char name[128] = "\0";
	int age, id;
	
	//数据库 增加
	printf(">>数据库增加\n");
	printf("Please input your name: ");
	scanf("%s", name);
	printf("Please input your age: ");
	scanf("%d", &age);
	printf("Please input your id: ");
	scanf("%d", &id);
	
	sprintf(sqlbuf, "insert into student (name, age, id) values ('%s', '%d', '%d');", name, age, id);
	
	ret = sqlite3_exec(db, sqlbuf, NULL, NULL, &errmsg);
	if (0 != ret)
	{
		fprintf(stderr, "%s", sqlite3_errmsg(db));
		fprintf(stderr, "errmsg = %s", errmsg);
		return -1;
	}
	printf("数据库插入成功!\n");
	
	//数据库 删除
	printf(">>根据条件删除数据库\n");
	printf("Please input your id: ");
	scanf("%d",&id);
	
	sprintf(sqlbuf,"delete from student where id = %d", id);
	
	ret = sqlite3_exec(db, sqlbuf, NULL, NULL, &errmsg);
	if (0 != ret)
	{
		fprintf(stderr, "%s", sqlite3_errmsg(db));
		fprintf(stderr, "errmsg = %s", errmsg);
		return -1;
	}
	printf("数据库删除成功!\n");
		
	//数据库 查询
	printf(">>根据条件查询数据库\n");
	printf("Please input your name: ");
	scanf("%s",name);
	
	sprintf(sqlbuf, "select * from student where name = %s", name);
	
	ret = sqlite3_exec(db, sqlbuf, NULL, NULL, &errmsg);
	if (0 != ret)
	{
		fprintf(stderr, "%s", sqlite3_errmsg(db));
		fprintf(stderr, "errmsg = %s", errmsg);
		return -1;
	}
	printf("数据库查询成功!\n");
		
	//数据库 更改
	printf(">>更新数据库\n");
	printf("Please input your name: ");
	scanf("%s", name);
	printf("Please input your age: ");
	scanf("%d", &age);
	printf("Please input your id: ");
	scanf("%d", &id);
	
	sprintf(sqlbuf, "update student set age = %d, id = %d where name = '%s';", age, id, name);
	ret = sqlite3_exec(db, sqlbuf, NULL, NULL, &errmsg);
	if (0 != ret )
	{
		fprintf(stderr, "%s", sqlite3_errmsg(db));
		fprintf(stderr, "errmsg = %s", errmsg);
		return -1;
	}
	printf("数据库更改成功!\n");
		
	sqlite3_close(db);  //关闭数据库
	return 0;
}
------------------------------------------------------------------
下面是个回掉函数的实例:< sqlite_exec.c >
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sqlite3.h>

#define MAX  100

//回掉函数
int show_sql_result(
		void *argc, 
		int n_column, 
		char **column_value, 
		char **column_name
	)
{
	int i = 0;
	int param = *((int *)argc);
	printf("enter callback ---> param = %d, n_column = %d\n", param, n_column);
	
	for (i = 0; i < n_column; i++)
	{
		printf("%s\t", column_name[i]);
	}
	printf("\n------------------------------------\n");
	
	for (i = 0; i < n_column; i++)
	{
		printf("%s\t", column_value[i]);
	}
	printf("\n\n");
	
	return 0;
}

//sqlite3_exec
int exec_sql_string(char *sql_string, sqlite3 *db)
{
	char *errmsg = NULL;  //防止出现野指针
	
	int param = 100;
	
	printf("before sqlite3_exec()\n");
	if (SQLITE_OK != sqlite3_exec(
			db, 
			sql_string, 
			show_sql_result, 
			¶m,
			&errmsg))
	{
		if(NULL != errmsg)
		{
			fprintf(stderr, "Fail to exec sql(%s) : %s.\n", sql_string, errmsg);
			sqlite3_free(errmsg);
		}
		else
		{
			fprintf(stderr, "Fail to exec sql(%s) : %s.\n", sql_string, errmsg);
		}
		
		return -1;
	}
	printf("after sqlite3_exec()");
	
	return 0;
}

//主函数
int main(int argc, char *argv[])
{
	sqlite3 *db = NULL; 
	int result;
	char sql_buf[MAX];
	
	/* 判断命令行参数 */
	if (argc < 2)
	{
		fprintf(stderr, "usage : %s argv[1].\n", argv[0]);
		exit(EXIT_FAILURE);
	}
	
	result = sqlite3_open(argv[1], &db);   /* 打开数据库 */
	//判断打开结果
	if (SQLITE_OK != result)
	{
		if (NULL != db) 
		{  
            fprintf(stderr, "sqlite3_open %s : %s.\n",  
                argv[1], sqlite3_errmsg(db));  
        }   
        else 
		{  
            printf("error : failed to allocate memory for sqlite3!\n");  
        }  
          
        sqlite3_close(db); 
				
		exit(EXIT_FAILURE);
	}
	
	while (1)
	{
		printf("sqlite>");
		if (NULL == fgets(sql_buf, sizeof(sql_buf), stdin))
			continue;
		sql_buf[strlen(sql_buf) - 1] = '\0'; /* eat up the ending '\n' */
		
		if (0 == strncmp(sql_buf, ".quit", 5))
			break;
		exec_sql_string(sql_buf, db);     //
	}
	
	result = sqlite3_close(db);
	
	if (0 != result)
	{
		fprintf(stderr, "Fail to sqlite3_open %s : %s.\n", argv[1], sqlite3_errmsg(db));
		exit(EXIT_FAILURE);
	}
	
	exit(EXIT_SUCCESS);

}
7、sqlite3_get_table
函数原型:
int sqlite3_get_table(
sqlite *pDb, /* An open database */
const char *sql, /* SQL to be evaluated */
char ***pResult, /*Results written to a char *[] that points to*/
int *rowCount, /* Number of result rows written here */
int *columnCount, /*Number of result columns written here */
char **errMsg /* Error msg written here */
)
函数功能:执行SQL语句,通过一维数组返回结果:一般用于数据记录查询
输入参数:
pDb,打开的数据库句柄;
sql, 待执行的SQL语句字符串,以’\0’结尾;
输出参数:
rowCount, 查询出多少条记录(即查出多少行,不包括字段名那行);
columnCount, 查询出来的记录有多少字段(即有多少列)
errMsg, 返回错误信息
pResult, 查询结果,是由字符串组成的一维数组(不要以为是二维数组)。
它的内存布局是:第一行是字段名称,后面紧接着每个字段的值;
pResult 返回的字符串数量实际上是(*pnRow+1) * (*pnColumn),因为前(*pnColumn)个是字段名
返回值:执行成功返回SQLITE_OK,否则返回其他值。

8、关闭 sqlite 数据库sqlite3_free_table
函数原型:
void sqlite3_free_table(char **result);
函数功能:
输入参数:
输出参数: 
返回值:
9、sqlite3_get_table获取数据内存分布
内存分布(即pResult查询结果的内存布局):
从第0索引到第columnCount-1索引都是字段的名称,从第columnCount索引开始,后面都是字段的值。




下面是个sqlite3_free_table 函数的实例:
< sqlite3_get_table.c >
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sqlite3.h>

#define MAX 100

int exec_sql_string(char *sql_string, sqlite3 *db)
{
	char *errmsg, **dbResult;
	int nRow, nColumn;
	int result, i, j, index;
	
	result = sqlite3_get_table(
					db, 
					sql_string, 
					&dbResult, 
					&nRow, 
					&nColumn, 
					&errmsg);
	if (0 != result)
	{
		fprintf(stderr, "Fail to exec sql(%s) : %s.\n", sql_string, errmsg);
		return -1;
	}
	
	//字段名字
	for (j = 0; j < nColumn; j++)
	{
		printf("%s\t", dbResult[j]);
	}
	printf("\n");
	
	index = nColumn;  //从它开始是字段对应的值
	
	for (i = 0; i < nRow; i++)  //查询到总共记录个数
	{
		for (j = 0; j < nColumn; j++)
		{
			printf("%s\t", dbResult[index]);
			index++;
		}
		printf("\n");
	}
	
	//释放查询结果所分配的内存
	sqlite3_free_table(dbResult);
	
	return 0;
	
}


int main(int argc, char *argv[])
{
	sqlite3 *db = NULL;
	int result;
	char sql_buf[MAX];
	
	if (argc < 2)
	{
		fprintf(stderr,"usage : %s argv[1].\n", argv[0]);
		exit(EXIT_FAILURE);
	}
	
	result = sqlite3_open(argv[1], &db);
	if (result != SQLITE_OK)
	{
		fprintf(stderr, "Fail to sqlite3_open %s : %s.\n",argv[1], sqlite3_errmsg(db));
		exit(EXIT_FAILURE);
	}
	
	while (1)
	{
		printf("sqlite>");
		if (NULL == fgets(sql_buf, sizeof(sql_buf), stdin))
			continue;
		sql_buf[strlen(sql_buf) - 1] = '\0';
		
		if (0 == strncmp(sql_buf, ".quit", 5))
			break;
		
		exec_sql_string(sql_buf, db);
		
		result = sqlite3_close(db);
		if (result != 0)
		{
			fprintf(stderr, "Fail to sqlite3_open %s : %s.\n",argv[1], sqlite3_errmsg(db));
			exit(EXIT_FAILURE);
		}
	}	
	exit(EXIT_SUCCESS);
	

}

------------------------------------------------------------------

<sqlite3_get_table使用举例.c>

//sqlite3_get_table使用举例 
 
void GetTable()
{
	sqlite3 * db;
	int result;
	char * errmsg = NULL;
	char **dbResult;         //是 char ** 类型,两个*号
	int nRow, nColumn;
	int i , j;
	int index; 
	
	result = sqlite3_open( “Dcg_database.db”, &db );
	
	if(SQLITE_OK != result )
	{
		return -1;          //数据库打开失败
	}
	
	//数据库操作代码
	//假设前面已经创建了 MyTable_1 表
	//开始查询,传入的 dbResult 已经是 char **,这里又加了一个 & 取地址符,传递进去的就成了 char ***
	result = sqlite3_get_table( 
				db, 
				“select * from MyTable_1”, 
				&dbResult, 
				&nRow, 
				&nColumn, 
				&errmsg );
				
	if( SQLITE_OK == result )
	{
		//查询成功
		index = nColumn;     //前面说过 dbResult 前面第一行数据是字段名称,从 nColumn 索引开始才是真正的数据
		printf( “查到%d条记录\n”, nRow );
		
		for( i = 0; i < nRow ; i )
		{
			printf( “第 %d 条记录\n”, i 1 );
			for( j = 0 ; j < nColumn; j )
			{
				printf( “字段名:%s ?> 字段值:%s\n”, dbResult[j], dbResult [index] );
				index; 
				// dbResult 的字段值是连续的,
				//从第0索引到第 nColumn - 1索引都是字段名称,
				//从第 nColumn 索引开始,后面都是字段值,
				//它把一个二维的表(传统的行列表示法)用一个扁平的形式来表示
			}
			printf( “-------\n” );
		}
	}
	
	//到这里,不论数据库查询是否成功,都释放 char** 查询结果,使用 sqlite 提供的功能来释放
	sqlite3_free_table( dbResult );
	
	//关闭数据库
	sqlite3_close( db );
	return 0;
	}
}

------------------------------------------------------------------

< sqlite3_get.c >

/*************************************************************************
	> File Name: sqlite3_open.c
	> Author: Zhang
	> Mail:  
	> Created Time: 2017年06月08日 星期四 16时32分40秒
 ************************************************************************/
#include <stdio.h>
#include <sqlite3.h>

int main(int argc, const char **argv)
{
	sqlite3 *db;
	int ret = -1;
	char sqlbuf[1024] = "\0";
	char name[128] = "\0";
	int age, id;
	char **result;
	int nrow, ncolumn;
	char *errmsg;
	int i, j;

	ret = sqlite3_open("test.db", &db);
	if(ret != 0)
	{
		perror("open");
		return -1;
	}

	sprintf(sqlbuf, "select * from student;");
	ret = sqlite3_get_table(db, sqlbuf, &result, &nrow, &ncolumn, &errmsg);
	if(0 != ret)
	{
		fprintf(stderr, "get_table failed:%s", errmsg);
		return -1;
	}

	for(i = 0; i < ncolumn; i++)
	{
		printf("%8s ", result[i]);
	}
	printf("\n-----------------------------------------------------\n");
	for(i = 1; i <= nrow; i++)
	{
		for(j = 0; j < ncolumn; j++)
		{
			printf("%8s ", result[i*ncolumn+j]);
		}
	}
	printf("\n");

	sqlite3_free_table(result);

	sqlite3_close(db);
	return 0;
}

------------------------------------------------------------------

< 3_p.c >

#include <stdio.h>
#include <stdlib.h>
/* 
 * 这个测试程序主要是为了测试sqlite_get_table中三级指针的作用
 * 这边使用三级指针主要是为了传递一个二级指针的地址
 * 这个二级指针应实际指向的应该时一个(指针数组)
 * */
void fun(char ***p, int column, int row)
{
	/*
	 * 三级指针p存放的是二级指针的地址,*p代表二级指针的内容即
	 * 一级指针的地址(指针数组的首地址)
	 * (**p)代表一级指针的内容即字符串的首地址
	 * */
	*p = (char **)malloc(sizeof(*p) * column * row);
	/*
	 *这边malloc申请的空间应当是指针数组的空间
	 *使用*p(二级指针)指向malloc 返回的首地址
	 *注意强制类型转换成二级指针
	 * */

	**p = "name";
	*(*p+1) = "id";
	*(*p+2) = "lu";
	*(*p+3) = "1";
	printf("%p\n",*p);
	printf("%p\n",&(**p));
	printf("%p\n",&(*(*p+1)));
	printf("%p\n",&(*(*p+2)));
	return ;
}
int main(int argc, const char *argv[])
{
	char **p;
	int column = 2,row = 3;
	fun(&p, column, row);
	printf("%s\n",p[0]);
	printf("%s\n",p[1]);  //?  0x1d91018
	printf("%s\n",p[2]);  //?  0x1d91020
	free(p);
	return 0;
}


//  运行结果
//     allure@ubuntu:~/Jeff/SQLite$ ./3_p

//     0x1d91010
//     0x1d91010
//     0x1d91018
//     0x1d91020
//     name
//     id
//     lu


#include <stdio.h>
#include <stdlib.h>
/* 
 * 這個測試程序主要是爲了測試sqlite_get_table中三級指針的作用
 * 這邊使用三級指針主要是爲了傳遞一個二級指針的地址
 * 這個二級指針應實際指向的應該時一個(指針數組)
 * */
void fun(char ***p, int column, int row)
{
	/*
	 * 三級指針p存放的是二級指針的地址,*p代表二級指針的內容即
	 * 一級指針的地址(指針數組的首地址)
	 * (**p)代表一級指針的內容即字符串的首地址
	 * */
	*p = (char **)malloc(sizeof(*p) * column * row);
	/*
	 *這邊malloc申請的空間應當是指針數組的空間
	 *使用*p(二級指針)指向malloc 返回的首地址
	 *注意強制類型轉換成二級指針
	 * */

	**p = "name";
	*(*p+1) = "id";
	*(*p+2) = "lu";
	*(*p+3) = "1";
	printf("%p\n",*p);
	printf("%p\n",&(**p));
	printf("%p\n",&(*(*p+1)));
	printf("%p\n",&(*(*p+2)));
	return ;
}
int main(int argc, const char *argv[])
{
	char **p;
	int column = 2,row = 3;
	fun(&p, column, row);
	printf("%s\n",p[0]);
	printf("%s\n",p[1]);  //?  0x1d91018
	printf("%s\n",p[2]);  //?  0x1d91020
	free(p);
	return 0;
}


//  运行结果
//     allure@ubuntu:~/Jeff/SQLite$ ./3_p

//     0x1d91010
//     0x1d91010
//     0x1d91018
//     0x1d91020
//     name
//     id
//     lu


















查看评论

《C语言/C++学习指南》数据库篇(MySQL& sqlite)

一部使用C语言/C++进行 MySQL & sqlite 数据库开发的教程
  • 2016年03月01日 20:58

嵌入式数据库sqlite 的简单使用

sqlite嵌入式数据库
  • wang735164515
  • wang735164515
  • 2016-09-29 14:04:15
  • 895

SQLite3嵌入式数据库arm+linux移植

SQLite数据库介绍 SQLite数据库是一种嵌入式数据库,他的目标是尽量简单,因此它抛弃了传统企业级数据库的种种复杂特性,只实现对于数据库而言的必备的功能。 尽管简单性是SQLit...
  • yangxuan12580
  • yangxuan12580
  • 2016-05-10 17:58:07
  • 1991

Java与嵌入式数据库SQLite的结合

      最近研究了一下嵌入式数据库,并使用Java与一个叫做SQLite的轻量级数据库结合写了个小程序,这个过程中也获得了不少经验,下面来总结一下。       本来是决定用Flex写的,因为它做...
  • xinem
  • xinem
  • 2009-01-27 22:00:00
  • 7302

嵌入式中的数据库sqlite移植步骤

http://www.sqlite.org/download.html; SQLite数据库的安装和移植 (1)下载数据库sqlite-autoconf-3081101.tar.gz。 (2)解...
  • u014213012
  • u014213012
  • 2016-06-25 09:09:32
  • 666

sqlite3数据库交叉编译并移植到嵌入式开发环境步骤

一、首先到http://www.sqlite.org/download.html下载linux版本的源码:sqlite-autoconf-3130000.tar.gz。 二、解压:tar xvzf s...
  • u010312436
  • u010312436
  • 2016-06-21 17:22:55
  • 4433

嵌入式数据库SqLite3使用入门

    最近一直在开发一个基于net-snmp的网络设备管理程序,由于该项目规模比较庞大,需要在潜入式系统里移植数据库,考虑该系统的高效和硬件资源,最后选择了SqLite3作为数据引擎,下面简要阐述一...
  • bachelorkang
  • bachelorkang
  • 2007-12-01 11:28:00
  • 645

Linux嵌入式之————Linux下安装SQLite3数据库

一、安装sqlite3 1、下载最新版的sqlite3,网址:http://www.sqlite.org/download.html 下载sqlite-autoconf-3130000.tar.gz...
  • huangan_xixi
  • huangan_xixi
  • 2016-05-24 22:08:57
  • 988

嵌入式SQLite数据库架构和设计

SQLite既是一个数据库,一个程序库,一个命令行工具,也是一个学习关系型数据库的很好的工具。确实有很多途径可以把它使用到内嵌环境、网站、操作系统服务、脚本语言和应用程序。对于程序员来说,SQLite...
  • swingwang
  • swingwang
  • 2017-05-30 20:19:22
  • 1809

JAVA在SQLite_嵌入式数据库中的应用

  • 2013年04月10日 10:25
  • 303KB
  • 下载
    个人资料
    等级:
    访问量: 520
    积分: 157
    排名: 110万+
    文章存档