1.求下面函數的傳回值(微軟)
int func(x)
{
int countx = 0;
while(x)
{
countx ++;
x = x&(x-1);
}
return countx;
}
假定x = 9999。答案:8
思路:将x轉化為2進制,看含有的1的個數。
2. 什麼是“引用”?申明和使用“引用”要注意哪些問題?
答:引用就是某個目标變量的“别名”(alias),對應用的操作與對變量直接操作效果完全相同。申明一個引用的時候,切記要對其進行初始化。引用聲明完畢後,相當于目标變量名有兩個名稱,即該目标原名稱和引用名,不能再把該引用名作為其他變量名的别名。聲明一個引用,不是新定義了一個變量,它隻表示該引用名是目标變量名的一個别名,它本身不是一種資料類型,是以引用本身不占存儲單元,系統也不給引用配置設定存儲單元。不能建立數組的引用。
3. 将“引用”作為函數參數有哪些特點?
(1)傳遞引用給函數與傳遞指針的效果是一樣的。這時,被調函數的形參就成為原來主調函數中的實參變量或對象的一個别名來使用,是以在被調函數中對形參變量的操作就是對其相應的目标對象(在主調函數中)的操作。
(2)使用引用傳遞函數的參數,在記憶體中并沒有産生實參的副本,它是直接對實參操作;而使用一般變量傳遞函數的參數,當發生函數調用時,需要給形參配置設定存儲單元,形參變量是實參變量的副本;如果傳遞的是對象,還将調用拷貝構造函數。是以,當參數傳遞的資料較大時,用引用比用一般變量傳遞參數的效率和所占空間都好。
(3)使用指針作為函數的參數雖然也能達到與使用引用的效果,但是,在被調函數中同樣要給形參配置設定存儲單元,且需要重複使用"*指針變量名"的形式進行運算,這很容易産生錯誤且程式的閱讀性較差;另一方面,在主調函數的調用點處,必須用變量的位址作為實參。而引用更容易使用,更清晰。
4. 在什麼時候需要使用“常引用”?
如果既要利用引用提高程式的效率,又要保護傳遞給函數的資料不在函數中被改變,就應使用常引用。常引用聲明方式:const 類型辨別符 &引用名=目标變量名;
例1
int a ;
const int &ra=a;
ra=1; //錯誤
a=1; //正确
例2
string foo( );
void bar(string & s);
那麼下面的表達式将是非法的:
bar(foo( ));
bar("hello world");
原因在于foo( )和"hello world"串都會産生一個臨時對象,而在C++中,這些臨時對象都是const類型的。是以上面的表達式就是試圖将一個const類型的對象轉換為非const類型,這是非法的。
引用型參數應該在能被定義為const的情況下,盡量定義為const 。
5. 将“引用”作為函數傳回值類型的格式、好處和需要遵守的規則?
格式:類型辨別符 &函數名(形參清單及類型說明){ //函數體 }
好處:在記憶體中不産生被傳回值的副本;(注意:正是因為這點原因,是以傳回一個局部變量的引用是不可取的。因為随着該局部變量生存期的結束,相應的引用也會失效,産生runtime error!
注意事項:
(1)不能傳回局部變量的引用。這條可以參照Effective C++[1]的Item 31。主要原因是局部變量會在函數傳回後被銷毀,是以被傳回的引用就成為了"無所指"的引用,程式會進入未知狀态。
(2)不能傳回函數内部new配置設定的記憶體的引用。這條可以參照Effective C++[1]的Item 31。雖然不存在局部變量的被動銷毀問題,可對于這種情況(傳回函數内部new配置設定記憶體的引用),又面臨其它尴尬局面。例如,被函數傳回的引用隻是作為一個臨時變量出現,而沒有被賦予一個實際的變量,那麼這個引用所指向的空間(由new配置設定)就無法釋放,造成memory leak。
(3)可以傳回類成員的引用,但最好是const。這條原則可以參照Effective C++[1]的Item 30。主要原因是當對象的屬性是與某種業務規則(business rule)相關聯的時候,其指派常常與某些其它屬性或者對象的狀态有關,是以有必要将指派操作封裝在一個業務規則當中。如果其它對象可以獲得該屬性的非常量引用(或指針),那麼對該屬性的單純指派就會破壞業務規則的完整性。
(4)流操作符重載傳回值申明為“引用”的作用:
流操作符<<和>>,這兩個操作符常常希望被連續使用,例如:cout << "hello" << endl; 是以這兩個操作符的傳回值應該是一個仍然支援這兩個操作符的流引用。可選的其它方案包括:傳回一個流對象和傳回一個流對象指針。但是對于傳回一個流對象,程式必須重新(拷貝)構造一個新的流對象,也就是說,連續的兩個<<操作符實際上是針對不同對象的!這無法讓人接受。對于傳回一個流指針則不能連續使用<<操作符。是以,傳回一個流對象引用是惟一選擇。這個唯一選擇很關鍵,它說明了引用的重要性以及無可替代性,也許這就是C++語言中引入引用這個概念的原因吧。指派操作符=。這個操作符象流操作符一樣,是可以連續使用的,例如:x = j = 10;或者(x=10)=100;指派操作符的傳回值必須是一個左值,以便可以被繼續指派。是以引用成了這個操作符的惟一傳回值選擇。
例3
#i nclude
int &put(int n);
int vals[10];
int error=-1;
void main()
{
put(0)=10; //以put(0)函數值作為左值,等價于vals[0]=10;
put(9)=20; //以put(9)函數值作為左值,等價于vals[9]=20;
cout<
cout<<VALS[9];
}
int &put(int n)
{
if (n>=0 && n<=9 ) return vals[n];
else { cout<<"subscript error"; return error; }
}
(5)在另外的一些操作符中,卻千萬不能傳回引用:+-*/ 四則運算符。它們不能傳回引用,Effective C++[1]的Item23詳細的讨論了這個問題。主要原因是這四個操作符沒有side effect,是以,它們必須構造一個對象作為傳回值,可選的方案包括:傳回一個對象、傳回一個局部變量的引用,傳回一個new配置設定的對象的引用、傳回一個靜态對象引用。根據前面提到的引用作為傳回值的三個規則,第2、3兩個方案都被否決了。靜态對象的引用又因為((a+b) == (c+d))會永遠為true而導緻錯誤。是以可選的隻剩下傳回一個對象了。
6. “引用”與多态的關系?
引用是除指針外另一個可以産生多态效果的手段。這意味着,一個基類的引用可以指向它的派生類執行個體。
例4
Class A; Class B : Class A{...}; B b; A& ref = b;
7. “引用”與指針的差別是什麼?
指針通過某個指針變量指向一個對象後,對它所指向的變量間接操作。程式中使用指針,程式的可讀性差;而引用本身就是目标變量的别名,對引用的操作就是對目标變量的操作。此外,就是上面提到的對函數傳ref和pointer的差別。
8. 什麼時候需要“引用”?
流操作符<<和>>、指派操作符=的傳回值、拷貝構造函數的參數、指派操作符=的參數、其它情況都推薦使用引用。
以上 2-8 參考:http://blog.csdn.net/wfwd/archive/2006/05/30/763551.aspx
9. 結構與聯合有和差別?
1. 結構和聯合都是由多個不同的資料類型成員組成, 但在任何同一時刻, 聯合中隻存放了一個被選中的成員(所有成員共用一塊位址空間), 而結構的所有成員都存在(不同成員的存放位址不同)。
2. 對于聯合的不同成員指派, 将會對其它成員重寫, 原來成員的值就不存在了, 而對于結構的不同成員指派是互不影響的。
10. 下面關于“聯合”的題目的輸出?
a)
#i nclude
union
{
int i;
char x[2];
}a;
void main()
{
a.x[0] = 10;
a.x[1] = 1;
printf("%d",a.i);
}
答案:266 (低位低位址,高位高位址,記憶體占用情況是Ox010A)
b)
main()
{
union{
int i;
struct{
char first;
char second;
}half;
}number;
number.i=0x4241;
printf("%c%cn", number.half.first, mumber.half.second);
number.half.first='a';
number.half.second='b';
printf("%xn", number.i);
getch();
}
答案: AB (0x41對應'A',是低位;Ox42對應'B',是高位)
6261 (number.i和number.half共用一塊位址空間)
11. 已知strcpy的函數原型:char *strcpy(char *strDest, const char *strSrc)其中strDest 是目的字元串,strSrc 是源字元串。不調用C++/C 的字元串庫函數,請編寫函數 strcpy。
答案:
char *strcpy(char *strDest, const char *strSrc)
{
if ( strDest == NULL || strSrc == NULL)
return NULL ;
if ( strDest == strSrc)
return strDest ;
char *tempptr = strDest ;
while( (*strDest++ = *strSrc++) != ‘0’)
;
return tempptr ;
}
12. 已知String類定義如下:
class String
{
public:
String(const char *str = NULL); // 通用構造函數
String(const String &another); // 拷貝構造函數
~ String(); // 析構函數
String & operater =(const String &rhs); // 指派函數
private:
char *m_data; // 用于儲存字元串
};
嘗試寫出類的成員函數實作。
答案:
String::String(const char *str)
{
if ( str == NULL ) //strlen在參數為NULL時會抛異常才會有這步判斷
{
m_data = new char[1] ;
m_data[0] = '0' ;
}
else
{
m_data = new char[strlen(str) + 1];
strcpy(m_data,str);
}
}
String::String(const String &another)
{
m_data = new char[strlen(another.m_data) + 1];
strcpy(m_data,other.m_data);
}
String& String::operator =(const String &rhs)
{
if ( this == &rhs)
return *this ;
delete []m_data; //删除原來的資料,新開一塊記憶體
m_data = new char[strlen(rhs.m_data) + 1];
strcpy(m_data,rhs.m_data);
return *this ;
}
String::~String()
{
delete []m_data ;
}
13. .h頭檔案中的ifndef/define/endif 的作用?
答:防止該頭檔案被重複引用。
14. #i nclude 與#i nclude "file.h"的差別?
答:前者是從Standard Library的路徑尋找和引用file.h,而後者是從目前工作路徑搜尋并引用file.h。
15.在C++ 程式中調用被C 編譯器編譯後的函數,為什麼要加extern “C”?
首先,作為extern是C/C++語言中表明函數和全局變量作用範圍(可見性)的關鍵字,該關鍵字告訴編譯器,其聲明的函數和變量可以在本子產品或其它子產品中使用。
通常,在子產品的頭檔案中對本子產品提供給其它子產品引用的函數和全局變量以關鍵字extern聲明。例如,如果子產品B欲引用該子產品A中定義的全局變量和函數時隻需包含子產品A的頭檔案即可。這樣,子產品B中調用子產品A中的函數時,在編譯階段,子產品B雖然找不到該函數,但是并不會報錯;它會在連接配接階段中從子產品A編譯生成的目标代碼中找到此函數
extern "C"是連接配接申明(linkage declaration),被extern "C"修飾的變量和函數是按照C語言方式編譯和連接配接的,來看看C++中對類似C的函數是怎樣編譯的:
作為一種面向對象的語言,C++支援函數重載,而過程式語言C則不支援。函數被C++編譯後在符号庫中的名字與C語言的不同。例如,假設某個函數的原型為:
void foo( int x, int y );
該函數被C編譯器編譯後在符号庫中的名字為_foo,而C++編譯器則會産生像_foo_int_int之類的名字(不同的編譯器可能生成的名字不同,但是都采用了相同的機制,生成的新名字稱為“mangled name”)。
_foo_int_int 這樣的名字包含了函數名、函數參數數量及類型資訊,C++就是靠這種機制來實作函數重載的。例如,在C++中,函數void foo( int x, int y )與void foo( int x, float y )編譯生成的符号是不相同的,後者為_foo_int_float。
同樣地,C++中的變量除支援局部變量外,還支援類成員變量和全局變量。使用者所編寫程式的類成員變量可能與全局變量同名,我們以"."來區分。而本質上,編譯器在進行編譯時,與函數的處理相似,也為類中的變量取了一個獨一無二的名字,這個名字與使用者程式中同名的全局變量名字不同。
未加extern "C"聲明時的連接配接方式
假設在C++中,子產品A的頭檔案如下:
// 子產品A頭檔案 moduleA.h
#ifndef MODULE_A_H
#define MODULE_A_H
int foo( int x, int y );
#endif
在子產品B中引用該函數:
// 子產品B實作檔案 moduleB.cpp
#i nclude "moduleA.h"
foo(2,3);
實際上,在連接配接階段,連接配接器會從子產品A生成的目标檔案moduleA.obj中尋找_foo_int_int這樣的符号!
加extern "C"聲明後的編譯和連接配接方式
加extern "C"聲明後,子產品A的頭檔案變為:
// 子產品A頭檔案 moduleA.h
#ifndef MODULE_A_H
#define MODULE_A_H
extern "C" int foo( int x, int y );
#endif
在子產品B的實作檔案中仍然調用foo( 2,3 ),其結果是:
(1)子產品A編譯生成foo的目标代碼時,沒有對其名字進行特殊處理,采用了C語言的方式;
(2)連接配接器在為子產品B的目标代碼尋找foo(2,3)調用時,尋找的是未經修改的符号名_foo。
如果在子產品A中函數聲明了foo為extern "C"類型,而子產品B中包含的是extern int foo( int x, int y ) ,則子產品B找不到子產品A中的函數;反之亦然。
是以,可以用一句話概括extern “C”這個聲明的真實目的(任何語言中的任何文法特性的誕生都不是随意而為的,來源于真實世界的需求驅動。我們在思考問題時,不能隻停留在這個語言是怎麼做的,還要問一問它為什麼要這麼做,動機是什麼,這樣我們可以更深入地了解許多問題):實作C++與C及其它語言的混合程式設計。
明白了C++中extern "C"的設立動機,我們下面來具體分析extern "C"通常的使用技巧:
extern "C"的慣用法
(1)在C++中引用C語言中的函數和變量,在包含C語言頭檔案(假設為cExample.h)時,需進行下列處理:
extern "C"
{
#i nclude "cExample.h"
}
而在C語言的頭檔案中,對其外部函數隻能指定為extern類型,C語言中不支援extern "C"聲明,在.c檔案中包含了extern "C"時會出現編譯文法錯誤。
C++引用C函數例子工程中包含的三個檔案的源代碼如下:
#ifndef C_EXAMPLE_H
#define C_EXAMPLE_H
extern int add(int x,int y);
#endif
#i nclude "cExample.h"
int add( int x, int y )
{
return x + y;
}
// c++實作檔案,調用add:cppFile.cpp
extern "C"
{
#i nclude "cExample.h"
}
int main(int argc, char* argv[])
{
add(2,3);
return 0;
}
如果C++調用一個C語言編寫的.DLL時,當包括.DLL的頭檔案或聲明接口函數時,應加extern "C" { }。
(2)在C中引用C++語言中的函數和變量時,C++的頭檔案需添加extern "C",但是在C語言中不能直接引用聲明了extern "C"的該頭檔案,應該僅将C檔案中将C++中定義的extern "C"函數聲明為extern類型。
C引用C++函數例子工程中包含的三個檔案的源代碼如下:
//C++頭檔案 cppExample.h
#ifndef CPP_EXAMPLE_H
#define CPP_EXAMPLE_H
extern "C" int add( int x, int y );
#endif
//C++實作檔案 cppExample.cpp
#i nclude "cppExample.h"
int add( int x, int y )
{
return x + y;
}
extern int add( int x, int y );
int main( int argc, char* argv[] )
{
add( 2, 3 );
return 0;
}
15題目的解答請參考《C++中extern “C”含義深層探索》注解:
16. 關聯、聚合(Aggregation)以及組合(Composition)的差別?
涉及到UML中的一些概念:關聯是表示兩個類的一般性聯系,比如“學生”和“老師”就是一種關聯關系;聚合表示has-a的關系,是一種相對松散的關系,聚合類不需要對被聚合類負責,如下圖所示,用空的菱形表示聚合關系:
從實作的角度講,聚合可以表示為:
class A {...} class B { A* a; .....}
而組合表示contains-a的關系,關聯性強于聚合:組合類與被組合類有相同的生命周期,組合類要對被組合類負責,采用實心的菱形表示組合關系:
實作的形式是:
class A{...} class B{ A a; ...}
參考文章:http://blog.csdn.net/wfwd/archive/2006/05/30/763753.aspx
http://blog.csdn.net/wfwd/archive/2006/05/30/763760.aspx
17.面向對象的三個基本特征,并簡單叙述之?
1. 封裝:将客觀事物抽象成類,每個類對自身的資料和方法實行protection(private, protected,public)
2. 繼承:廣義的繼承有三種實作形式:實作繼承(指使用基類的屬性和方法而無需額外編碼的能力)、可視繼承(子窗體使用父窗體的外觀和實作代碼)、接口繼承(僅使用屬性和方法,實作滞後到子類實作)。前兩種(類繼承)和後一種(對象組合=>接口繼承以及純虛函數)構成了功能複用的兩種方式。
3. 多态:是将父對象設定成為和一個或更多的他的子對象相等的技術,指派之後,父對象就可以根據目前指派給它的子對象的特性以不同的方式運作。簡單的說,就是一句話:允許将子類類型的指針指派給父類類型的指針。
18. 重載(overload)和重寫(overried,有的書也叫做“覆寫”)的差別?
常考的題目。從定義上來說:
重載:是指允許存在多個同名函數,而這些函數的參數表不同(或許參數個數不同,或許參數類型不同,或許兩者都不同)。
重寫:是指子類重新定義複類虛函數的方法。
從實作原理上來說:
重載:編譯器根據函數不同的參數表,對同名函數的名稱做修飾,然後這些同名函數就成了不同的函數(至少對于編譯器來說是這樣的)。如,有兩個同名函數:function func(p:integer):integer;和function func(p:string):integer;。那麼編譯器做過修飾後的函數名稱可能是這樣的:int_func、str_func。對于這兩個函數的調用,在編譯器間就已經确定了,是靜态的。也就是說,它們的位址在編譯期就綁定了(早綁定),是以,重載和多态無關!
重寫:和多态真正相關。當子類重新定義了父類的虛函數後,父類指針根據賦給它的不同的子類指針,動态的調用屬于子類的該函數,這樣的函數調用在編譯期間是無法确定的(調用的子類的虛函數的位址無法給出)。是以,這樣的函數位址是在運作期綁定的(晚綁定)。
19. 多态的作用?
主要是兩個:1. 隐藏實作細節,使得代碼能夠子產品化;擴充代碼子產品,實作代碼重用;2. 接口重用:為了類在繼承和派生的時候,保證使用家族中任一類的執行個體的某一屬性時的正确調用。
20. Ado與Ado.net的相同與不同?
除了“能夠讓應用程式處理存儲于DBMS 中的資料“這一基本相似點外,兩者沒有太多共同之處。但是Ado使用OLE DB 接口并基于微軟的COM 技術,而ADO.NET 擁有自己的ADO.NET 接口并且基于微軟的.NET 體系架構。衆所周知.NET 體系不同于COM 體系,ADO.NET 接口也就完全不同于ADO和OLE DB 接口,這也就是說ADO.NET 和ADO是兩種資料通路方式。ADO.net 提供對XML 的支援。
21. New delete 與malloc free 的聯系與差別?
答案:都是在堆(heap)上進行動态的記憶體操作。用malloc函數需要指定記憶體配置設定的位元組數并且不能初始化對象,new 會自動調用對象的構造函數。delete 會調用對象的destructor,而free 不會調用對象的destructor.
22. #define DOUBLE(x) x+x ,i = 5*DOUBLE(5); i 是多少?
答案:i 為30。
23. 有哪幾種情況隻能用intialization list 而不能用assignment?
答案:當類中含有const、reference 成員變量;基類的構造函數都需要初始化表。
24. C++是不是類型安全的?
答案:不是。兩個不同類型的指針之間可以強制轉換(用reinterpret cast)。C#是類型安全的。
25. main 函數執行以前,還會執行什麼代碼?
答案:全局對象的構造函數會在main 函數之前執行。
26. 描述記憶體配置設定方式以及它們的差別?
1)從靜态存儲區域配置設定。記憶體在程式編譯的時候就已經配置設定好,這塊記憶體在程式的整個運作期間都存在。例如全局變量,static 變量。
2)在棧上建立。在執行函數時,函數内局部變量的存儲單元都可以在棧上建立,函數執行結束時這些存儲單元自動被釋放。棧記憶體配置設定運算内置于處理器的指令集。
3)從堆上配置設定,亦稱動态記憶體配置設定。程式在運作的時候用malloc 或new 申請任意多少的記憶體,程式員自己負責在何時用free 或delete 釋放記憶體。動态記憶體的生存期由程式員決定,使用非常靈活,但問題也最多。
27.struct 和 class 的差別
答案:struct 的成員預設是公有的,而類的成員預設是私有的。struct 和 class 在其他方面是功能相當的。
從感情上講,大多數的開發者感到類和結構有很大的差别。感覺上結構僅僅象一堆缺乏封裝和功能的開放的記憶體位,而類就象活的并且可靠的社會成員,它有智能服務,有牢固的封裝屏障和一個良好定義的接口。既然大多數人都這麼認為,那麼隻有在你的類有很少的方法并且有公有資料(這種事情在良好設計的系統中是存在的!)時,你也許應該使用 struct 關鍵字,否則,你應該使用 class 關鍵字。
28.當一個類A 中沒有生命任何成員變量與成員函數,這時sizeof(A)的值是多少,如果不是零,請解釋一下編譯器為什麼沒有讓它為零。(Autodesk)
答案:肯定不是零。舉個反例,如果是零的話,聲明一個class A[10]對象數組,而每一個對象占用的空間是零,這時就沒辦法區分A[0],A[1]…了。
29. 在8086 彙編下,邏輯位址和實體位址是怎樣轉換的?(Intel)
答案:通用寄存器給出的位址,是段内偏移位址,相應段寄存器位址*10H+通用寄存器内位址,就得到了真正要通路的位址。
30. 比較C++中的4種類型轉換方式?
請參考:http://blog.csdn.net/wfwd/archive/2006/05/30/763785.aspx,重點是static_cast, dynamic_cast和reinterpret_cast的差別和應用。
31.分别寫出BOOL,int,float,指針類型的變量a 與“零”的比較語句。
答案:
BOOL : if ( !a ) or if(a)
int : if ( a == 0)
float : const EXPRESSION EXP = 0.000001
if ( a < EXP && a >-EXP)
pointer : if ( a != NULL) or if(a == NULL)
32.請說出const與#define 相比,有何優點?
答案:1) const 常量有資料類型,而宏常量沒有資料類型。編譯器可以對前者進行類型安全檢查。而對後者隻進行字元替換,沒有類型安全檢查,并且在字元替換可能會産生意料不到的錯誤。
2)有些內建化的調試工具可以對const 常量進行調試,但是不能對宏常量進行調試。
33.簡述數組與指針的差別?
數組要麼在靜态存儲區被建立(如全局數組),要麼在棧上被建立。指針可以随時指向任意類型的記憶體塊。
(1)修改内容上的差别
char a[] = “hello”;
a[0] = ‘X’;
char *p = “world”; // 注意p 指向常量字元串
p[0] = ‘X’; // 編譯器不能發現該錯誤,運作時錯誤
(2) 用運算符sizeof 可以計算出數組的容量(位元組數)。sizeof(p),p 為指針得到的是一個指針變量的位元組數,而不是p 所指的記憶體容量。C++/C 語言沒有辦法知道指針所指的記憶體容量,除非在申請記憶體時記住它。注意當數組作為函數的參數進行傳遞時,該數組自動退化為同類型的指針。
char a[] = "hello world";
char *p = a;
cout<< sizeof(a) << endl; // 12 位元組
cout<< sizeof(p) << endl; // 4 位元組
計算數組和指針的記憶體容量
void Func(char a[100])
{
cout<< sizeof(a) << endl; // 4 位元組而不是100 位元組
}
34.類成員函數的重載、覆寫和隐藏差別?
答案:
a.成員函數被重載的特征:
(1)相同的範圍(在同一個類中);
(2)函數名字相同;
(3)參數不同;
(4)virtual 關鍵字可有可無。
b.覆寫是指派生類函數覆寫基類函數,特征是:
(1)不同的範圍(分别位于派生類與基類);
(2)函數名字相同;
(3)參數相同;
(4)基類函數必須有virtual 關鍵字。
c.“隐藏”是指派生類的函數屏蔽了與其同名的基類函數,規則如下:
(1)如果派生類的函數與基類的函數同名,但是參數不同。此時,不論有無virtual關鍵字,基類的函數将被隐藏(注意别與重載混淆)。
(2)如果派生類的函數與基類的函數同名,并且參數也相同,但是基類函數沒有virtual 關鍵字。此時,基類的函數被隐藏(注意别與覆寫混淆)
35. There are two int variables: a and b, don’t use “if”, “? :”, “switch”or other judgement statements, find out the biggest one of the two numbers.答案:( ( a + b ) + abs( a - b ) ) / 2
36. 如何列印出目前源檔案的檔案名以及源檔案的目前行号?
答案:
cout << __FILE__ ;
cout<<__LINE__ ;
__FILE__和__LINE__是系統預定義宏,這種宏并不是在某個檔案中定義的,而是由編譯器定義的。
37. main 主函數執行完畢後,是否可能會再執行一段代碼,給出說明?
答案:可以,可以用_onexit 注冊一個函數,它會在main 之後執行int fn1(void), fn2(void), fn3(void), fn4 (void);
void main( void )
{
String str("zhanglin");
_onexit( fn1 );
_onexit( fn2 );
_onexit( fn3 );
_onexit( fn4 );
printf( "This is executed first.n" );
}
int fn1()
{
printf( "next.n" );
return 0;
}
int fn2()
{
printf( "executed " );
return 0;
}
int fn3()
{
printf( "is " );
return 0;
}
int fn4()
{
printf( "This " );
return 0;
}
The _onexit function is passed the address of a function (func) to be called when the program terminates normally. Successive calls to _onexit create a register of functions that are executed in LIFO (last-in-first-out) order. The functions passed to _onexit cannot take parameters.
38. 如何判斷一段程式是由C 編譯程式還是由C++編譯程式編譯的?
答案:
#ifdef __cplusplus
cout<<"c++";
#else
cout<<"c";
#endif
39.檔案中有一組整數,要求排序後輸出到另一個檔案中
答案:
#i nclude
#i nclude
using namespace std;
void Order(vector& data) //bubble sort
{
int count = data.size() ;
int tag = false ; // 設定是否需要繼續冒泡的标志位
for ( int i = 0 ; i < count ; i++)
{
for ( int j = 0 ; j < count - i - 1 ; j++)
{
if ( data[j] > data[j+1])
{
tag = true ;
int temp = data[j] ;
data[j] = data[j+1] ;
data[j+1] = temp ;
}
}
if ( !tag )
break ;
}
}
void main( void )
{
vectordata;
ifstream in("c:data.txt");
if ( !in)
{
cout<<"file error!";
exit(1);
}
int temp;
while (!in.eof())
{
in>>temp;
data.push_back(temp);
}
in.close(); //關閉輸入檔案流
Order(data);
ofstream out("c:result.txt");
if ( !out)
{
cout<<"file error!";
exit(1);
}
for ( i = 0 ; i < data.size() ; i++)
out<<DATA[I]<<" ?;
40. 連結清單題:一個連結清單的結點結構
struct Node
{
int data ;
Node *next ;
};
typedef struct Node Node ;
(1)已知連結清單的頭結點head,寫一個函數把這個連結清單逆序 ( Intel)
Node * ReverseList(Node *head) //連結清單逆序
{
if ( head == NULL || head->next == NULL )
return head;
Node *p1 = head ;
Node *p2 = p1->next ;
Node *p3 = p2->next ;
p1->next = NULL ;
while ( p3 != NULL )
{
p2->next = p1 ;
p1 = p2 ;
p2 = p3 ;
p3 = p3->next ;
}
p2->next = p1 ;
head = p2 ;
return head ;
}
(2)已知兩個連結清單head1 和head2 各自有序,請把它們合并成一個連結清單依然有序。(保留所有結點,即便大小相同)
Node * Merge(Node *head1 , Node *head2)
{
if ( head1 == NULL)
return head2 ;
if ( head2 == NULL)
return head1 ;
Node *head = NULL ;
Node *p1 = NULL;
Node *p2 = NULL;
if ( head1->data < head2->data )
{
head = head1 ;
p1 = head1->next;
p2 = head2 ;
}
else
{
head = head2 ;
p2 = head2->next ;
p1 = head1 ;
}
Node *pcurrent = head ;
while ( p1 != NULL && p2 != NULL)
{
if ( p1->data <= p2->data )
{
pcurrent->next = p1 ;
pcurrent = p1 ;
p1 = p1->next ;
}
else
{
pcurrent->next = p2 ;
pcurrent = p2 ;
p2 = p2->next ;
}
}
if ( p1 != NULL )
pcurrent->next = p1 ;
if ( p2 != NULL )
pcurrent->next = p2 ;
return head ;
}
(3)已知兩個連結清單head1 和head2 各自有序,請把它們合并成一個連結清單依然有序,這次要求用遞歸方法進行。 (Autodesk)
答案:
Node * MergeRecursive(Node *head1 , Node *head2)
{
if ( head1 == NULL )
return head2 ;
if ( head2 == NULL)
return head1 ;
Node *head = NULL ;
if ( head1->data < head2->data )
{
head = head1 ;
head->next = MergeRecursive(head1->next,head2);
}
else
{
head = head2 ;
head->next = MergeRecursive(head1,head2->next);
}
return head ;
}
41. 分析一下這段程式的輸出 (Autodesk)
class B
{
public:
B()
{
cout<<"default constructor"<<ENDL;
}
~B()
{
cout<<"destructed"<<ENDL;
}
B(int i):data(i) //B(int) works as a converter ( int -> instance of B)
{
cout<<"constructed by parameter " << data <<ENDL;
}
private:
int data;
};
B Play( B b)
{
return b ;
}
(1) results:
int main(int argc, char* argv[]) constructed by parameter 5
{ destructed B(5)形參析構
B t1 = Play(5); B t2 = Play(t1); destructed t1形參析構
return 0; destructed t2 注意順序!
} destructed t1
(2) results:
int main(int argc, char* argv[]) constructed by parameter 5
{ destructed B(5)形參析構
B t1 = Play(5); B t2 = Play(10); constructed by parameter 10
return 0; destructed B(10)形參析構
} destructed t2 注意順序!
destructed t1
42. 寫一個函數找出一個整數數組中,第二大的數(microsoft)
答案:
const int MINNUMBER = -32767 ;
int find_sec_max( int data[] , int count)
{
int maxnumber = data[0] ;
int sec_max = MINNUMBER ;
for ( int i = 1 ; i < count ; i++)
{
if ( data[i] > maxnumber )
{
sec_max = maxnumber ;
maxnumber = data[i] ;
}
else
{
if ( data[i] > sec_max )
sec_max = data[i] ;
}
}
return sec_max ;
}
43. 寫一個在一個字元串(n)中尋找一個子串(m)第一個位置的函數。
KMP算法效率最好,時間複雜度是O(n+m)。
44. 多重繼承的記憶體配置設定問題:
比如有class A : public class B, public class C {}
那麼A的記憶體結構大緻是怎麼樣的?
這個是compiler-dependent的, 不同的實作其細節可能不同。
如果不考慮有虛函數、虛繼承的話就相當簡單;否則的話,相當複雜。
可以參考《深入探索C++對象模型》,或者:
http://blog.csdn.net/wfwd/archive/2006/05/30/763797.aspx
45. 如何判斷一個單連結清單是有環的?(注意不能用标志位,最多隻能用兩個額外指針)
struct node { char val; node* next;}
bool check(const node* head) {} //return false : 無環;true: 有環
一種O(n)的辦法就是(搞兩個指針,一個每次遞增一步,一個每次遞增兩步,如果有環的話兩者必然重合,反之亦然):
bool check(const node* head)
{
if(head==NULL) return false;
node *low=head, *fast=head->next;
while(fast!=NULL && fast->next!=NULL)
{
low=low->next;
fast=fast->next->next;
if(low==fast) return true;
}
return false;
}
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1541242
2007.8.23 16:13 作者:akai 收藏 | 評論:0
免安裝Oracle運作pl/sql developer
分類:DB
Sql用戶端中,雖然最便捷的是萬能而且輕量無比的Sql Workbench,唯一的遺憾是隻支援JDK5,不過這個小小的遺憾隻要配置配置就能避免。
Otherwise,Oracle來說,用起來最爽的應該還是pl/sql Developer。隻是開發機器上懶得裝肥碩的Oracle,即使是用戶端也是笨重無比。
所幸發現了一個Windows下免安裝Oracle用戶端就能使用pl/sql developer輕便的方法,分享:
1, 從http://www.oracle.com/technology/software/tech/oci/instantclient/htdocs/winsoft.html中 Download Instant Client,注意2個basic包下一個即可,不推薦basiclife
2,在磁盤建立上目錄,解壓過去,最終解壓檔案會在同一個目錄下。比如解壓到c:oracleclient
3,建立目錄c:oracleclientnetworkadmin
4,建立檔案tnsnames.ora 内容如下
oracledata =
(DESCRIPTION =
(ADDRESS_LIST =
(ADDRESS = (PROTOCOL = TCP)(HOST = yourhostIp )(PORT = 1521))
)
(CONNECT_DATA =
(SERVICE_NAME = yourSID )
)
)
5,設定pl/sql Developer的perference,主要填二個文本框 OCI Library:“c:oracleclientoci.dll”, Oracle_home: "c:oracleclient"
6,重新開機pl/sql developer, 輸入使用者名密碼,以及tnsnames.ora設定的oracledata, Enjoy it.
Trackback: http://tb.blog.csdn.net/TrackBack.aspx?PostId=1568747
2007.8.3 12:58 作者:akai 收藏 | 評論:0
Vsftpd PAM安裝配置
分類:Linux
前言:本教程主要針對有一定linux操作經驗的使用者,但相對來說也可以适用于初級使用者,但絕對不适用于“未裝過linux作業系統性的使用者”。本文收集于網上的資料,隻做了簡單的整理!大家應該看得懂!
一、軟體的安裝
#rpm –qa | grep vsftpd
//此指令用于檢查linux系統有沒有裝過vsftpd
#mount /mnt/cdrom
//挂載你的第二張linux安裝盤
#cd /mnt/cdrom/RedHat/RPMS
//進入rpm 安裝包的CD光牒目錄
#rpm –ivh vsftpd-1.1.3-.i386.rpm
//使用rpm –ivh 指令安裝vsftpd-1.1.3-.i386.rpm
#cd;eject
//彈出光驅>相當windows中光驅的彈出
二、啟動Vsftpd
#service vsftpd start //啟動Vsftpd
#pstree | grep vsftpd //檢查Vsftpd是否啟動
| -vsftpd //出現這一行,就表明Vsftpd已經啟動
三、配置虛拟使用者的Vsftpd伺服器
#cat<< ! >logins.txt
#>up //第一個使用者
#>up //第一個使用者的密碼
#>down //第二個使用者
#>down //第二個使用者的密碼
#>del //第三個使用者
#>del //第三個使用者的密碼
#>! //退出并儲存
//以上為建立的虛拟使用者和密碼,當然我隻是在舉例子,你們可以随便用其它使用者名和密碼,我這裡隻是讓你容易明白一點!
#
#db_load -T -t hash -f logins.txt /etc/vsftpd/vsftpd_login.db
//使用db_load指令生成密碼庫檔案
#chmod 600 /etc/vsftpd/vsftpd_login.db //把密碼庫檔案權限改成600
#vi /etc/pam.d/vsftp.vu //建立生成虛拟使用者所需的PAM配置檔案
//并在其中寫入如下内容,先按一下“I”鍵進入寫入狀态
auth required /lib/security/pam_userdb.so db=/etc/vsftpd/vsftpd_login
account required /lib/security/pam_userdb.so db=/etc/vsftpd/vsftpd_login
//寫完後,按“Shift+:”鍵,然後鍵入“wq”儲存vsftp.vu
#useradd –d /mnt/download virtual //建立虛拟使用者所要通路的目錄
#chmod 700 /mnt/download/ //并設定這個目錄隻有virtual使用者可以通路
//以上的“download”為你FTP的主目錄,如果你對linux不熟就按我這樣做吧
#cp /etc/vsftpd/vsftpd.conf /etc/vsftpd/vsftpd.conf.bak //這裡備份vsftpd的配置檔案
#rm /etc/vsftpd/vsftpd.conf //删除預設配置
#vi /etc/vsftpd/vsftpd.conf
//開始編輯Vsftpd的配置檔案,并加入下面的配置,然後儲存
========================================================
anonymous_enable=NO
local_enable=YES
write_enable=NO
local_umask=022
anon_upload_enable=YES
anon_mkdir_write_enable=NO
dirmessage_enable=YES
xferlog_enable=YES
connect_from_port_20=YES
xferlog_std_format=YES
ftpd_banner=Welcome to My FTP service.
chroot_list_file=/etc/vsftpd/chroot_list
anon_other_write_enable=NO
one_process_model=NO
chroot_local_user=YES
guest_enable=YES
guest_username=virtual
user_config_dir=/etc/vsftpd/vsftpd_user_conf
pam_service_name=vsftp.vu
userlist_enable=YES
listen=YES
tcp_wrappers=YES
========================================================
#
#service vsftpd restart //重新啟動Vsftpd伺服器
#mkdir /etc/vsftpd/vsftpd_user_conf //建立虛拟使用者檔案存放的目錄
//下面分别建立 up、down、del這三個FTP使用者的配置檔案
#echo “anon_world_readable_only=NO”>/etc/vsftpd/vsftpd_user_conf/up
#echo “anon_world_readable_only=NO”>/etc/vsftpd/vsftpd_user_conf/down
#echo “anon_world_readable_only=NO”>/etc/vsftpd/vsftpd_user_conf/del
//這裡要說一下,現在這三個使用者隻有讀取的權限,如果你想讓他們有其它更多的權限,如“删除、下載下傳、上傳”等,你需要通過編輯這三個檔案,并加入以下配置才能有這些權限
anon_world_readable_only=NO //讀取
write_enable=YES
anon_upload_enable=YES //上傳
anon_other_write_enable=YES //删除
anon_mkdir_write_enable=YES //建立目錄
#
#service vsftpd restart
//Vsftpd到這裡已經建成了,你可以通過up、down、del這三個帳戶進行測試,當然你可以在當初建立帳戶時,多建幾個,這個随便你建多少的!
//到這裡又有人要問了,現在這幾個使用者的目錄是局限于/mnt/download目錄下,不可以移到别的目錄上,有于以後linux伺服器的各項服務的擴充,需要進入任意一個目錄時,我們就要接着做下面的補充配置了:
#
#cat<<! >/etc/vsftpd/chroot_list
#> up
#> !
//如果我們想把up使用者鎖定在/mnt/up 這個目錄下面,需要以下配置
#mkdir /mnt/up#chmod 0777 /mnt/up
#vi /etc/vsftpd/vsftpd_user_conf/up //修改這個使用者,加入local_root=/mnt/up //那麼up這個使用者的主目錄就鎖定在/mnt這個目錄下,目錄的位置随便你們自定!
#service vsftpd restart //重新開機一下,全部完成
2007.7.29 11:49 作者:akai 收藏 | 評論:0
vsftp安裝設定
分類:Linux
在網際網路上或是企業内部,有許多站點需要高品質的FTP應用和安全的服務控制,
如何能配置高品質應用的安全站點是企業應用和一些提供下載下傳服務的網站的重要需
求。基于這個出發點,我們将使用VSFTP--very safe ftp--架設高品質應用的安全
FTP站點。
我們的步驟分為兩大步:安裝VSFTP和配置VSFTP。
第一步:安裝VSFTP
準備:下載下傳VSFTP源碼包或VSFTP的RPM包軟體,這裡我使用的是vsftpd-
1.2.1.tar.gz,這是目前VSFTP的最高版本,或是使用RPM包,我下載下傳了vsftpd-
1.1.3-8.i386.rpm,無論你使用哪種包安裝vsftp都需要有root權限。
使用tar.gz源碼包安裝VSFTP,把下載下傳的源碼包放在一個目錄下,這裡我建一個目
錄ftp,所有的操作都在這個目錄下進行:
mkdir ftp
把vsftpd-1.2.1.tar.gz複制到目錄ftp下:
cp 下載下傳vsftpd-1.2.1.tar.gz放置目錄 ftp/
進入ftp目錄:
cd ftp
接下來解壓:
tar zxvf vsftpd-1.2.1.tar.gz
解壓之後ftp目錄下多了一個名為vsftpd-1.2.1的目錄,進入該目錄編譯VSFTP:
cd vsftpd-1.2.1
編譯:
make
編譯之後目錄下多了一個可執行檔案vsftpd,
#ls -l vsftpd
-rwxr-xr-x 1 root root 77144 4月 13 21:17 vsftpd
這是vsftp的主程式。因為vsftp預設需要使用"nobody"這個使用者來配置,是以你必
須确定你的系統中有這個使用者,一般說都會有的,但為了明确起見,執行下述指令
添加nobody使用者:
#adduser nobody
adduser: user nobody exists
因為我的系統裡已經有nobody使用者了,是以提示該使用者已經存在了。
vsftp預設的配置還需要一個空的目錄(empty),該目錄的絕對路徑應該是
/usr/share/empty/,另外若ftp伺服器需要匿名使用者(anonymous)需要加一個使用者
ftp,此使用者的要求這樣:使用者目錄設為/var/ftp,它是VSFTP的匿名使用者的映射本
地使用者,即指anonymous使用者在程序中以ftp使用者身分運作 程序,但anonymous使用者
并不繼承了ftp使用者的檔案權限,它隻擁有其他組的檔案權限。可使用下述的指令
完成上面的需求:
#mkdir /var/ftp/
#useradd -d /var/ftp ftp
如果你的系統已經存在有ftp使用者的話,使用下面的指令更改目錄屬主和使用者目錄:
#chown root.root /var/ftp
#chmod og-w /var/ftp
接下來把編譯的檔案安裝到相應目錄:
make install
安裝之後,在/usr/local/sbin/目錄下有vsftpd這個主程式。
在/etc/xinetd.d下也有一個vsftpd配置檔案,這個檔案是由xinetd守護程序啟動
vsftpd的配置檔案。另外你不使用xinetd啟動vsftp的話,你應該在/etc/目錄下加
一個vsftp的配置檔案,預設的檔案名為/etc/vsftpd.conf,這個檔案你可以手動
編輯,但在我們的源碼目錄裡已經有一個樣本配置檔案了,可以直接修改這個檔案
以滿足我們的需求,現在把這個樣本配置檔案拷貝到這個目錄下:
#cp vsftpd.conf /etc/
這樣在/etc/下有一個配置檔案vsftpd.conf了。
我們來測試一下VSFTP是否能夠正常運作,我們采取使用獨立程序而不是xinetd來
啟動VSFTP,這樣要在剛才的檔案/etc/vsftpd.conf後面加入一行:
listen=YES
加入之後用下面的指令試試啟動VSFTP:
#/usr/local/sbin/vsftpd &
[1] 7208
好了,VSFTP已經啟動,程序号為7208。
接下來測試FTP(你應該确定你的機器裡沒有裡别的FTP服務軟體運作,否則使用相
同的端口會發生沖突):
# ftp 127.0.0.1
Connected to 127.0.0.1 (127.0.0.1).
220 (vsFTPd 1.2.1)
Name (127.0.0.1:root): ftp
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
OK,FTP伺服器運作正常,使用匿名使用者ftp登陸成功,你也可以使用anonymous代
替使用者名ftp,一樣可以成功登陸。
使用RPM包安裝VSFTP就容易多了,隻需要執行下面的指令:
#rpm -ivh sftpd-1.1.3-8.i386.rpm
好了,看來我們的VSFTP至此為止安裝得很正确并且運作得非常良好,這樣我們可
以進入第二大步:配置VSFTP。
第二步:配置VSFTP
a)使本地使用者能登入FTP。按照上面的源碼安裝配置我們的FTP還不能讓本地使用者登
錄,因為缺少一個認證PAM檔案,在源碼目錄下有一個RedHat/vsftpd.pam認證文
件,把它複制到/etc/pam.d/ftp。
#cp RedHat/vsftpd.pam /etc/pam.d/ftp
測試一下,假設有一個本地使用者test,登入FTP:
#ftp 127.0.0.1
Connected to 127.0.0.1 (127.0.0.1).
220 (vsFTPd 1.2.1)
Name (127.0.0.1:root): test
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
看來情況很好:)
b)配置匿名使用者有浏覽,讀寫,建立目錄權限的FTP。這種配置的FTP是極度不安全
的FTP,但在某些FTP網站上可能希望能匿名使用者能上傳檔案,是以有必要講解一下:
編輯配置VSFTP的配置檔案vsftpd.conf,在檔案加入下面幾行:
anon_world_readable_only=NO //關閉匿名使用者隻讀權限,這個選項是控制匿名用
戶隻能下載下傳具有可讀權限的檔案,絕不允許有其他權限,特别是寫權限,是以要使
匿名使用者有寫權限,應該禁止它
anon_upload_enable=YES //匿名使用者上傳權限開放
anon_mkdir_write_enable=YES //匿名使用者寫和建立目錄權限開放
write_enable=YES //這是VSFTP控制使用者改變檔案系統的權限的選項,若任何使用者
要使用改變檔案系統指令(如,讀寫,删除等等操作)都必須使它開放,預設值是NO
OK,儲存後退出。
測試:
#ftp127.0.0.1
Connected to 127.0.0.1 (127.0.0.1).
220 (vsFTPd 1.2.1)
Name (127.0.0.1:root): test
331 Please specify the password.
Password:
230 Login successful.
Remote system type is UNIX.
Using binary mode to transfer files.
ftp> put mp3.txt
local: mp3.txt remote: mp3.txt
227 Entering Passive Mode (127,0,0,1,25,17)
150 Ok to send data.
226 File receive OK.
682 bytes sent in 0.00885 secs (75 Kbytes/sec)
測試成功,匿名使用者已經有了上傳的權限。
幾點說明:
1, anon_other_write_enable選項可以使匿名使用者删除檔案目錄,一般不開啟。
2
2007.7.29 11:15 作者:akai 收藏 | 評論:0
為linux和windows安裝php和oracle10g
分類:Linux
oracle 10g instant client(免費下載下傳)是php 與遠端 oracle 資料庫連接配接的最簡單方式,它隻需要安裝三個庫。
php 通路 oracle 的目前 api 所使用的 instant client 庫稱作 oci8.(此 c 接口的名稱最早是在 oracle8 中引入的。)php oracle 8 函數 可以直接調用 oracle 8.1.7、9.x 或 10.x,或者也可以為了友善起見,使用可選的抽象類,如 pear mdb2 和 adodb。
instant client 也可以使用老版本的 php“oracle”擴充,但它調用不贊成使用的 oracle api。php 界或 oracle 建議不要使用此擴充進行新的開發。
要在 apache 上将 instant client 與 php 4 或 連用,請遵循以下步驟。需要一個現有的 oracle 資料庫;instant client 不提供 oracle 資料庫。通常情況下,此資料庫将位于其他計算機上。如果資料庫位于本地,則 oracle 元件一般早已可用,進而不需要 instant client。
軟體需求: 軟體 附注
oracle instant client 下載下傳“instant client package - basic”。在 linux 上,還應下載下傳“instant client package - sdk”。
apache httpd server php 界仍推薦 apache 1.3
php — php 超文本處理器 4.3 版或更高版本
在 windows 上啟用 php oci8 擴充
instant client 二進制檔案是 php 的 windows 預建構二進制檔案的補充。
下載下傳 php 二進制壓縮檔案(不是安裝程式版本)和 apache。按照 php 手冊中的 windows 系統上的安裝安裝它們。otn 的開放源代碼開發人員中心包含有用背景資料的連結,如“在 windows 2000/xp 上安裝 oracle、php 和 apache”,它介紹了如何安裝傳統、完整的 oracle 10g 版本(instant client 不需要此版本)。
繼續操作之前檢查 php 是否正常運作。此階段未啟用 oracle 支援。
從 otn 的 instant client 頁面下載下傳用于 windows 的 instant client basic 程式包。此壓縮檔案的大小大約為 30mb。
建立一個子目錄(例如,c:instantclient10_1),然後從壓縮檔案中複制以下庫:
oraociei10.dll
orannzsbb10.dll
oci.dll
這三個檔案的總大小大約為 80mb。
要使用 php 老版本的“oracle”擴充(在 php.ini 中使用“extension=php_oracle.dll”啟用),則複制 ociw32.dll 而非 oci.dll。
編輯此環境,将 c:instantclient10_1 添加到 path 中(位于其他 oracle 目錄之前)。
例如,在 windows 2000 上,依次單擊“開始”->“設定”->“控制台”->“系統”->“進階”->“環境變量”,編輯系統變量清單中的 path。
如果使用了 tnsnames.ora 檔案定義 oracle net 服務名稱,則将 tnsnames.ora 複制到 c:instantclient10_1,并将使用者環境變量 tns_admin 設定為 c:instantclient10_1。也可以在使用者環境變量 local 中定義預設的服務名稱。
設定必要的 oracle 全球化語言環境變量,如 nls_lang。如果沒有設定,則使用預設的本地環境。有關更多詳細資訊,請參見 oracle php 應用程式全球化概述。
無需設定不必要的 oracle 變量,如 oracle_home 和 oracle_sid。
編輯 php.ini,并不要将 oci8 擴充設為注釋:
extension=php_oci8.dll
将 extension_dir 指令設定為完整的 php 擴充 dll 路徑。在 php 4 中,dll 位于 php 軟體的“extensions”子目錄中。在 php 5 中,它們位于“ext”中。
重新啟動 apache。
要檢查是否配置了擴充,請在 web 伺服器可以讀取的地方建立一個簡單的 php 腳本。
<?php
phpinfo();
?>
使用“http://”url 将此腳本加載到浏覽器中。浏覽器頁面應包含一個顯示“oci8 support enabled”的“oci8”部分。
在 linux 上啟用 php oci8 擴充
要在 linux 上添加 oracle 連接配接,需要重新編譯 php。
開放源代碼開發人員中心包含有用背景資料的連結,如在 linux 上安裝 oracle、php 和 apache,它介紹了如何安裝傳統、完整的 oracle 10g 版本(instant client 不需要此版本)。
下載下傳并安裝 apache。例如,在您的主目錄中安裝它:
cd apache_1.3.31
./configure --enable-module=so --prefix=$home/apache --with-port=8888
make
make install
編輯 $home/apache/conf/httpd.conf 并添加:
addtype application/x-httpd-php .php
addtype application/x-httpd-php-source .phps
下載下傳并解壓縮 php。
從 otn 上的 instant client 頁面下載下傳 basic 和 sdk instant client 程式包。這兩個 rpm 的總大小大約為 30mb。
以 root 使用者的身份安裝 rpm。
rpm -uvh oracle-instantclient-basic-10.1.0.3-1.i386.rpm
rpm -uvh oracle-instantclient-devel-10.1.0.3-1.i386.rpm
第一個 rpm 将 oracle 庫置于 /usr/lib/oracle/10.1.0.3/client/lib 中,第二個 rpm 在 /usr/include/oracle/10.1.0.3/client 中建立頭 (header)。
備份此更新檔,然後将它應用于 php 的 ext/oci8/config.m4。該更新檔的行号是基于 php 4.3.9 的。如果已修複了 php 錯誤 31084(很有可能已在 php 4.3.11 和 5.0.4 中修複),則不需要此更新檔。
如果使用的是 php 4.3.9 或 4.3.10,則可以将此更新檔儲存到一個檔案中(如 php_oci8ic_buildpatch),然後使用以下指令安裝它:
patch -u config.m4 php_oci8ic_buildpatch
此更新檔建立一個新的 php 配置參數:--with-oci8-instant-client.在 linux 上,預設情況下,它使用從 rpm 中安裝的最新版本的 instant client。可以指定 oracle 庫所在的目錄來使用其他版本。無論在哪種情況下,都将自動使用正确的 sdk 頭。
新參數與現有的 --with-oci8 參數互斥。
例如:在非 linux 平台上,将 instant client 程式包解壓縮到您所選擇的目錄中。--with-oci8-instant-client 參數将需要明确指定此目錄;例如,--with-oci8-instant-client=/home/instantclient10_1。應将 instant client sdk 解壓縮到與基本程式包相同的目錄中,以便修改後的配置腳本可以找到頭檔案的子目錄。
在頂層 php 目錄中重新建構“configure”腳本。
cd php-4.3.9
rm -rf autom4te.cache config.cache
./buildconf --force
使用新選項運作 configure。此示例使用安裝在主目錄中的 apache。
./configure
--with-oci8-instant-client
--prefix=$home/php --with-apxs=$home/apache/bin/apxs
--enable-sigchild --with-config-file-path=$home/apache/conf
重建 php。
make
make install
将 php 配置複制到 --with-config-file-path 指定的位置
cp php.ini-recommended $home/apache/conf/php.ini
将 ld_library_path 設定為 /usr/lib/oracle/10.1.0.3/client/lib 并重新啟動 apache。
如果使用了 tnsnames.ora 檔案定義 oracle net 服務名稱,則将 tns_admin 設定為包含此檔案的目錄。
啟動 apache 之前應設定所有 oracle 環境變量。以下腳本可以幫助完成此操作:
#!/bin/sh
apachehome=/home/apache
ld_library_path=/usr/lib/oracle/10.1.0.3/client/lib:${ld_library_path}
tns_admin=/home
export ld_library_path tns_admin
echo starting apache
$apachehome/apachectl start
要确認是否配置了擴充,請在 web 伺服器可以讀取的地方建立一個簡單的 php 腳本。
<?php
phpinfo();
?>
使用類似“http://localhost:8888/<path>/phpinfo.php”的 url 将此腳本加載到浏覽器中。浏覽器頁面應包含一個顯示“oci8 support enabled”的“oci8”部分。
連接配接到 oracle
oracle 連接配接資訊被傳遞給 ocilogon() 來建立連接配接。與 instant client 關聯的工具通常“遠離”任何資料庫伺服器,是以必須将 oracle net 連接配接辨別符與使用者名和密碼一起使用。對于已建立的 oracle 資料庫,連接配接資訊有可能是衆所周知的。對于新系統,此資訊由 oracle 安裝程式在安裝資料庫時提供。此安裝程式應配置了 oracle net 和建立了一個服務名稱。
在新資料庫中,可能需要将示範模式(如 hr 使用者)解除鎖定并向其提供密碼。也可通過在 sql*plus 中以 system 使用者身份連接配接并執行以下語句來完成此操作:
alter user 使用者名 identified by 新密碼 account unlock;
将連接配接資訊傳遞給 php 有多種方法。第一個示例使用 oracle 10g的 easy connect 文法連接配接到 在 mymachine 上運作的 mydb 資料庫服務中的 hr 模式。不需要 tnsnames.ora 或其他 oracle network 檔案:
$c = ocilogon("hr", "hr_password", "//mymachine.mydomain/mydb");
有關 easy connect 的文法,請參見 oracle 的使用 easy connect 命名方法文檔。
或者,如果 /home/tnsnames.ora 包含:
mydb =
(description=
(address = (protocol = tcp)(host = mymachine.mydomain)(port = 1521))
(connect_data=
(server = dedicated)
(service_name = mydb)
)
)
且 tns_admin 環境變量設定為 /home(在啟動 apache 之前),則連接配接字元串可以為:
$c = ocilogon("hr", "hr_password", "mydb");
如果環境變量 local(在 windows 上)或 two_task (在 linux 上)設定為 mydb,則可以使用以下代碼生成與 mydb 連接配接:
$c = ocilogon("hr", "hr_password");
使用 oracle
當基本連接配接可以使用時,試着運作一個簡單的腳本 testoci.php。根據您的資料庫修改該連接配接的詳細資訊并在浏覽器中加載它。此示例列出了使用者 hr 擁有的所有表:
<?php
$conn = ocilogon("hr", "hr_password", "//mymachine.mydomain:port/mydb);
$query = "select table_name from user_tables";
$stid = ociparse($conn, $query);
ociexecute($stid, oci_default);
while ($succ = ocifetchinto($stid, $row)) {
foreach ($row as $item) {
echo $item." ";
}
echo "<br>n";
}
ocilogoff($conn);
?>
故障診斷
oracle php 故障診斷常見問題解答包含有關連接配接 oracle 的有用資訊。
可以從 instant client 頁面下載下傳 oracle 的 sql*plus 指令行工具來幫助解決環境問題和連接配接問題。另請參見 sql*plus instant client 版本說明。
檢查 sql*plus 使用的環境是否與 phpinfo.php 顯示的環境相同。
windows 幫助
如果 phpinfo.php 腳本沒有生成顯示“oci8 support enabled”的“oci8”部分,則确認在 php.ini 中沒有将“extension=php_oci8.dll”設為注釋。
如果 path 設定錯誤,或找不到 oracle 庫,則啟動 apache 将顯示警告:“在指定的路徑中找不到動态連結庫 oci.dll。”phpinfo() 頁面的 environment 部分将顯示 path 的值以及 php 實際使用的 oracle 變量。
如果 php.ini 的 extension_dir 指令不正确,則在啟動 apache 将顯示警告:“php 啟動:無法加載動态庫 php_oci8.dll。”
linux 幫助
仔細檢查是否正确修複了 config.m4。如果“configure”失敗,則檢查 config.log 檔案。還原 config.m4,删除緩存檔案,運作 ./buildconf --force and configure,驗證問題是否與所做的更改相關。
確定“configure”上的時間戳是目前的。删除所有緩存檔案,并在必要時重建它。
在啟動 apache 的 shell 中設定所有必要的 oracle 環境變量。
2007.7.25 15:02 作者:akai 收藏 | 評論:0
Linux Apache Mysql PHP典型配置
分類:PHP
版權聲明:可以任意轉載,轉載時請務必以超連結形式标明文章原始出處和作者資訊及本聲明
http://www.5ilinux.com/lamp01.html
關鍵字:apache+mysql+php apache mysql php 配置 lamp 伺服器 web
Linux+Apache+Mysql+PHP典型配置
調試環境:Redhat9.0 Apache1.3.29 Mysql3.23.58 PHP4.3.4
Linux 系統的安裝我就不講了,這是基本功,其實這篇文章在類似Redhat的其他linux也應該通用,大家隻要掌握我提供的方法就行。記得安裝 Redhat9。0的時候不要安裝系統預設的apache,mysql和php以及相關的軟體。已經安裝的請用rpm -e * 删除已經安裝的包。
1.安裝Mysql3.23.58
其實老實說直接安裝Mysql官方網站提供的rpm包也是一個比較可行的辦法,他的官方網站的rpm包的提供基本跟tar包發行是同步的,這點我比較喜歡,至少安裝rpm包的在後面的調試中不會出現mysql庫檔案找不到的情況。但這裡還是有必要講一下自定義安裝的步驟,畢竟網友自定義安裝的還說挺多的。
軟體擷取:http://www.mysql.com/downloads/index.html
安裝步驟:
tar zxvf mysql-3.23.58.tar.gz
cd mysql-3.23.58
./configure --prefix=/usr/local/mysql --sysconfdir=/etc --localstatedir=/var/lib/mysql
make
make install
#prefix=/usr/local/mysql mysql安裝的目标目錄
#sysconfdir=/etc my.ini配置檔案的路徑
#localstatedir=/var/lib/mysql 資料庫存放的路徑
安裝完以後要初始化資料庫,當然你是更新的話不用做這步;
/usr/local/mysql/bin/mysql_install_db
如果系統沒有mysql這個使用者的話,最好做以下這步:
useradd -M -o -r -d /var/lib/mysql -s /bin/bash -c "MySQL Server" -u 27 mysql
然後我啟動mysql
/usr/local/mysql/bin/safe_mysqld &
ok,先看看mysql能否正常工作
mysql -uroot mysql
一般情況下都是不能正常連結資料庫,錯誤提示一般為:
ERROR 2002: Can't connect to local MySQL server through socket '/var/lib/mysql/mysql.sock' (2)
其實網上大家問的最多的都是整個問題,說什麼連結不到mysqld.sock,其實大家不妨看看mysql的錯誤日志就明白怎麼回事,我這裡的錯誤日志是在
/var/lib/mysql/*.err 你會發現mysql隻是以不能啟動,是因為/var/lib/mysql的權限不允許mysql服務通路,英文mysql預設是調用mysql使用者來啟動服務的,好了,既然知道是什麼原因找到不能啟動,那就簡單了。我們隻要
chown -R mysql:mysql /var/lib/mysql 就行,如果還是啟動不了,再慢慢調試權限,反正一般啟動不了都是權限的問題。
如果大家還是不能啟動不了的話,那就用我的比較繁瑣的權限的設定,反正我每次都是這麼做的,一般不會有問題,見下:
chown -R root /usr/local/mysql
chgrp -R mysql /usr/local/mysql
chown -R root /usr/local/mysql/bin
chgrp -R mysql /usr/local/mysql/bin
chgrp -R mysql /var/lib/mysql
chmod 777 /var/lib/mysql
chown -R root /var/lib/mysql/mysql
chgrp -R mysql /var/lib/mysql/mysql
chmod 777 /var/lib/mysql/mysql
chown -R root /var/lib/mysql/mysql/*
chgrp -R mysql /var/lib/mysql/mysql/*
chmod 777 /var/lib/mysql/mysql/*
chmod 777 /usr/local/mysql/lib/mysql/libmysqlclient.a
做完上面的步驟,然後把你編譯目錄的一個腳本COPY過去
cp support-files/mysql.server /etc/rc.d/init.d/mysqld
chkconfig --add mysqld
用ntsysv設定使mysql每次啟動都能自動運作。
好了,至此mysql安裝完畢,你可以這樣起動你的mysql服務
/etc/rc.d/init.d/mysqld start
下面這步比較關鍵,
ln -s /usr/local/mysql/lib/mysql /usr/lib/mysql
ln -s /usr/local/mysql/include/mysql /usr/include/mysql
大家可以不做這步,大可以在編譯其他軟體的時候自定義myslq的庫檔案路徑,但我還是喜歡把庫檔案連結到預設的位置,這樣你在編譯類似PHP,Vpopmail等軟體時可以不用指定mysql的庫檔案位址。
2.安裝Apache1.3.29。我沒有選擇安裝Apache2.0是我對他還是不放心,因為網上最新公布的apache的漏洞基本上是針對2.0,當然大家可以自己選擇安裝相應的版本。我這裡講的都是采用DSO動态編譯的方法編譯Apache.
至于有關apache的編譯方法,可以參考我以前的文章《apache的靜态/動态編譯在apache+php+mysql的應用》http://www.5ilinux.com/apache01.html
軟體擷取:http://httpd.apache.org/
tar zvxf apache_1.3.29.tar.gz
cd apache_1.3.29
修改src/include/httpd.h 增大最大線程數
#define HARD_SERVER_LIMIT 256
改成
#define HARD_SERVER_LIMIT 2560
儲存退出編譯apache
./configure --prefix=/usr/local/apache --enable-module=so --enable-module=rewrite --enable-shared=max --htdocsdir=/var/www &&
make &&
make install
# 這裡我們通過enable-module參數告訴設定腳本,我們需要啟動so和rewrite子產品,so子產品是用來提DSO支援的apache核心子產品,而rewrite子產品則是用意實作位址重寫的子產品,由于rewrite子產品需要DBM支援,如果在初次安裝時沒有編譯進apache,以後需要用到時需要重新編譯整個apache才可以實作。為此除非你可以确定以後不會用到rewrite子產品,否則還是建議你在第一次編譯的時候把rewrite子產品編譯好。
enable-shared=max 這個參數的作用時編譯apache時,把除了so以外的所有apache的标準子產品都編譯成DSO子產品。而不是編譯進apache核心内。
好了安裝apache很簡單的哦,啟動apache看看
/usr/local/apache/bin/apachectl start
然後用ie看http://你的伺服器位址。應該能看到熟悉的apache羽毛标志。
3.安裝PHP4.3.4
軟體擷取:http://www.php.net/downloads.php
tar zvxf php-4.3.4.tar.gz
cd php-4.3.4
./configure
--prefix=/usr/local/php
--with-mysql=/usr/local/mysql
--enable-force-cgi-redirect
--with-freetype-dir=/usr
--with-png-dir=/usr
--with-gd --enable-gd-native-ttf
--with-ttf
--with-gdbm
--with-gettext
--with-iconv
--with-jpeg-dir=/usr
--with-png
--with-zlib
--with-xml
--enable-calendar
--with-apxs=/usr/local/apache/bin/apxs
make
make install
# 我這裡由于伺服器需要用到GD庫,是以加了一些支援GD的編譯參數,GD直接用了redhat自帶的GD庫,大家沒有安裝的話可以從安裝盤安裝,注意除了安裝GD以外,還要安裝libjpeg,libpng等庫檔案。另外--with-mysql=/usr/local/mysql指向你安裝mysql的路徑。--with-apxs指向apache的apxs檔案的路徑。
vi /usr/local/apache/conf/httpd.conf
查找
在此範圍添加
AddType application/x-httpd-php .php
AddType application/x-httpd-php-source .phps
然CPOPY PHP的配置檔案
cp ../php4.3.4/php.ini.dist /usr/local/php/lib/php.ini
修改php.ini檔案
register_globals = On
ok!重新啟動一下apache伺服器
/usr/local/apache/bin/apachectl restart
然後寫個php測試頁info.php:内容如下
<?php
phpinfo();
?>
正常的話,應該能看到php的資訊了,恭喜你的Apche+Mysql+PHP安裝成功。
好了寫了這麼多,希望對大家有所幫助!!!
參看文檔:
apache的靜态/動态編譯在apache+php+mysql的應用 http://www.5ilinux.com/apache01.html
作者:張微波
2003年12月3日于北京
2007.7.23 14:49 作者:akai 收藏 | 評論:0
Linux下安裝Apache
分類:Linux
1.先去www.apache.com下載下傳apache,這裡我下的是httpd-2.2.3.tar.gz
2.複制這個壓縮檔案到安裝目錄下這裡我把他放在/usr/local/下
3.解壓這個檔案tar xzvf httpd-2.2.3.tar.gz 得到一個httpd-2.2.3的檔案
4.然後打開這個檔案cd httpd-2.2.3
5.然後進行安裝軟體前的配置,這幾乎是裝軟體都需要進行的操作.
./configure --prefix=/usr/local/apache --enable-cgi --enable-so --enable-rewrite=shared --enable-speling=shared
其中/usr/local/apache是你将要安裝的目錄,
6.然後編譯執行指令make
7.然後安裝執行指令make install
然後去/usr/local/apache/bin下運作apachectl start
8.測試是否安裝成功
在網頁中輸入自己安裝機器的ip位址就可以了.如果看到
It works!
那就是安裝成功了,如果看不到,就失敗
失敗的可能是配置檔案沒配置好
9.去/etc/init.d/下檢視httpd檔案
10.把其中2行改成如下
apachectl=/usr/local/apache/bin/apachectl //這裡是你安裝目錄下的
httpd=${HTTPD-/usr/local/apache/bin/httpd} //這裡是你安裝目錄下的
以前這裡不是的,這裡是我改了後的結果,找到這個地方改了,儲存,然後重新開機動伺服器,然後啟動服務前面那中啟動方法也行.或者直接到/etc/init.d/下去運作httpd start也可以.好了,看看安裝成功沒.
2007.7.23 14:48 作者:akai 收藏 | 評論:0
PHP字元串操作入門教程
分類:PHP
無論哪種語言,字元串操作都是一個重要的基礎,往往是簡單而重要。正像人說話一樣,一般有形體(圖形界面),有語言(print 字元串?),顯然字元串能解釋更多的東西。PHP提供了大量的字元串操作函數,功能強大,使用也比較簡單,詳細請參看 http://cn2.php.net/manual/zh/ref.strings.php . 以下将簡單的講述它的功能和特性。
弱類型
PHP是弱類型語言,是以其它類型的資料一般可以直接應用于字元串操作函數裡,而自動轉換成字元串類型,進行處理,如:
PHP:
--------------------------------------------------------------------------------
echo substr("1234567", 1, 3);
和
PHP:
--------------------------------------------------------------------------------
echo substr(123456,1, 3);
是一樣的
定義
一般用雙引号或單引号辨別一個字元串。比如
PHP:
--------------------------------------------------------------------------------
$str = "i love u";
$str = 'i love u';
它者兩者是有一些差別的。後者将一切單引号的内容都會當作字元處理;前者則不然。比如
PHP:
--------------------------------------------------------------------------------
$test = "iwind";
$str = "i love $test";
$str1 = 'i love $test';
echo $str; //将得到 i love iwind
echo $str1; //将得到 i love $test
同樣的以下兩個例子的行為也不一樣的:
PHP:
--------------------------------------------------------------------------------
echo "i love test"; // 将得到 i love est,已經将t視為轉義
echo 'i love test'; // 将得到 i love test
進而可以簡單認為雙引号裡的内容是經過“解釋”過的,單引号的是“所見即所得”的。顯而易見,雙引号形式的更為靈活一些,當然單引号會适用于一些特殊的場合,這裡就不作闡述了。
輸出
PHP裡的輸出最常用的是echo,print.兩者都不是真正的函數,而是語言構造,是以調用時不必用雙括号(比如echo("test");print("test")).在輸出的時候兩者都可以實作指派:
PHP:
--------------------------------------------------------------------------------
echo $str="test"; //一方面輸出test,一方面把"test"賦給字元串變量 $str
print $str="test";
兩者除了名字不一樣外,還是有其它差別的。print具有傳回值,一直傳回1,而echo沒有,是以echo比print要快一些:
PHP:
--------------------------------------------------------------------------------
$return = print "test";
echo $return; // 輸出1
也正因為這個原因,print能應用于複合語句中,而echo不能:
PHP:
--------------------------------------------------------------------------------
isset($str) or print "str 變量未定義"; // 将輸出"str 變量未定義"
isset($str) or echo "str 變量未定義";// 将提示分析錯誤
echo一次可輸出多個字元串,而print則不可以:
PHP:
--------------------------------------------------------------------------------
echo "i ","love ","iwind"; // 将輸出 "i love iwind"
print "i ","love ","iwind"; // 将提示錯誤
echo,print還可以輸出被稱作“文檔句法”的字元串,句法如:
PHP:
--------------------------------------------------------------------------------
echo <<< 标簽名稱
...
字元串内容
...
标簽名稱;
比如
PHP:
--------------------------------------------------------------------------------
echo <<< test
i love iwind
test;
要注意的是語句開始和結束的兩個标簽名稱是一樣的,且後一個标簽名稱前不能有空白,即要頂格寫。文檔句法輸出的内容識别變量名稱和常用符号,大緻形同雙引号的作用。
輸出echo,print外,PHP還提供了一些格式化字元串的函數,比如printf,sprintf,vprintf,vsprintf,在這裡不作詳解。
連接配接
兩個以上的字元串連接配接用"."操作符,依字元串的順序形成新的字元串。
PHP:
--------------------------------------------------------------------------------
$str = "i " . "love " . "iwind";
這裡的$str 就是 "i love iwind";字元串。當然,還可以使用 .= 操作符:
$str = ""; // 初始化
$str .= "i love iwind";
這裡用到了初始化,是因為未定義變量在使用時會産生一個notice錯誤,""或者null可以簡單地代表空字元串。
長度
PHP提供strlen函數來計算字元串的長度:
PHP:
--------------------------------------------------------------------------------
$str = "test";
echo strlen($str); // 将輸出 4
有點奇怪的是strlen将中日等漢字以及全角字元都當作兩個或四個長度計算。好在mbstring或icon兩個函數可以幫助解決這個問題,比如:
PHP:
--------------------------------------------------------------------------------
$len = iconv_strlen($str, "GBK");
$len = mb_strlen($str, "GBK");
注:mbstring子產品提供了大量的對含有多位元組字元的字元串的處理函數,推薦多加應用,由于這篇文章講的是字元串入門,是以不打算詳細解說。
分隔與連接配接
PHP允許你把一個字元串按照一個分隔符進行分隔成一個數組,或者将一個數組組合成一個字元串。看下面的例子:
PHP:
--------------------------------------------------------------------------------
$str = "i love iwind";
$array = explode(" ", $str);
上面的explode函數,就把$str字元串按空格字元進行分隔,結果傳回一個數組 $array:array("i", "love", "iwind").與explode函數有類似功能的有:preg_split(), spliti(), split()等函數。
與此相反的,implode和join則能把一個數組結合成一個字元串,他們是具有完全相同功能的函數。
PHP:
--------------------------------------------------------------------------------
$array = array("i", "love", "iwind");
$str = implode(" ", $array);
例中的implode函數将數組$array的每個元素用空格字元進行連接配接,傳回一個字元串 $str: "i love iwind".
裁剪
一個字元串首和尾,可能不是你想要的部分,就可以用trim,rtrim,ltrim等函數,分别去除一個字元串兩端空格,一個字元串尾部空格,一個字元串首部空格。
PHP:
--------------------------------------------------------------------------------
echo trim(" i love iwind "); // 将得到 "i love iwind"
echo rtrim(" i love iwind "); // 将得到 " i love iwind"
echo ltrim(" i love iwind "); // 将得到 "i love iwind "
其實這三個參數不僅可以去除字元串首尾的空格,還可以去除它們的第二個參數指定的字元,如:
PHP:
--------------------------------------------------------------------------------
echo trim(",1,2,3,4,", ","); // 将得到 1,2,3,4 兩端的","号被裁掉了。
有時還會看到有人使用chop這個函數,其實它是rtrim的同義函數。
大小寫
對于英文字母來說,可以用strtoupper,strtolower将其轉變成大寫或小寫。
PHP:
--------------------------------------------------------------------------------
echo strtoupper("i love iwind"); // 将得到 I LOVE IWIND
echo strtolower("I LOVE IWIND"); // 将得到 i love iwind
比較
一般可以用 !=, == 比較兩個對象是否相等,隻是以說是兩個對象,是因為它們不一定全部為字元串,也可以為整型等等。比如
PHP:
--------------------------------------------------------------------------------
$a = "joe";
$b = "jerry";
if ($a != $b)
{
echo "不相等";
}
else
{
echo "相等";
}
如果用 !==,===(可以看到多了一個等号)比較的話,兩個對象的類型要嚴格相等才能傳回true;否則用==,!=則會将字元串自動轉換成相應的類型,以便進行比較.
PHP:
--------------------------------------------------------------------------------
22 == "22"; // 傳回 true
22 === "22"; // 傳回false
//正因為這樣,是以我們的程式時常會發生一些想不到的"意外":
0 == "我愛你"; // 傳回true
1 == "1 我愛你";// 傳回true
PHP 裡還有這樣一組用于字元串比較的函數:strcmp,strcasecmp,strncasecmp(), strncmp(),它們都是如果前者比後者大,則傳回大于0的整數;如果前者比後者小,則傳回小于0的整數;如果兩者相等,則傳回0.它們比較的原理與其它語言的規則都是一樣的。
strcmp是用于區分大小寫(即大小寫敏感)的字元串比較:
PHP:
--------------------------------------------------------------------------------
echo strcmp("abcdd", "aBcde"); // 傳回 1 (>0), 比較的是 "b"和"B"
strcasecmp用于不區分大小寫的字元串比較:
PHP:
--------------------------------------------------------------------------------
echo strcasecmp("abcdd", "aBcde"); // 傳回 -1 (<0), 比較的是"d"和"e"
strncmp用于比較字元串的一部分,從字元串的開頭開始比較,第三個參數,為要比較的長度:
PHP:
--------------------------------------------------------------------------------
echo strncmp("abcdd", "aBcde", 3); // 傳回 1 (>0), 比較了 abc 和 aBc
strncasecmp用于不區分大小寫的比較字元串的一部分,從字元串的開頭開始比較,第三個參數,為要比較的長度:
PHP:
--------------------------------------------------------------------------------
echo strncasecmp("abcdd", "aBcde", 3); // 傳回 0, 比較了 abc 和 aBc,
由于不區分大小寫,是以兩者是相同的。
還有一種情況是單單比較字元串大小,達不到我們預定的要求,比如照常理 10.gif 會比 5.gif 大,但如果應用上面幾個函數,就會傳回 -1,即表示 10.gif比5.gif,針對這種情況,PHP提供了兩個自然對比的函數strnatcmp,strnatcasecmp:
PHP:
--------------------------------------------------------------------------------
echo strnatcmp("10.gif", "5.gif"); // 傳回 1 (>0)
echo strnatcasecmp("10.GIF", "5.gif"); // 傳回 1 (>0)
替換
替換的意義在于将一個字元串的一部分進行改變,使之成為别外一個新的字元串,以滿足新的要求。PHP裡通常用str_replace("要替換的内容", "要取代原内容的字元串", "原字元串")進行替換。
PHP:
--------------------------------------------------------------------------------
echo str_replace("iwind", "kiki", "i love iwind, iwind said"); // 将輸出 "i love kiki, kiki said"
即将 原字元串中的所有"iwind"都替換成了"kiki".
str_replace是大小寫敏感的,是以對你不能設想用 str_replace("IWIND", "kiki",...)替換原字元串中的"iwind".
str_replace還可以實作多對一,多對多的替換,但無法實作一對多的替換:
PHP:
--------------------------------------------------------------------------------
echo str_replace(array("iwind", "kiki"), "people", "i love kiki, iwind said");
将會輸出
i love people, people said
第一個參數中的array("iwind", "kiki")都被替換成了"people"
PHP:
--------------------------------------------------------------------------------
echo str_replace(array("iwind", "kiki"), array("gentle man", "ladies"), "i love kiki, iwind said");
輸出 i love ladies, gentle man said 。也就是說第一個數組中的元素被第二個數組中的相對應的元素替換掉了,如果有一個數組比另一個數組元素數要少,那麼不足的都會當作空來處理。
與此有些類似的是strtr,用法請參閱手冊,它們的比較請參閱 http://diary.4kiki.net/index.php?action=info&id=372 .
此外,PHP還提供了substr_replace,實作替換一部分的字元串。文法如下:
substr_replace (原字元串, 要替代的字元串, 開始替換的位置 [, 替換的長度])
其中,開始替換的位置從0開始計算,應該小于原字元串的長度。要替換的長度是可選的。
PHP:
--------------------------------------------------------------------------------
echo substr_replace("abcdefgh", "DEF", 3); // 将輸出 "abcDEF"
echo substr_replace("abcdefgh", "DEF", 3, 2); // 将輸出 "abcDEFfgh"
第一個例子中,從第三個位置(即"d")開始替換,進而把 "defgh"都替換成了“DEF”
第二個例子中,也是從第三個位置(即"d")開始替換,但隻能替換2個長度,即到e,是以就把"de"替換成了"DEF".
PHP還提供了preg_replace,preg_replace_callback,ereg_replace,eregi_replace等函數應用正規表達式來完成字元串替換,用法請參考手冊。
查找與比對
PHP裡用于查找或者比對或者定位的函數非常多,它們都有不同的意義。這裡隻講述用得比較多的strstr,stristr.後者與前者的功能,傳回值都一樣,隻是不區分大小寫。
strstr("母字元串", "子字元串")用來查找子字元串在母字元串中第一次出現的位置,并傳回母字元串中從子字元串開始到母字元串結束的部分。比如
echo strstr("abcdefg", "e"); //将輸出 "efg"
如果找不到子字元串,則傳回空。因為可以用來判斷一個字元串中是否含有另外一個字元串:
PHP:
--------------------------------------------------------------------------------
$needle = "iwind";
$str = "i love iwind";
if (strstr($str, $needle))
{
echo "裡面有 iwind";
}
else
{
echo "裡面沒有 iwind";
}
将會輸出"裡面有 iwind"
HTML相關
1,htmlspecialchars($string)
這是它的最簡單用法,将字元串中的一些特殊字元(顧名思義)&,',"<,>轉換成它們對應的HTML實體形式:
PHP:
--------------------------------------------------------------------------------
$str = "i love <font color="red">kiki</font>, iwind said.";
echo htmlspecialchars($str);
将會輸出
i love <font color="red">kiki</font>, iwind said.
2,htmlentities($string)
将所有能轉換成實體形式的字元都轉換成實體形式。
3,html_entity_decode($string);
PHP4.3.0以後加入的具有與htmlentities($string)相反的功能。
4,nl2br($string)
将字元串中所有換行符轉變成<br /> + 換行符。如:
PHP:
--------------------------------------------------------------------------------
$str = "i love kiki,n iwind said.";
echo nl2br($str);
将會輸出
i love kiki,<br />
iwind said.
加密
加密字元串最常用的就是md5了,它将一個字元串轉換成一個長32位的唯一的字元串。
PHP:
--------------------------------------------------------------------------------
echo md5("i love iwind"); // 将輸出 "2df89f86e194e66dc54b30c7c464c21c"
PHP5給md5加了第二個參數,進而使它可以輸出16位的加密後的字元串。
到這裡,這篇字元串操作入門教程就算結束了,但上面講的這些還隻是它的冰山一角,特别是PHP5之後增加了大量的新功能,是以需要我們不斷的去學習它才有可能很好的應用。
2007.6.13 18:30 作者:akai 收藏 | 評論:0
Oracle中romwnum的用處
分類:DB
以下是我在網上查到的:
使用方法:
現有一個商品銷售表sale,表結構為:
Sale
----------------------------------------------
month char(6) --月份
sell number(10,2) --月銷售金額
create table sale (month char(6),sell number);
insert into sale values('200001',1000);
insert into sale values('200002',1100);
insert into sale values('200003',1200);
insert into sale values('200004',1300);
insert into sale values('200005',1400);
insert into sale values('200006',1500);
insert into sale values('200007',1600);
insert into sale values('200101',1100);
insert into sale values('200202',1200);
insert into sale values('200301',1300);
insert into sale values('200008',1000);
commit;
SQL> select rownum,month,sell from sale where rownum=1;(可以用在限制傳回記錄條數的地方,保證不出錯,如:隐式遊标)
ROWNUM MONTH SELL
--------- ------ ---------
1 200001 1000
SQL> select rownum,month,sell from sale where rownum=2;(1以上都查不到記錄)
沒有查到記錄
SQL> select rownum,month,sell from sale where rownum>5;
(由于rownum是一個總是從1開始的僞列,Oracle 認為這種條件不成立,查不到記錄)
沒有查到記錄
隻傳回前3條紀錄
SQL> select rownum,month,sell from sale where rownum<4;
ROWNUM MONTH SELL
--------- ------ ---------
1 200001 1000
2 200002 1100
3 200003 1200
如何用rownum實作大于、小于邏輯?(傳回rownum在4—10之間的資料)(minus操作,速度會受影響)
SQL> select rownum,month,sell from sale where rownum<10
2 minus
3 select rownum,month,sell from sale where rownum<5;
ROWNUM MONTH SELL
--------- ------ ---------
5 200005 1400
6 200006 1500
7 200007 1600
8 200101 1100
9 200202 1200
想按日期排序,并且用rownum标出正确序号(有小到大)
SQL> select rownum,month,sell from sale order by month;
ROWNUM MONTH SELL
--------- ------ ---------
1 200001 1000
2 200002 1100
3 200003 1200
4 200004 1300
5 200005 1400
6 200006 1500
7 200007 1600
11 200008 1000
8 200101 1100
9 200202 1200
10 200301 1300
查詢到11記錄.
可以發現,rownum并沒有實作我們的意圖,系統是按照記錄入庫時的順序給記錄排的号,rowid也是順序配置設定的
SQL> select rowid,rownum,month,sell from sale order by rowid;
ROWID ROWNUM MONTH SELL
------------------ --------- ------ ---------
000000E4.0000.0002 1 200001 1000
000000E4.0001.0002 2 200002 1100
000000E4.0002.0002 3 200003 1200
000000E4.0003.0002 4 200004 1300
000000E4.0004.0002 5 200005 1400
000000E4.0005.0002 6 200006 1500
000000E4.0006.0002 7 200007 1600
000000E4.0007.0002 8 200101 1100
000000E4.0008.0002 9 200202 1200
000000E4.0009.0002 10 200301 1300
000000E4.000A.0002 11 200008 1000
查詢到11記錄.
正确用法,使用子查詢
SQL> select rownum,month,sell from (select month,sell from sale group by month,sell) where rownum<13;
ROWNUM MONTH SELL
--------- ------ ---------
1 200001 1000
2 200002 1100
3 200003 1200
4 200004 1300
5 200005 1400
6 200006 1500
7 200007 1600
8 200008 1000
9 200101 1100
10 200202 1200
11 200301 1300
按銷售金額排序,并且用rownum标出正确序号(有小到大)
SQL> select rownum,month,sell from (select sell,month from sale group by sell,month) where rownum<13;
ROWNUM MONTH SELL
--------- ------ ---------
1 200001 1000
2 200008 1000
3 200002 1100
4 200101 1100
5 200003 1200
6 200202 1200
7 200004 1300
8 200301 1300
9 200005 1400
10 200006 1500
11 200007 1600
查詢到11記錄.
利用以上方法,如在列印報表時,想在查出的資料中自動加上行号,就可以利用rownum。
傳回第5—9條紀錄,按月份排序
SQL> select * from (select rownum row_id ,month,sell
2 from (select month,sell from sale group by month,sell))
3 where row_id between 5 and 9;
ROW_ID MONTH SELL
---------- ------ ----------
5 200005 1400
6 200006 1500
7 200007 1600
8 200008 1000
9 200101 1100
id="statusFrame" name="status" marginwidth="0" marginheight="0" src="http://tiger.stat.360quan.com/stat.htm?checkpoint=0&agt=mozilla/5.0%20%28windows%3B%20u%3B%20windows%20nt%205.1%3B%20zh-cn%3B%20rv%3A1.9.0.4%29%20gecko/2008102920%20firefox/3.0.4&r=http%3A//www.baidu.com/s%3Fwd%3DC%252FC%252B%252B%25B1%25CA%25CA%25D4%25A1%25A2%25C3%25E6%25CA%25D4%25CC%25E2%25C4%25BF%25B4%25F3%25BB%25E3%25D7%25DC&aN=Netscape&lg=undefined&OS=Win32&aV=5.0%20%28Windows%3B%20zh-CN%29&ntime=0.94767800%201148373299&repeatip=0&vrepeatip=0&rtime=0&quan_uid=93017992-http%3A//www.baidu.com/s%3Fwd%3DC%252FC%252B%252B%25B1%25CA%25CA%25D4%25A1%25A2%25C3%25E6%25CA%25D4%25CC%25E2%25C4%25BF%25B4%25F3%25BB%25E3%25D7%25DC&quan_vid=43146294&showp=1024x768&afid=0&quan_ucode=0&quan_zzz=0&quan_znh=0" frame width="0" scrolling="no" height="0" style="color: rgb(51, 51, 51); font-family: Arial; font-size: 14px; line-height: 26px;"> id="statusFrame2" name="status" marginwidth="0" marginheight="0" src="about:blank" frame width="0" scrolling="no" height="0" style="color: rgb(51, 51, 51); font-family: Arial; font-size: 14px; line-height: 26px;"> marginwidth="0" marginheight="0" src="http://count.stat.360quan.com/log.php?t=space&g=&h=1546817&c=73077287" frame width="0" scrolling="no" height="0" style="color: rgb(51, 51, 51); font-family: Arial; font-size: 14px; line-height: 26px;">