Linux下C语言字符串操作之分割字符串总结

http://biancheng.dnbcw.info/c/452773.html

http://biancheng.dnbcw.info/c/452774.html

http://www.oschina.net/code/snippet_2325404_47570

 

http://blog.csdn.net/bg2bkk/article/details/37569555

 

 

c/cpp中如何分割字符串,类似于split的功能

 

1,分割字符串
char *strtok(char *str, const char *delim);
功能:分解字符串为一组字符串。str为要分解的字符串,delim为分隔符字符串。实质上的处理是,strtok在str中查找包含在delim中的字符并用NULL(’\0′)来替换,直到找遍整个字符串。
说明:首次调用时,str指向要分解的字符串,之后再次调用要把str设成NULL。strtok在str中查找包含在delim中的字符并用NULL(’\0′)来替换,直到找遍整个字符串。
返回值:从str开头开始的一个个被分割的串。当没有被分割的串时则返回NULL。所有delim中包含的字符都会被滤掉,并将被滤掉的地方设为一处分割的节点。
示例:

1.      #include

2.      #include

3.       

4.      int main(){

5.          //id,姓名,语文,数学,英语

6.          charstr[]="2,张三,89,99,66";

7.          char*token=strtok(str,",");

8.          while(token!=NULL){

9.              printf("%s\t",token);

10.          token=strtok(NULL,",");

11.      } 

12.      printf("\n");

13.      return 0;

14.  }

示例程序输出:

1.      2   张三  89  99  66

说明:str参数必须设置为数组的形式,而不是字符串常量(如:char *str="2,张三,89,99,66";),因为strtok在执行过程中会对str进行修改,必须保证str是可写的。

2,分割字符串(还是分割字符串)
char *strsep(char **stringp, const char *delim);

1.      #include

2.      #include

3.       

4.      int main(){

5.          //id,姓名,语文,数学,英语

6.          charstr[]="2,张三,89,99,66";

7.          //str是一个指针常量,而strsep的第一个参数需要一个指向指针的指针,所以不能对str做取地址操作,

8.          //这里再定义一个指针变量就可以取地址操作了。否则会出现段错误。

9.          char *strv=str;

10.      char*token=strsep( &strv,",");

11.      while(token!=NULL){

12.          printf("%s\t",token);

13.          token=strsep( &strv,",");

14.      } 

15.      printf("\n");

16.      return 0;

17.  }

说明:此函数也会修改第一个参数的内容,所以必须保证提供的不是字符串常量。


相关资料:

·        c/c++LinuxC程序访问mysql数据库

·        c/c++LinuxC语言字符串操作之分割字符串

·        c/c++向量空间模型——计算文本(英文)相似度

·        c/c++LinuxC语言字符串操作之连接和查找

·        c/c++C语言之预处理命令

Linux下C语言字符串操作之分割字符串来源网络,如有侵权请告知,即处理!

 

 

 

废话不多说,直接上代码:

1.      #include

2.      #include <mysql/mysql.h>

3.       

4.      #define HOST "192.168.56.2"

5.      #define DB "webdevtest"

6.      #define USER "webdev"

7.      #define PWD "webdev"

8.      #define PORT 3306

9.       

10.  int main(){

11.      MYSQL mysql;

12.   

13.      //连接之前得先初始化

14.      mysql_init(&mysql);

15.   

    //连接mysql数据库

1.          if(!mysql_real_connect(&mysql,HOST,USER,PWD,DB,PORT,NULL,0)){

2.              printf("连接数据库发生错误!\n");

3.              return-1;

4.          }

5.          printf("连接数据库成功!\n");

6.       

7.          //设置查询时的编码

8.          mysql_query(&mysql,"setnames utf8");

9.       

    //执行查询语句   
    char *sql="select * from test_sell_records limit 20";

1.          if(mysql_query(&mysql,sql)!=0){

2.              printf("执行mysql语句发生错误!\n");

3.              mysql_close(&mysql);

4.              return-1;

5.          }

6.          //获取结果集

7.          MYSQL_RES*result=mysql_store_result(&mysql);

8.          unsigned inti,num_fields;

9.          //获取字段数

10.      num_fields=mysql_num_fields(result);

1.          //循环打印出各行

2.          MYSQL_ROW row;

3.          while((row=mysql_fetch_row(result))!=NULL){

4.              for(i=0;i

5.                  printf("%s\t",row[i]);

6.              }

7.              printf("\n");

8.          }

9.       

10.      //释放结果集

11.      mysql_free_result(result);

12.      //关闭连接

13.      mysql_close(&mysql);

14.      return 0;

15.  }

以上用到的函数为:
mysql_init()
mysql_real_connect()
mysql_query()
mysql_store_result()
mysql_num_fields()
mysql_fetch_now()
mysql_free_result()
mysql_close()

还有,编译的时候不要忘记了添加 -lmysqlclient 参数:

1.      gcc -o mysql_test mysql_test.c-lmysqlclient

在Linux下用C语言开发mysql客户端程序,需要安装mysql开发包,请参考:
http://blog.chinaunix.net/uid-20769015-id-3540362.html

mysql官方C API参考:http://dev.mysql.com/doc/refman/5.1/en/c-api-functions.html

相关资料:

·        c/c++LinuxC程序访问mysql数据库

·        c/c++LinuxC语言字符串操作之分割字符串

·        c/c++向量空间模型——计算文本(英文)相似度

·        c/c++LinuxC语言字符串操作之连接和查找

Linux下C程序访问mysql数据库来源网络,如有侵权请告知,即处理!

 

 

 

 

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#include

#define N 7

MYSQL my_sql;

DIR * my_dir = NULL;

char *args[N] ={NULL,NULL,NULL,NULL,NULL,NULL,NULL};

void read_dir(char *);

void connect_mysql();

void set_work();

void get_file_infor(const char *,char *);

void write_mysql();

int main(int argc,char *argv[])

{

   if(argc != 2)

    {

       fprintf(stderr,"arguments is not two!\n");

       return -1;

   }else

    {

       connect_mysql();

       set_work();

       read_dir(argv[1]);

    }

   mysql_close(&my_sql);

   return EXIT_SUCCESS;

}

 

void read_dir(char *dirname)

{

   struct dirent * dir;

   int n = 0;

   my_dir = opendir(dirname);

   if(!my_dir)

    {

       fprintf(stderr,"open dir fail %s\n",strerror(errno));

   }else

    {

        

       while((dir = readdir(my_dir)))

       {

           if(strcmp(".",dir->d_name)&&strcmp("..",dir->d_name))

           {

                for(;n < N;n++)

                {

                    args[n] = (char*)malloc(256);

                   if(!args[n])

                    {

                       fprintf(stderr,"malloc fail\n");

                        closedir(my_dir);

                        exit(-1);

                    }

                }

                args[0] = dir->d_name;

               get_file_infor(dir->d_name,dirname);

                printf("\n");

           }

        

       }

 

    

    }

}

 

void connect_mysql()

{

   mysql_init(&my_sql);

   if(mysql_real_connect(&my_sql,"localhost","ma","123456ma",

                            "student",0,0,0))

    {

       printf("connect mysql success\n");

   }else{

       fprintf(stderr,"connect mysql fail%s",mysql_error(&my_sql));

       exit(-1);

    }

}

 

void set_work()

{

   int res1,res2;

   res1 =mysql_query(&my_sql,"set names utf8");

   res2 = mysql_query(&my_sql,"use student");

   if(res1)

    {

       fprintf(stderr,"set character fail!%s\n",mysql_error(&my_sql));

   }else

          printf("set character success !\n");

   if(res2)

    {

       fprintf(stderr,"use student database fail !%s\n",mysql_error(&my_sql));

   }else

          printf("use database success !\n");

 

}

 

void write_mysql()

{

   printf("\t#######start write into mysql#######\n");

   int res ;

   char * infor = (char *)malloc(512);

   memset(infor,0,512);

   sprintf(infor,"INSERT INTOFile(filename,filemode,filelink,fileown,filegroup,filetime,filesize) VALUES('%s','%s',%s,'%s','%s','%s',%s)",args[0],args[1],args[2],args[3],args[4],args[5],args[6]);

    infor[strlen(infor)]= '\0';

// printf("%s\n",infor);

   res = mysql_query(&my_sql,infor);

   if(!res)

          printf("Insert %lu rows\n",(unsignedlong)mysql_affected_rows(&my_sql));

   else

          fprintf(stderr,"Insert data fail%s\n",mysql_error(&my_sql));

 

}

 

void get_file_infor(const char *path1,char*arg)

{

   struct stat  filestat;

   int n = 0;

   char *path = (char *)malloc(256);

   memset(path,0,256);

   sprintf(path,"%s/%s",arg,path1);

   if(lstat(path,&filestat))

    {

       fprintf(stderr,"get inode information fail%s\n",strerror(errno));

       return;

   }else

    {

        switch(filestat.st_mode & S_IFMT)

       {

           case S_IFBLK: args[1]  ="block";break;

           case S_IFCHR: args[1] = "character";break;

           case S_IFDIR: args[1] = "directory";break;

           case S_IFIFO: args[1] = "FIFO/pipe";break;

           case S_IFLNK: args[1] = "symlink";break;

           case S_IFREG: args[1] = "regularfile";break;

           case S_IFSOCK: args[1] = "socket";break;

           default: args[1] = "unknown";

        

       }

       sprintf(args[2],"%ld ",(unsigned long)filestat.st_nlink);

       struct passwd * passwd = getpwuid(filestat.st_uid);

       sprintf(args[3],"%s ",passwd->pw_name);

       struct group * group = getgrgid(filestat.st_gid);

       sprintf(args[4],"%s ",group->gr_name);

       struct tm *filetime = gmtime(&(filestat.st_mtime));

       sprintf(args[5],"%d/%d/%d",filetime->tm_year+1900,filetime->tm_mon,filetime->tm_mday);

       sprintf(args[6],"%lld",filestat.st_size);

       write_mysql();

    }

 

}

 

python中,如果要求当前时间的unix时间戳,我特别喜欢这么用:

[python] view plaincopy

1.  import time  

2.  timestr = time.time()  

3.  timestamp = int(timestr.split('.')[0])  


这里的split函数,我非常喜欢,在javac#python中都有,很方便,不用担心踩地雷,但是C/CPP中,就没有了,这点比较遗憾。

如果要处理一个字符串型的“192.168.1.254”,想把每个字段都分开,怎么办呢,C标准库中有函数strtok()的实现,可以一用。

[cpp] view plaincopy

1.  #include  

2.  #include  

3.  #include  

4.    

5.  int main()  

6.  {  

7.      char ip_str[] = "192.168.1.250";  

8.      char *ip_arr[4] ;  

9.      char * s = strtok(ip_str, ".");  

10.     int i=0;  

11.     while(s)  

12.     {  

13.         ip_arr[i] = s;  

14.         s = strtok(NULL, ".");  

15.         i++;  

16. //      printf("%s\n",s);  

17.     }  

18.   

19.     for(i=0; i<4; i++)  

20.         printf("%s\n",ip_arr[i]);  

21. }  


在这里,strtok是非线程安全的,这点也可以在程序的第二次strtok调用中看到,因此linuxstrsep来替换strtok了,我在linux2.6.22的源码/lib/string.clinux-3.3中同文件中,c文件开头就是这样一段话:

[html] view plaincopy

1.  /*  

2.   *  linux/lib/string.c  

3.   *  

4.   *  Copyright (C) 1991, 1992  Linus Torvalds  

5.   */  

6.    

7.  /*  

8.   * stupid library routines.. The optimized versions should generally be found  

9.   * as inline code in /string.h>  

10.  *  

11.  * These are buggy as well..  

12.  *  

13.  * * Fri Jun 25 1999, Ingo Oeser @informatik.tu-chemnitz.de>  

14.  * -  Added strsep() which will replace strtok() soon (because strsep() is  

15.  *    reentrant and should be faster). Use only strsep() in new code, please.  

16.  *  

17.  * * Sat Feb 09 2002, Jason Thomas @topic.com.au>,  

18.  *                    Matthew Hawkins @mh.dropbear.id.au>  

19.  * -  Kissed strtok() goodbye  

20.  */  




因为strsep是线程安全的,并且速度上更快一些,所以采用strsep来替换strtok,接下来我会试一试strsep。在这里感慨下,没事的时候或者写程序的时候,用man和查看源码的方式,能学到很多基本的知识,比如内核源码的lib文件夹下,linux内核使用的rbtree结构,还有lib文件夹的string.cinclude下的string.h里的各种strcpystrcat等基本函数的实现,都是非常经典而且久经考验的。

strtok使用的代码里,有两处很有意思。

其中一个,修改第7行,如下所示:

[cpp] view plaincopy

1.  #include  

2.  #include  

3.  #include  

4.    

5.  int main()  

6.  {  

7.      char *ip_str = "192.168.1.250";  

8.      char *ip_arr[4] ;  

9.      char * s = strtok(ip_str, ".");  

10.     int i=0;  

11.     while(s)  

12.     {  

13.         ip_arr[i] = s;  

14.         s = strtok(NULL, ".");  

15.         i++;  

16. //      printf("%s\n",s);  

17.     }  

18.   

19.     for(i=0; i<4; i++)  

20.         printf("%s\n",ip_arr[i]);  

21. }  


char ip_str[] ="192.168.1.250";改为char *ip_str = "192.168.1.250";就会core dump,通过gdbcore文件来看,程序崩溃在了

[cpp] view plaincopy

1.  Program terminated with signal 11, Segmentation fault.  

2.  #0  strtok () at ../sysdeps/i386/i686/strtok.S:245  

3.  245      movb $0, (%edx) /* Terminate string.  */  

4.  (gdb) where  

5.  #0  strtok () at ../sysdeps/i386/i686/strtok.S:245  

6.  #1  0x0804841e in main () at test.c:9  

而这段代码在VS下是没有问题的,所以这个原因需要找一下。

这个原因找到了,在链接http://www.cnblogs.com/longzhao1234/archive/2012/05/31/2528317.html

通过阅读源代码,因为函数内部会修改原字符串变量,所以传入的参数不能是不可变字符串(即文字常量区)。
char *tokenremain ="abcdefghij"//编译时为文字常量,不可修改。
strtok(tokenremain,"cde");
strsep(&tokenremain,"cde");
编译通过,运行时会报段错误。

VS在很多情况下要比GCC优秀很多,VSCPP支持是最全面的,可以这么说。好多CPP的作者啦,大牛啦,都是M$VC组的,好牛逼的地方。

另外在改一处,这次只改第16行,将printf语句注释掉,代码如下:

[cpp] view plaincopy

1.  #include  

2.  #include  

3.  #include  

4.    

5.  int main()  

6.  {  

7.      char ip_str[] = "192.168.1.250";  

8.      char *ip_arr[4] ;  

9.      char * s = strtok(ip_str, ".");  

10.     int i=0;  

11.     while(s)  

12.     {  

13.         ip_arr[i] = s;  

14.         s = strtok(NULL, ".");  

15.         i++;  

16.         printf("%s\n",s);  

17.     }  

18.   

19.     for(i=0; i<4; i++)  

20.         printf("%s\n",ip_arr[i]);  

21. }  


又崩溃了,我也整个人都不好了。

分析core文件,出错如下:

[cpp] view plaincopy

1.  Program terminated with signal 11, Segmentation fault.  

2.  #0  __strlen_ia32 () at ../sysdeps/i386/i586/strlen.S:99  

3.  99   movl (%eax), %ecx /* get word (= 4 bytes) in question */  

4.  (gdb) where  

5.  #0  __strlen_ia32 () at ../sysdeps/i386/i586/strlen.S:99  

6.  #1  0x00b9ddd5 in _IO_puts (str=0x0) at ioputs.c:37  

7.  #2  0x0804846b in main () at test.c:16  

令人欣慰的是,VS在这句也崩了。

根据core文件的提示,在#0处,在strlen函数这里崩溃了,我判断,是strtok阶段字符数组到最后,要在printf("%s\n",s);处打印时,由于没有'\0'符号,所以缓冲区无法截断,最后溢出导致printf崩溃,所以我重新声明一个长度为sizeof(ip_str)+1的字符数组,将ip_str复制进去,并将最后一个字符置为'\0',代表字符结束,结果依然崩溃。

如果我把printf("%s\n",s);改为printf("%s\t",s);,因为printf是打印到标准输出中,而标准输出是行缓冲的,对于'\n',代表行缓冲结束,需要输出,如果我不让他输出,会怎样?

打印结果为:

[cpp] view plaincopy

1.  168 1   250 (null)    

好吧我也不知道是什么了,而且这个结果与是否有'\0'符号无关。

 

这两个地方一定要找出来问题,嗯。

 

接下来我们看看strsep的用法吧

[cpp] view plaincopy

1.  #include  

2.  #include  

3.  #include  

4.    

5.  int main()  

6.  {  

7.      char ip_str[] = "192.168.1.250";  

8.      char *p = ip_str;  

9.      char *ip_arr[4] ;  

10.     char * s = strsep(&p, ".");  

11.     int i=0;  

12.     while(s)  

13.     {  

14.         ip_arr[i] = s;  

15.         s = strsep(&p, ".");  

16.         i++;  

17. //      printf("%s\n",s);  

18.     }  

19.   

20.     for(i=0; i<4; i++)  

21.         printf("%s\n",ip_arr[i]);  

22. }  


用法也差不多。

你可能感兴趣的:(Linux,C)