Linux下C语言字符串操作之分割字符串总结
2016-02-22 21:37
393 查看
http://biancheng.dnbcw.info/c/452773.html
http://biancheng.dnbcw.info/c/452774.html
http://www.oschina.net/code/snippet_2325404_47570
/article/1950797.html
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 <stdio.h>
2. #include <string.h>
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 <stdio.h>
2. #include <string.h>
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++|Linux下C程序访问mysql数据库
· c/c++|Linux下C语言字符串操作之分割字符串
· c/c++|向量空间模型——计算文本(英文)相似度
· c/c++|Linux下C语言字符串操作之连接和查找
· c/c++|C语言之预处理命令
Linux下C语言字符串操作之分割字符串来源网络,如有侵权请告知,即处理!
废话不多说,直接上代码:
1. #include <stdio.h>
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<num_fields;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++|Linux下C程序访问mysql数据库
· c/c++|Linux下C语言字符串操作之分割字符串
· c/c++|向量空间模型——计算文本(英文)相似度
· c/c++|Linux下C语言字符串操作之连接和查找
Linux下C程序访问mysql数据库来源网络,如有侵权请告知,即处理!
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <dirent.h>
#include <pwd.h>
#include <time.h>
#include <grp.h>
#include <mysql/mysql.h>
#define N 7
MYSQL my_sql;
DIR * my_dir = NULL;
char *args
={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
= (char*)malloc(256);
if(!args
)
{
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函数,我非常喜欢,在java、c#和python中都有,很方便,不用担心踩地雷,但是C/CPP中,就没有了,这点比较遗憾。
如果要处理一个字符串型的“192.168.1.254”,想把每个字段都分开,怎么办呢,C标准库中有函数strtok()的实现,可以一用。
[cpp] view plaincopy
1. #include<stdio.h>
2. #include<stdlib.h>
3. #include<string.h>
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调用中看到,因此linux用strsep来替换strtok了,我在linux2.6.22的源码/lib/string.c和linux-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 <asm-xx/string.h>
10. *
11. * These are buggy as well..
12. *
13. * * Fri Jun 25 1999, Ingo Oeser <ioe@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 <jason@topic.com.au>,
18. * Matthew Hawkins <matt@mh.dropbear.id.au>
19. * - Kissed strtok() goodbye
20. */
因为strsep是线程安全的,并且速度上更快一些,所以采用strsep来替换strtok,接下来我会试一试strsep。在这里感慨下,没事的时候或者写程序的时候,用man和查看源码的方式,能学到很多基本的知识,比如内核源码的lib文件夹下,linux内核使用的rbtree结构,还有lib文件夹的string.c,include下的string.h里的各种strcpy,strcat等基本函数的实现,都是非常经典而且久经考验的。
在strtok使用的代码里,有两处很有意思。
其中一个,修改第7行,如下所示:
[cpp] view plaincopy
1. #include<stdio.h>
2. #include<stdlib.h>
3. #include<string.h>
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,通过gdb和core文件来看,程序崩溃在了
[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优秀很多,VS的CPP支持是最全面的,可以这么说。好多CPP的作者啦,大牛啦,都是M$的VC组的,好牛逼的地方。
另外在改一处,这次只改第16行,将printf语句注释掉,代码如下:
[cpp] view plaincopy
1. #include<stdio.h>
2. #include<stdlib.h>
3. #include<string.h>
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<stdio.h>
2. #include<stdlib.h>
3. #include<string.h>
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. }
用法也差不多。
http://biancheng.dnbcw.info/c/452774.html
http://www.oschina.net/code/snippet_2325404_47570
/article/1950797.html
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 <stdio.h>
2. #include <string.h>
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 <stdio.h>
2. #include <string.h>
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++|Linux下C程序访问mysql数据库
· c/c++|Linux下C语言字符串操作之分割字符串
· c/c++|向量空间模型——计算文本(英文)相似度
· c/c++|Linux下C语言字符串操作之连接和查找
· c/c++|C语言之预处理命令
Linux下C语言字符串操作之分割字符串来源网络,如有侵权请告知,即处理!
废话不多说,直接上代码:
1. #include <stdio.h>
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<num_fields;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++|Linux下C程序访问mysql数据库
· c/c++|Linux下C语言字符串操作之分割字符串
· c/c++|向量空间模型——计算文本(英文)相似度
· c/c++|Linux下C语言字符串操作之连接和查找
Linux下C程序访问mysql数据库来源网络,如有侵权请告知,即处理!
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include <sys/stat.h>
#include <sys/types.h>
#include <stdlib.h>
#include <errno.h>
#include <fcntl.h>
#include <dirent.h>
#include <pwd.h>
#include <time.h>
#include <grp.h>
#include <mysql/mysql.h>
#define N 7
MYSQL my_sql;
DIR * my_dir = NULL;
char *args
={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
= (char*)malloc(256);
if(!args
)
{
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函数,我非常喜欢,在java、c#和python中都有,很方便,不用担心踩地雷,但是C/CPP中,就没有了,这点比较遗憾。
如果要处理一个字符串型的“192.168.1.254”,想把每个字段都分开,怎么办呢,C标准库中有函数strtok()的实现,可以一用。
[cpp] view plaincopy
1. #include<stdio.h>
2. #include<stdlib.h>
3. #include<string.h>
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调用中看到,因此linux用strsep来替换strtok了,我在linux2.6.22的源码/lib/string.c和linux-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 <asm-xx/string.h>
10. *
11. * These are buggy as well..
12. *
13. * * Fri Jun 25 1999, Ingo Oeser <ioe@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 <jason@topic.com.au>,
18. * Matthew Hawkins <matt@mh.dropbear.id.au>
19. * - Kissed strtok() goodbye
20. */
因为strsep是线程安全的,并且速度上更快一些,所以采用strsep来替换strtok,接下来我会试一试strsep。在这里感慨下,没事的时候或者写程序的时候,用man和查看源码的方式,能学到很多基本的知识,比如内核源码的lib文件夹下,linux内核使用的rbtree结构,还有lib文件夹的string.c,include下的string.h里的各种strcpy,strcat等基本函数的实现,都是非常经典而且久经考验的。
在strtok使用的代码里,有两处很有意思。
其中一个,修改第7行,如下所示:
[cpp] view plaincopy
1. #include<stdio.h>
2. #include<stdlib.h>
3. #include<string.h>
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,通过gdb和core文件来看,程序崩溃在了
[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优秀很多,VS的CPP支持是最全面的,可以这么说。好多CPP的作者啦,大牛啦,都是M$的VC组的,好牛逼的地方。
另外在改一处,这次只改第16行,将printf语句注释掉,代码如下:
[cpp] view plaincopy
1. #include<stdio.h>
2. #include<stdlib.h>
3. #include<string.h>
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<stdio.h>
2. #include<stdlib.h>
3. #include<string.h>
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 uart
- CentOS 没有root权限下Caffe 安装的小问题
- Linux中如何添加/删除FTP用户并设置权限
- Linux X11 程序下都有神马
- 学习Linux计划书
- 《超级优化Linux远程SSH连接》
- gitlab install centos 详细步骤!
- linux makefile详解?
- 在Linux飞控环境下使用MAVLink教程
- linux Native AIO的使用
- 第2章 Linux如何学习
- linux环境变量PS1设置完整版附带颜色
- arm-linux-gcc工具链安装FreeTpye 编译的支持
- 《Linux操作系统编译构建指南》
- QT5-控件-QLineEdit-文本输入控件,用来输入密码什么的还不错,可以和Linux登录一样不移动光标哦
- Linux下的消息队列示例
- 使用synergy软件使两台电脑共用一个鼠标和键盘
- 查看网卡流量
- Centos 执行top命令详细解读
- Linux Grep命令详解