CString/string /Char轉化、Vector、分割、New、Malloc、Memset、Memcpy、Strcpy、static
#include "stdafx.h" #include <string> // #include <stdlib.h> #include <stdio.h> #include <iostream> using namespace std; int _tmain() { //把字串轉成數字 char *token="20";//或者 char token[10]="20"; int n; n=atoi(token); n+=8; //把數字轉成字串 char buf[200]; //不能轉換成 char *buf; 可以寫成char *buf=new char[200] sprintf_s(buf,20,"%d",n); cout<<buf; return 0; }
char *itoa(int value, char *string, int radix);
int value 被轉換的整數,char *string 轉換後儲存的字元陣列,int radix 轉換進位制數,如2,8,10,16 進位制等char charUnsharp[10];
int num= 3;
itoa(num,charUnsharp,10);//把整數num轉換成字串charUnsharp ,10進位制轉換。
為TgImage自定義的結構體分配空間
static char* pShowImgX;
static TgImage outimage;//前面加了個static
if ( bFirstreg )
{
bFirstreg = FALSE;
pShowImgX = new char[384*288*3];
outimage.pData = pShowImgX;
outimage.width = g_Image.width;
outimage.height = g_Image.height;
outimage.nChannels = 3;
在用MFC進行程式設計時,我們從對話方塊中利用GetWindowText得到的字串是 CString型別,CString是屬於MFC的類。
而一些標準C/C++庫函式是不能直接對CString型別進行操作的,所以我們經常遇到將 CString型別轉化char*等等其他資料型別的情況。這裡總結備忘於此!
首先要明確,標準C中是不存在string型別的,string是標準C++擴充字串操作的一個類。但是我們知道標準C中有string.h這個標頭檔案,這裡要區分清楚,此string非彼string。 string.h這個標頭檔案中定義了一些我們經常用到的操作字串的函式,如:strcpy、strcat、strcmp等等,但是這些函式的操作物件都是char*指向的字串。而C++的string類操作物件是string型別字串,
CString並非是你賦予多大長度的字串就佔有多大的記憶體空間。它的空間分配機制是事先申請一個比較大的記憶體空間來存放字串,在以後的操作中如果字串超出了這個記憶體區域,它才會先釋放原先的記憶體區域,重新申請一個更大的記憶體空間。同樣,如果字串變短了,它也不是立即釋放多餘空間,而是累積到了一定程度才釋放。這樣實現了“無長度限制”,又避免了頻繁的申請、釋放記憶體的操作。
CString的另外一個特色就是“寫入複製技術(CopyBeforeWrite)”。當使用一個CString物件A來初始化另外一個CString物件B時,B並不會被分配空間,而是將自己的指標指向物件A的儲存空間。除非對兩個中的某個做修改時,才會為物件B申請記憶體。
1.CString和string的轉化
string str="ksarea";
CString cstr(str.c_str());//或者CString cstr(str.data());初始化時才行
cstr = str.c_str();或者cstr = str.data();
str = cstr.GetBuffer(0); //CString -> string
cstr.format("%s", str.c_str());
//string->CString
cstr.format("%s", str.data()); //string->CString
str = LPCSTR(cstr); //CString->string
/*c_str()和data()區別是:前者返回帶'/0'的字串,後者則返回不帶'/0'的字串*/
string型別不能直接賦值給CString
2.CString和int的轉換
int i=123;
CString str;
str.format("%d",i);//int->CString 其他的基本型別轉化類似
i=atoi(str);//CString->int 還有(atof,atol)
3、判斷string是否為空
string類為空,實際也就是元素為0個。 可以按照如下方式判斷:
1、string類有自己的成員函式empty, 可以用來判斷是否為空。
1 2 3 |
string s;
if (s.empty()) //成立則為空
...
|
2、判斷字串長度。如果長度為0,則為空。
1 2 3 |
string s;
if (s.length()==0) //成立則為空
...
|
3、與空串比較,如果相等則為空。
1 2 3 |
string s;
if (s== "" ) //成立則為空
...
|
幾種方法中,empty函式是效率最高也是最常用的一種。
3、string型別轉換int型別
1、c- std::string str;
- int i = atoi(str.c_str());
2、c++
- std::string str;
- int i = std::stoi(str);
string::size_type string::find(string &);
1)
string a="abcdefghigklmn";
string b="def";
idx=a.find(b);//在a中查詢b.
if(idx == string::npos )//不存在。
cout << "not found\n";
else//存在。
cout <<"found\n";
2)C語言風格。字串儲存為字元陣列,以'\0'結束。 在C的介面中,有strstr函式,可以在字串中查詢另一個字串。
char * strstr(const char *str1, const char *str2);
功能為在str1中查詢str2,如果存在,那麼返回查詢到的起始指標,否則返回NULL。
string a="abcdefghigklmn";
char *b="def";
if(strstr(a.c_str(), b) == NULL)//在a中查詢b,如果不存在,
cout << "not found\n";//輸出結果。
else//否則存在。
cout <<"found\n"; //輸出結果。
標準庫的string類提供了3個成員函式來從一個string得到c型別的字元陣列:c_str()、data()、copy(p,n)。
1. c_str():生成一個const char*指標,指向以空字元終止的陣列。
注:
①這個陣列的資料是臨時的,當有一個改變這些資料的成員函式被呼叫後,其中的資料就會失效。因此要麼現用先轉換,要麼把它的資料複製到使用者自己可以管理的記憶體中。注意。看下例:
const char* c;
string s="1234";
c = s.c_str();
cout<<c<<endl;//輸出:1234
s="abcd";
cout<<c<<endl;//輸出:abcd
上面如果繼續用c指標的話,導致的錯誤將是不可想象的。就如:1234變為abcd
其實上面的c = s.c_str(); 不是一個好習慣。既然c指標指向的內容容易失效,我們就應該按照上面的方法,那怎麼把資料複製出來呢?這就要用到strcpy等函式(推薦)。
//const char* c; //①
//char* c; //②
//char c[20];
char* c=new char[20];
string s="1234";
//c = s.c_str();
strcpy(c,s.c_str());
cout<<c<<endl;//輸出:1234
s="abcd";
cout<<c<<endl;//輸出:1234
注意:不能再像上面一樣①所示了,const還怎麼向裡面寫入值啊;也不能②所示,使用了未初始化的區域性變數“c”,執行會出錯的 。
② c_str()返回一個客戶程式可讀不可改的指向字元陣列的指標,不需要手動釋放或刪除這個指標。
2. data():與c_str()類似,但是返回的陣列不以空字元終止。
3. copy(p,n,size_type _Off = 0):從string型別物件中至多複製n個字元到字元指標p指向的空間中。預設從首字元開始,但是也可以指定,開始的位置(記住從0開始)。返回真正從物件中複製的字元。------使用者要確保p指向的空間足夠儲存n個字元。
string::copy()舉例:
char c2[11] = {0};
string s2 = "hello boy!";
int iRtn = s2.copy(c2, 10, 0);//功能為將s2的,從第0個開始的,共10個字元拷貝到c2中,iRtn為拷貝的字元個數,此處為10。
注意:iRtn返回的是實際拷貝的位元組數,當第二個引數比字串本身長時,返回的便是字串長度。
CString msg;
int dep = disp.depth();
msg.Format(_T("depth:%d"),dep);
AfxMessageBox(msg);
3. char* 和CString的轉換
1) CString cstr = "ksarea";
char* ptemp = cstr.getbuffer(0);
2) char* str;
strcpy(str,ptemp);//CString->char*
cstr.releasebuffer(-1);
char* str="lovesha";
CString cstr=str;//char*->CString
至於int與float、string與char*之間的轉化可以使用強制轉化,或者標準庫函式進行。對於CString與其他型別的轉化方法很多,但其實都殊途同歸,朝著一個方向即將型別首先轉化為char*型別,因為char*是不同型別之間的橋樑。得到char*型別,轉化為其他型別就非常容易了。
3.1 把兩個char *字串複製到另一個char * 變數中
char str3[20];
strcpy(str3,str1);
strcat(str3,str2);
char* str=str3;
cout<<str<<endl; //使用此句要包含:#include <iostream> 和 using namespace std;
string 轉換成 const char *
string s1 = "abcdeg";
const char *k = s1.c_str();或 const char *t = s1.data();
printf("%s%s",k,t);
cout<<k<<t<<endl;
如上,都可以輸出。內容是一樣的。但是隻能轉換成const char*,如果去掉const編譯不能通過。
那麼,如果要轉換成char*,可以用string的一個成員函式copy實現。
string s1 = "abcdefg";
char *data;
int len = s1.length();
data = (char *)malloc((len+1)*sizeof(char));
s1.copy(data,len,0);
printf("%s",data);
cout<<data; //說明,如果字符集是unicode的話,可能字串後面有亂碼,如果選 為多字符集的話,就只輸出字串
3.2、char *轉換成string
可以直接賦值。
string s;
char *p = "adghrtyh";
s = p;
printf("%s",s1.c_str())// 這樣是正確的
// printf("%s",s1) 這樣是錯誤的
cout<<s.c_str()<<endl; //正確
//cout<<s<<endl; //錯誤
注:
1)用printf("%s",s1);輸出是會出問題的。這是因為“%s”要求後面的物件的首地址。但是string不是這樣的一個型別。所以肯定出錯。
那麼可以這樣:printf("%s",s1.c_str())
如何判斷一個 char * s 指標的內容是否為空
1、 CString strname;
strname=m_bstr_name; //m_bstr_name也是CString型別的
if (strname=="")
{
AfxMessageBox("name is null");
}
如果要判斷一個char *s 是否為空,要用strcmp(m_bstr_name.GetBuffer(0),"")進行判斷
2、if (strcmp(m_bstr_name.GetBuffer(0),"")==0) //m_bstr_name.GetBuffer(0)是把一個CString型別轉換成char *型別
{
AfxMessageBox("name is null");
}
else
AfxMessageBox("name is not null222");
(2) char * s = new char[10];
memset(s,'\0',10);
if(strcmp(s,"")==0) 或者是 if(s[0]==0)
注意:如果寫成下面這樣,就是錯誤的
if (m_bstr_name.GetBuffer(0) ==“”) //m_bstr_name.GetBuffer(0)是把一個CString型別轉換成char *型別
上面這句是錯誤,m_bstr_name.GetBuffer(0)指向的內容一直都不是空。
String name==null;//是空引用 Null ::一個值,表示一個變數不包含任何有效資料。
String name="";//這是個空字串
String name="";這個在堆上分配了儲存空間.你可以呼叫String的所有方法.
char* str_1 = "abc" ; char * str_2 = "abc" ; char* str_3 = "ABC" ;
if (strcmp(str_1, str_2) == 0)
{ 。。。。。
}
1.首先正確包含標頭檔案
使用下面語句
#include <string>
沒有.h,
否則無法引用標準模板庫
2.使用名稱空間
即使用下面語句:
using namespace std;
3.string 所建立的物件不能夠直接使用裡面的字串
如 string str;
cout<<str<<endl;
這樣語句不能執行
要使用string的一個函式進行轉化 c_str() 才能正確使用其中的字串。
4、怎樣比較兩個型別為String的字串?
1)
string s1="fsf";
string s2="sdfnk";
// if(strcmp(s1,s2))//這樣寫錯誤,因為strcmp(s1,s2)中,要求s1,s2都是char * 型別
if (s1.compare(s2)==0) // 這樣寫正確
cout<<"s1 is equal to s2";
else
cout<<"s1 !=s2";
2)
string s1="fsf";
string s2="fsf";
// if(strcmp(s1,s2))//這樣寫錯誤,因為strcmp(s1,s2)中,要求s1,s2都是char * 型別
// if (s1.compare(s2)==0)//正確
if (s2 ==s1) //正確
cout<<"s1 equal to s2"<<endl;
else
cout<<"s1 is not s2"<<endl;
說明:如果內容已經存在了,不會分配第二個,上面已經 String s1 = "fsf";了, 這個"fsf"已經存在了,下面String s2 = "fsf"; 就不會分配第二個"fsf"了,那麼s2指向誰?s2也指向上面s1指向的這個物件,現在是s1和s2同時指向同一個物件,那麼它們的地址當然一樣,==比較的是引用地址,所以s1 == s2
返回true。
在兩個物件之間使用 "==",會將“兩個物件是否有同一reference”的結果傳回。也就是說, 這等同於“兩個物件是否擁有同一地址 (address)”,或者“兩個物件物件是否為同一物件”。
如果您的意思是判斷兩個字串的內容是否相同,那麼應該使用以下的方法才對:
if (s1.equals(s2) )
or if (s1.equalsIgnoreCase(s2) )
or if (s1.startsWith(s2) )
or if (s1.endsWith(s2) )
or if (s1.regionMatches(s1_offset, s2, s2_offset, length) )
or if (s1.compare(s2) )
1)strlen:計算字串s的長度,不包括'\0'在內 //const char * 的長度
如:
string strName="abc"; char * data="bcd";
int len2=strlen(strName);//錯誤 要求:strName 為const char* 型別
int len2=strlen(data);//正確
cout<<"len2: "<<len2<<endl; 結果是len2: 3
2)sizeof:判斷資料型別長度符如:sizeof(int)結果就是4,
sizeof(string)結果就是16,
sizeof(char *)結果就是4,
sizeof(char)結果就是1
3)length:是求字串長度,或陣列中長度最長的那一維的長度。
如: string strName="abc"; int len = strName.length();//string 的長度 cout<<"len: "<<len<<endl; 結果就是 len: 3
總之:strlen是統計字串的字元個數,不包括結尾的\0;length是求字串長度,
5、轉換成相應的字串
vs2005:
char *filename=new char[20];
sprintf_s(filename,20,"air%d.jpg",i);
vc6.0:
char *filename=new char[20];
sprintf(filename,"air%d.jpg",i);
char buf[5];
sprintf(buf,"%d",srcImg->nChannels);
MessageBox(buf);
CString cstr;
cstr.format("%s", 123);
IplImage* paintx=cvCreateImage( cvGetSize(src),IPL_DEPTH_8U, 1 );
IplImage* painty=cvCreateImage( cvGetSize(src),IPL_DEPTH_8U, 1 );
// cvZero(paintx); //全變為黑色
cvSet(paintx,cvScalar(255,255,255,255),0);//全變為白色
cvZero(painty);
int* v=new int[src->width];
int* h=new int[src->height];
memset(v,0,src->width*4);
memset(h,0,src->height*4);
delete v;
delete h;
CString str1;
avg=totalwidthmy/(w.size()-6-sb);
str1.Format("%d",avg);
MessageBox(str1);
6、new 和 malloc 的區別
從函式宣告上可以看出。malloc 和 new 至少有兩個不同: new 返回指定型別的指標,並且可以自動計算所需要大小。比如:int *p;
p = new int; //返回型別為int* 型別(整數型指標),分配大小為 sizeof(int);
或:
int* parr;
parr = new int [100]; //返回型別為 int* 型別(整數型指標),分配大小為 sizeof(int) * 100;
而 malloc 則必須要由我們計算位元組數,並且在返回後強行轉換為實際型別的指標。
int* p;
p = (int *) malloc (sizeof(int)*128); //分配128個(可根據實際需要替換該數值)整型儲存單元,並將這128個連續的整型儲存單元的首地址儲存到指標變數p中
double *pd=(double *) malloc (sizeof(double)*12); //分配12個double型儲存單元, //並將首地址儲存到指標變數pd中
第一、malloc 函式返回的是 void * 型別。對於C++,如果你寫成:p = malloc (sizeof(int)); 則程式無法通過編譯,報錯:“不能將 void* 賦值給 int * 型別變數”。所以必須通過 (int *) 來將強制轉換。而對於C,沒有這個要求,但為了使C程式更方便的移植到C++中來,建議養成強制轉換的習慣。
第二、函式的實參為 sizeof(int) ,用於指明一個整型資料需要的大小。如果你寫成:
int* p = (int *) malloc (1); 程式碼也能通過編譯,但事實上只分配了1個位元組大小的記憶體空間,當你往裡頭存入一個整數,就會有3個位元組無家可歸,而直接“住進鄰居家”!造成的結果是後面的記憶體中原有資料內容被改寫。 7、 memset()、memcpy()、strcpy()、strncpy() 1)memset()的深刻內涵:用來對一段記憶體空間全部設定為某個字元,一般用在對定義的字串進行初始化為‘ ’或‘\0’; 例:char a[100]; memset(a, '\0', sizeof(a)*100);
#include<iostream>
#include<cstring>
using namespace std;
int main()
{
char a[5];
memset (a, '1' ,5*sizeof(a));//sizeof(a) =1
for (int i=0;i<5;i++)
cout<<a[i]<< "" ;
system ( "pause" );
return0;
}
|
以上這段程式是正確的,a[i]的值是1.
#include<iostream>
#include<cstring>
#include<windows.h>
using namespace std;
int main()
{
int a[5];
memset (a,1,20); //如果這裡改成memset(a,1,5*sizeof(int))也不可以,因為memset按位元組賦值。
for (int i=0;i<5;i++)
cout<<a[i]<< " " ;
system ( "pause" );
return0;
}
|
問題是:
1,第一個程式為什麼可以,而第二個不行? 因為第一個程式的陣列a是字元型的,字元型佔據記憶體大小是1Byte,而memset函式也是以位元組為單位進行賦值的,所以你輸出沒有問題。 而第二個程式a是整型的,使用 memset還是按位元組賦值,這樣賦值完以後,每個陣列元素的值實際上是0x01010101即十進位制的16843009。 如果用memset(a,1,20) 就是對a指向的記憶體的20個位元組進行賦值,每個都用ASCⅡ為1的字元去填充,轉為二進位制後,1就是00000001,佔一個位元組。一個INT元素是4位元組,合一起就是0x01010101,就等於16843009,就完成了對一個int 元素的賦值了
2)memcpy用來做記憶體拷貝,你可以拿它拷貝任何資料型別的物件,可以指定拷貝的資料長度;
3)strcpy就只能拷貝字串了,它遇到'/0'就結束拷貝; 例:char a[100], b[50]; strcpy(a,b); 如用strcpy(b,a),要注意a中的字串長度(第一個‘/0’之前)是否超過50位,如超過,則會造成b的記憶體地址溢位。 4) strcpy 和strncpy 的差別在哪裡,各自的優缺點是什麼
strcpy (目標串地址,源串的開始地址): 從源串的開始到結尾('\0')完全拷貝到目標串地址 strncpy(目標串地址,源串的開始地址,n): 從源串的開始拷貝n個字元到目標串地址,n大於源串長度時,遇到'\0'結束; n小於源串長度時,到第n個字元結束,但不會在目標串尾補'\0'
char *p="hello"; char *p1="liulina"; char s[40]="how are you? where are you from";
strncpy(s,p1,3); cout<<s<<endl;// 輸出 liu are you? where are you from
strcpy(s,p);//輸出 hello cout<<s<<endl;
8、動態分配陣列大小 typedef std::vector<int> List;List w; w.push_back(roi.width); w.size();//容器裡有多少個變數
用new分配的物件會呼叫物件的建構函式,delete則會呼叫物件的解構函式
而malloc和free從不呼叫構造和解構函式,他們只是簡單的分配記憶體。
參考以下程式分析說明 new 和 malloc 的區別: 1#include <iostream> 2#include <cstdio> 3#include <cstdlib> 4using namespace std; 5class T 6{ 7 public: 8 T(){ cout << "T()" << endl; } 9 ~T(){ cout << "~T()" << endl; } 10 }; 11int main() 12{ 13 T* first = new T; 14 T* second = (T*)malloc(sizeof(T)); 15 if( first ) delete first; 16 if( second ) free(second); 17 return 0; 18} 解答: 由第13、14行程式碼可見,new,malloc均能完成動態分配一個新的空間的功能,並把它的首地址交給一個指標。區別在於: 1. new直接寫在型別T的前面,是C++中的一個操作符,且直接分配T大小的記憶體空間。而malloc是C中的一個函式,且需要藉助於函式sizeof幫其判斷T型別的大小; 2. new直接返回一個T型別的指標,而且會呼叫類中的建構函式。而malloc返回一個void指標,需要在前面對其強制定義為一個T型別的指標,不用呼叫建構函式。 3. new與delete搭配使用,delete會呼叫類中的解構函式對記憶體進行釋放。malloc則與free搭配,不呼叫解構函式。
9、 vetor容器
#include "stdafx.h"
#include "cv.h"
#include "highgui.h"
#include "cvaux.h"
#include "cxcore.h"
#include <stdio.h>
#include <vector>
#include <iostream>
#include <cv.h>
#include <highgui.h>
#pragma comment( lib, "cv.lib" )
#pragma comment( lib, "cxcore.lib" )
#pragma comment( lib, "highgui.lib" )
using namespace std;
typedef std::vector<int> List;
void bubble_sort(List& a,int n)
{
for(int i = 0; i < n; ++i)//[0..(n-1)]
{
//j < n - 1可以優化
for( int j = 0 ; j < n - 1; ++j)//a[0..(n-2)]
if ( a[j] > a[j+1] )
{
int t = a[j];
a[j] = a[j+1];
a[j+1] = t;
}
}
}
void print(List& a, int n)
{
for(int i = 0; i < n; ++i)
{
printf("%2d ",a[i]);
}
printf("\n");
}
int main()
{
IplImage * src1=cvLoadImage("show1.bmp",0);
IplImage * src=cvCreateImage(cvSize(src1->width,src1->height),src1->depth,src1->nChannels);
cvErode(src1,src,NULL,1);//膨脹影象
cvSaveImage("c:\\src11.bmp",src);
cvDilate(src,src,NULL,1);//腐蝕影象
cvSaveImage("c:\\src00.bmp",src);
cvThreshold(src,src,150,255,/*CV_THRESH_BINARY_INV*/0);
IplImage* paintx=cvCreateImage( cvGetSize(src),IPL_DEPTH_8U, 1 );
IplImage* painty=cvCreateImage( cvGetSize(src),IPL_DEPTH_8U, 1 );
// cvZero(paintx); //全變為黑色
cvSet(paintx,cvScalar(255,255,255,255),0);//全變為白色
cvZero(painty);
int* v=new int[src->width];
int* h=new int[src->height];
memset(v,0,src->width*4);
memset(h,0,src->height*4);
int x,y;
int mark=0,num1=0;
int min=src->height,col=0;
bool flag1=0;
bool flag2=0;
int leftnew=0,rightnew=0,left,right;
CvScalar s,t;
IplImage * histgram;
char * fname=new char[100];
int tem