1. 程式人生 > >c/cpp中如何分割字串,類似於split的功能

c/cpp中如何分割字串,類似於split的功能

在python中,如果要求當前時間的unix時間戳,我特別喜歡這麼用:

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

這裡的split函式,我非常喜歡,在java、c#和python中都有,很方便,不用擔心踩地雷,但是C/CPP中,就沒有了,這點比較遺憾。

如果要處理一個字串型的“192.168.1.254”,想把每個欄位都分開,怎麼辦呢,C標準庫中有函式strtok()的實現,可以一用。

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main()
{
	char ip_str[] = "192.168.1.250";
	char *ip_arr[4] ;
	char * s = strtok(ip_str, ".");
	int i=0;
	while(s)
	{
		ip_arr[i] = s;
		s = strtok(NULL, ".");
		i++;
//		printf("%s\n",s);
	}

	for(i=0; i<4; i++)
		printf("%s\n",ip_arr[i]);
}

在這裡,strtok是非執行緒安全的,這點也可以在程式的第二次strtok呼叫中看到,因此linux用strsep來替換strtok了,我在linux2.6.22的原始碼/lib/string.c和linux-3.3中同文件中,c檔案開頭就是這樣一段話:
/*
 *  linux/lib/string.c
 *
 *  Copyright (C) 1991, 1992  Linus Torvalds
 */

/*
 * stupid library routines.. The optimized versions should generally be found
 * as inline code in <asm-xx/string.h>
 *
 * These are buggy as well..
 *
 * * Fri Jun 25 1999, Ingo Oeser <
[email protected]
> * - Added strsep() which will replace strtok() soon (because strsep() is * reentrant and should be faster). Use only strsep() in new code, please. * * * Sat Feb 09 2002, Jason Thomas <[email protected]>, * Matthew Hawkins <[email protected]
> * - Kissed strtok() goodbye */


因為strsep是執行緒安全的,並且速度上更快一些,所以採用strsep來替換strtok,接下來我會試一試strsep。在這裡感慨下,沒事的時候或者寫程式的時候,用man和檢視原始碼的方式,能學到很多基本的知識,比如核心原始碼的lib資料夾下,linux核心使用的rbtree結構,還有lib資料夾的string.c,include下的string.h裡的各種strcpy,strcat等基本函式的實現,都是非常經典而且久經考驗的。

在strtok使用的程式碼裡,有兩處很有意思。

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

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main()
{
	char *ip_str = "192.168.1.250";
	char *ip_arr[4] ;
	char * s = strtok(ip_str, ".");
	int i=0;
	while(s)
	{
		ip_arr[i] = s;
		s = strtok(NULL, ".");
		i++;
//		printf("%s\n",s);
	}

	for(i=0; i<4; i++)
		printf("%s\n",ip_arr[i]);
}

將char ip_str[] = "192.168.1.250";改為char *ip_str = "192.168.1.250";就會core dump,通過gdb和core檔案來看,程式崩潰在了
Program terminated with signal 11, Segmentation fault.
#0  strtok () at ../sysdeps/i386/i686/strtok.S:245
245 	 movb $0, (%edx) /* Terminate string.  */
(gdb) where
#0  strtok () at ../sysdeps/i386/i686/strtok.S:245
#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語句註釋掉,程式碼如下:

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main()
{
	char ip_str[] = "192.168.1.250";
	char *ip_arr[4] ;
	char * s = strtok(ip_str, ".");
	int i=0;
	while(s)
	{
		ip_arr[i] = s;
		s = strtok(NULL, ".");
		i++;
		printf("%s\n",s);
	}

	for(i=0; i<4; i++)
		printf("%s\n",ip_arr[i]);
}

又崩潰了,我也整個人都不好了。

分析core檔案,出錯如下:

Program terminated with signal 11, Segmentation fault.
#0  __strlen_ia32 () at ../sysdeps/i386/i586/strlen.S:99
99 	 movl (%eax), %ecx /* get word (= 4 bytes) in question */
(gdb) where
#0  __strlen_ia32 () at ../sysdeps/i386/i586/strlen.S:99
#1  0x00b9ddd5 in _IO_puts (str=0x0) at ioputs.c:37
#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',代表行緩衝結束,需要輸出,如果我不讓他輸出,會怎樣?

列印結果為:

168	1	250	(null)	
好吧我也不知道是什麼了,而且這個結果與是否有'\0'符號無關。

這兩個地方一定要找出來問題,嗯。

接下來我們看看strsep的用法吧

#include<stdio.h>
#include<stdlib.h>
#include<string.h>

int main()
{
	char ip_str[] = "192.168.1.250";
	char *p = ip_str;
	char *ip_arr[4] ;
	char * s = strsep(&p, ".");
	int i=0;
	while(s)
	{
		ip_arr[i] = s;
		s = strsep(&p, ".");
		i++;
//		printf("%s\n",s);
	}

	for(i=0; i<4; i++)
		printf("%s\n",ip_arr[i]);
}

用法也差不多。

相關推薦

c/cpp如何分割字串類似split功能

在python中,如果要求當前時間的unix時間戳,我特別喜歡這麼用: import time timestr = time.time() timestamp = int(timestr.split('.')[0]) 這裡的split函式,我非常喜歡,在java、c#和

leetcode676+修改一個字母在vector的dict有沒有類似字典樹暴力

https://leetcode.com/problems/implement-magic-dictionary/description/ class MagicDictionary { public: set<string> s; /** Initialize

C語言字串也叫c

在C語言中,字串常量是指用一對雙撇號括起來的字元序列。如 “Hello World” ,  “CHINA" , "a" C規定: 在每一個字串的結尾加一個”字串結束標誌“,以便系統據此判斷字串是否結束。 C規定:以字元"空操作字元“(即不引起任何控制動作,不同於空格字元)

淺析在QtWidget自定義Model(beginInsertRows()和endInsertRows()是空架子類似一種信號用來通知底層)

cti ron 初學者 開發 http 沒有 insert ati 學習 Qt 4推出了一組新的item view類,它們使用model/view結構來管理數據與表示層的關系。這種結構帶來的功能上的分離給了開發人員更大的彈性來定制數據項的表示,它也提供一個標準的model接

mysql下分組取關聯表指定提示方法類似mssql的cross apply

nbsp cts ont font ack you 方法 sta lease 轉至:https://stackoverflow.com/questions/12113699/get-top-n-records-for-each-group-of-grouped-result

【kotlin】基本語法when的使用類似java的switch,但是又青出於藍而勝

href .com log 事情 IT 使用 基本語法 kotlin 參數 when(要判斷的參數){   參數值為1  ->做這種事情   參數值為2  ->做另一種事情   else  ->  類似於switch中的default } 擴展使用:ht

python多執行緒開啟的兩種方式(內含有event的應用即安全的機制類似java的等待喚醒機制不會出現多個執行緒之間的錯亂問題)

 event是類似於java中的等待喚醒機制,具體方法參照上一篇CSDN 下面來介紹開啟執行緒的第一種方式 #Filename:threading1.py #開啟執行緒的第一種方式 import threading import time event=threadin

釘釘e應用的插槽功能類似element-ui 的slot功能點選某個按鈕輸出所在列表項的資料

定義data屬性,data-obj="{{item}}" <view data-obj="{{item}}" catchTap="onHasQuiz">隨堂考試</view> 用e接收,console輸出看 onHasQuiz(e) { console.l

C重要字串自動分割函式strtok

函式strtok  原型  char * strtok ( char * str, const char * delimiters ); 功 能: 查詢由在第二個串中指定的分界符分隔開的單詞, 即源串中除去了含有分隔串中的所有字元後餘下的一段段的字串,每呼叫一次找到

c語言】一個字串包含n個字元。將此字串從第m個字元開始的全部字元複製成為另一個字串

#include <stdio.h> #include <string.h> int main() { void copystr(char *,char *,int); int m; char str1[20],str2[20]; print

關於mybatis根據傳進來的引數執行不同的語句類似java的if~else~語句

1、在一個方法中根據條件執行兩個不同的查詢語句,例如下面的查詢穿進來的引數為admin時執行第一個查詢語句,否則就執行下面查詢語句 dao類中的方法 public List<Caidan> getcaidan(@Param(value="czyid") Stri

c++ 實現字串替換字串也可去掉字串特定字串

int string_replase(string &s1, const string &s2, const string &s3) { string::size_type pos = 0; string::size_type a = s2.si

string的字串替換函式類似CString的Replace

標準C++中的string中的函式不多,沒有CString的功能強大,但是如果想在Unicode編碼下使用多位元組,就不能使用CString,於是自己寫了一個類似於CString的Replace函式。string replace( const string& inSt

AndroidApplication類用法(整個程式的全域性變數即單例)類似session

<?xml version="1.0" encoding="utf-8"?> <manifest xmlns:android="http://schemas.android.com/apk/res/android" package="com.android.test"

vs2013/2015scanf函數類似error C4996: 'scanf': This function or variable may be unsafe的安全檢查錯誤

span 調試 ria 安全性 init 點擊 scan online pan   在使用vs2015時,遇到了scnaf函數安全性的問題,程序不能正常運行,錯誤如下: error C4996: ‘scanf‘: This function or variable may

Java分割字串split()的用法小結

用"."做分隔符,必須是如下寫法 String.split("\\."),不能是String.split("."); 用"|"做分隔符,必須是如下的寫法 String.split("\\|"),不能是String.split("|"); 如果在一個字串中有多

UE4 C++程式碼使用材質字型等資源

當我使用ue4 editor製作了一個材質(Material)或字型(Font)之後,該材質和字型等資源不僅可以在editor中使用,還可以在C++程式碼中使用。 下圖為我在editor中製作的資源: 我們可以通過右鍵點選該資源,點選“Copy Reference”來獲得資源的參考路徑。

C語言字串的操

最近對於C語言接收到的資料(字串)處理比較多。 字串:零個或多個字元組成的有限序列。假設:S="abcd1234efghmn",其中S是串列埠,字串中的字元可以是字元、數字或其他字元。 #include <string.h> #include <stdio.h>

C++ Builder字串替換函式

UnicodeString __fastcall StringReplace(         const System::UnicodeString S,