青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品

glxhyt

  C++博客 :: 首頁 :: 新隨筆 :: 聯(lián)系 :: 聚合  :: 管理 ::
  15 隨筆 :: 0 文章 :: 4 評(píng)論 :: 0 Trackbacks

2013年5月19日 #

http://www.who1753.com/100-bugs-in-c-cpp-opensource-projects/

俄羅斯OOO Program Verification Systems公司用自己的靜態(tài)源碼分析產(chǎn)品PVS-Studio對(duì)一些知名的C/C++開源項(xiàng)目,諸如Apache Http ServerChromiumClangCMakeMySQL等的源碼進(jìn)行了分析,找出了100個(gè)典型的Bugs。個(gè)人覺得這份列表對(duì)C/C++ 程序員有一定參考意義。與其說事后用靜態(tài)工具分析,倒不如在編碼時(shí)就提高自知自覺,避免這份列表上的錯(cuò)誤發(fā)生在你的代碼中,因此這里將部分摘錄一些Bugs(Bug編號(hào)這里不連續(xù),為的是對(duì)應(yīng)原文的編號(hào))并做簡(jiǎn)要說明。原文將這份Bug列表分為了幾類,這里也將沿用這個(gè)思路。

一、數(shù)組和字符串處理錯(cuò)誤

數(shù)組和字符串處理錯(cuò)誤是C/C++程序中最多的一類缺陷類型。這也可以看作是我們?yōu)閾碛懈咝У氐讓觾?nèi)存操作能力而付出的代價(jià)。

[#1] Wolfenstein 3D項(xiàng)目 -"只有部分對(duì)象被clear了"

1
2
3
4
5
6
7
8
void CG_RegisterItemVisuals( int itemNum )
{
       
      itemInfo_t *itemInfo;
      
      memset( itemInfo, 0, sizeof( &itemInfo ) ); 
      
}

這里的Bug出現(xiàn)在memset那一行。代碼的真實(shí)意圖是clear iteminfo這塊內(nèi)存,但調(diào)用memset時(shí),第三個(gè)參數(shù)傳入的卻是sizeof(&iteminfo),要知道 sizeof(&itemInfo) != sizeof(itemInfo_t),前者只是一個(gè)指針的大小罷了。正確的寫法是:

memset(itemInfo, 0, sizeof(itemInfo_t)); 或memset(itemInfo, 0, sizeof(*itemInfo));

[#2] Wolfenstein 3D項(xiàng)目 -"只有部分Matrix被clear了"

ID_INLINE mat3_t::mat3_t( float src[ 3 ][ 3 ] ) {
memcpy( mat, src, sizeof( src ) );
}

這里的Bug出現(xiàn)在memcpy一行。程序的原意是將clear src[3][3]這個(gè)二維數(shù)組。但這里有個(gè)坑:那就是作為函數(shù)形式參數(shù)的數(shù)組名已經(jīng)退化為指針了,對(duì)其sizeof只能得到一個(gè)指針的長(zhǎng)度,因此這里的 memcpy只是copy了一個(gè)指針的長(zhǎng)度,沒有copy全。這里的代碼是C++代碼,原文中給出了正確的改正方法 – 傳reference:

ID_INLINE mat3_t::mat3_t( float (&src)[3][3] )
{
memcpy( mat, src, sizeof( src ) );
}

[#4] ReactOS項(xiàng)目 – "錯(cuò)誤地計(jì)算一個(gè)字符串的長(zhǎng)度"

static const PCHAR Nv11Board = "NV11 (GeForce2) Board";
static const PCHAR Nv11Chip = "Chip Rev B2";
static const PCHAR Nv11Vendor = "NVidia Corporation";

BOOLEAN
IsVesaBiosOk(…)
{

if (!(strncmp(Vendor, Nv11Vendor, sizeof(Nv11Vendor))) &&
!(strncmp(Product, Nv11Board, sizeof(Nv11Board))) &&
!(strncmp(Revision, Nv11Chip, sizeof(Nv11Chip))) &&
(OemRevision == 0×311))

}

Bug處在IsVesaBiosOK中那一串strncmp調(diào)用中,代碼將一個(gè)指針的size傳入strncmp作為第三個(gè)參數(shù),導(dǎo)致 strncmp實(shí)際只是比較了字符串的前4 or 8個(gè)字節(jié),而不是字符串的全部?jī)?nèi)容。

[#6] CPU Identifying Tool項(xiàng)目 – 數(shù)組越界

#define FINDBUFFLEN 64  // Max buffer find/replace size

int WINAPI Sticky (…)
{

static char findWhat[FINDBUFFLEN] = {'\0'};

findWhat[FINDBUFFLEN] = '\0';

}

bug出在"findWhat[FINDBUFFLEN] = ‘\0′;”這一行。數(shù)組的最大長(zhǎng)度為FINDBUFFLEN,但下標(biāo)的最大值應(yīng)該是FINDBUFFLEN-1,而不是FINDBUFFLEN。因此這 行代碼顯然應(yīng)該改為findWhat[FINDBUFFLEN-1] = '\0';

[#7] Wolfenstein 3D項(xiàng)目 – 數(shù)組越界

typedef struct bot_state_s
{

char teamleader[32]; //netname of the team leader

}  bot_state_t;

void BotTeamAI( bot_state_t *bs ) {

bs->teamleader[sizeof( bs->teamleader )] = '\0';

}

"sizeof( bs->teamleader )]"這行的結(jié)果值已經(jīng)超出了數(shù)組的最大邊界,正確的代碼是:

bs->teamleader[
sizeof(bs->teamleader) / sizeof(bs->teamleader[0]) – 1
] = '\0';

[#8] Miranda IM項(xiàng)目 – 只Copy了部分字符串

struct _textrangew
{
CHARRANGE chrg;
LPWSTR lpstrText;
} TEXTRANGEW;

const wchar_t* Utils::extractURLFromRichEdit(…)
{

::CopyMemory(tr.lpstrText, L"mailto:", 7);

}

這里的bug在于L"mailto:"是寬字符串,寬字符串中的每個(gè)字符占2或4個(gè)字節(jié)(依Compiler使用的字符集編碼而定),因此這里只 copy 7個(gè)字節(jié)顯然是不夠的,應(yīng)該是7 * sizeof(wchar_t)。

[#9] CMake項(xiàng)目 – 循環(huán)內(nèi)的數(shù)組越界

static const struct {
DWORD   winerr;
int     doserr;
} doserrors[] =
{

};

static void
la_dosmaperr(unsigned long e)
{

for (i = 0; i < sizeof(doserrors); i++)
{
if (doserrors[i].winerr == e)
{
errno = doserrors[i].doserr;
return;
}
}

}

作者原本意圖la_dosmaperr中for循環(huán)的次數(shù)等于數(shù)組的元素個(gè)數(shù),但sizeof(doserrors)返回的卻是數(shù)組占用的字節(jié)個(gè)數(shù),這遠(yuǎn)遠(yuǎn)大于數(shù)組元素個(gè)數(shù),因此造成數(shù)組越界。正確的寫法:

for (i = 0; i < sizeof(doserrors) / sizeof(*doserrors); i++)

[#10] CPU Identifying Tool項(xiàng)目 – 打印到自身的字符串

char * OSDetection ()
{

sprintf(szOperatingSystem,
"%sversion %d.%d %s (Build %d)",
szOperatingSystem,
osvi.dwMajorVersion,
osvi.dwMinorVersion,
osvi.szCSDVersion,
osvi.dwBuildNumber & 0xFFFF);

sprintf (szOperatingSystem, "%s%s(Build %d)",
szOperatingSystem, osvi.szCSDVersion,
osvi.dwBuildNumber & 0xFFFF);

}

通過sprintf,szOperatingSystem字符串將自己打印到自己里面,這是十分危險(xiǎn)的,將導(dǎo)致無法預(yù)知的錯(cuò)誤結(jié)果,可能會(huì)導(dǎo)致棧溢出等嚴(yán)重問題。

[#12] Notepad++項(xiàng)目 – 數(shù)組局部clear

#define CONT_MAP_MAX 50
int _iContMap[CONT_MAP_MAX];

DockingManager::DockingManager()
{

memset(_iContMap, -1, CONT_MAP_MAX);

}

代碼的原本試圖將數(shù)組_iContMap清零,但memset的第三個(gè)參數(shù)CONT_MAP_MAX并不能代表數(shù)組的真正大小,而只是數(shù)組的元素個(gè)數(shù)而已,顯然其忘記乘以sizeof(int)了。

二、未定義行為

在C/C++的語言規(guī)范中,我們常常能看到“xx is undefined”。規(guī)范中并沒有明確表明這類錯(cuò)誤是什么樣子的,只是說取決于Compiler的實(shí)現(xiàn),也許Compiler會(huì)給出正確的結(jié)果,但這么使用卻是不可移植的。

[#1] Chromium項(xiàng)目 – 智能指針的誤用

void AccessibleContainsAccessible(…)
{

auto_ptr<VARIANT> child_array(new VARIANT[child_count]);

}

這里的問題在于使用new[]分配的內(nèi)存,在智能指針釋放時(shí)卻用了delete,這將會(huì)導(dǎo)致未定義行為。看看autoptr的destructor就知道了:

~auto_ptr() {
delete _Myptr;
}

我們可以找一些更合適的類來fix這個(gè)問題,比如boost::scopedarray。

[#2] IPP Sample項(xiàng)目 – 經(jīng)典未定義行為

template<typename T, Ipp32s size> void HadamardFwdFast(…)
{
Ipp32s *pTemp;

for(j=0;j<4;j++) {
a[0] = pTemp[0*4] + pTemp[1*4];
a[1] = pTemp[0*4] – pTemp[1*4];
a[2] = pTemp[2*4] + pTemp[3*4];
a[3] = pTemp[2*4] – pTemp[3*4];
pTemp = pTemp++;

}

}

很多人一眼就看到了"pTemp = pTemp++"這行,對(duì)于這個(gè)代碼編譯器會(huì)產(chǎn)生兩種結(jié)果截然不同的翻譯:

pTemp = pTemp + 1;
pTemp = pTemp;

TMP = pTemp;
pTemp = pTemp + 1;
pTemp = TMP;

到底是哪種呢?依賴于編譯器的實(shí)現(xiàn),甚至是優(yōu)化級(jí)別的設(shè)定。

三、與運(yùn)算優(yōu)先級(jí)相關(guān)的錯(cuò)誤

[#1] MySQL工程 – !和&的運(yùn)算優(yōu)先級(jí)

int ha_innobase::create(…)
{

if (srv_file_per_table
&& !mysqld_embedded
&& (!create_info->options & HA_LEX_CREATE_TMP_TABLE)) {

}

這段代碼原意是想測(cè)試create_info->options變量中幾個(gè)bit位的值是否set了,即!(create_info->options & HA_LEX_CREATE_TMP_TABLE),但由于!的運(yùn)算優(yōu)先級(jí)高于&,實(shí)際邏輯變成了(!create_info->options) & HA_LEX_CREATE_TMP_TABLE了。如果想要這段代碼如期工作,就不要吝嗇小括號(hào)了。

[#2] Emule工程 – *和++的運(yùn)算優(yōu)先級(jí)

STDMETHODIMP
CCustomAutoComplete::Next(…, ULONG *pceltFetched)
{

if (pceltFetched != NULL)
*pceltFetched++;

}

顯然作者原意是想對(duì)pceltFetched所指向的long型變量進(jìn)行++操作,但由于*和++的運(yùn)算優(yōu)先級(jí)沒有搞對(duì),導(dǎo)致實(shí)際上執(zhí)行了*(pceltFetched++)的操作,而不是(*pceltFetched)++操作。

[#3] Chromium項(xiàng)目 – &和!=的運(yùn)算優(yōu)先級(jí)

#define FILE_ATTRIBUTE_DIRECTORY 0×00000010

bool GetPlatformFileInfo(PlatformFile file, PlatformFileInfo* info) {

info->is_directory =
file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY != 0;

}

這個(gè)程序員的意圖是通過測(cè)試file_info.dwFileAttributes的幾個(gè)bit位的值來判定是否是目錄,邏輯上應(yīng)該是(file_info.dwFileAttributes & FILE_ATTRIBUTE_DIRECTORY) != 0,但由于!=優(yōu)先級(jí)高于&,原代碼中無括號(hào),結(jié)果邏輯變成了file_info.dwFileAttributes & (FILE_ATTRIBUTE_DIRECTORY != 0),導(dǎo)致is_directory將永遠(yuǎn)求值為true。

[#4] BCmenu項(xiàng)目 – if和else弄混

void BCMenu::InsertSpaces(void)
{
if(IsLunaMenuStyle())
if(!xp_space_accelerators) return;
else
if(!original_space_accelerators) return;

}

這又是C語言的一個(gè)“大坑”,無奈這個(gè)BCMenu項(xiàng)目的程序員掉坑里了。雖然從代碼縮進(jìn)上來看,else似乎是與最外層的if配對(duì)使用,但實(shí)際這段代碼的效果是:

if(IsLunaMenuStyle())
{
if(!xp_space_accelerators) {
return;
} else {
if(!original_space_accelerators) return;
}
}

這顯然不是程序員原意,看來括號(hào)必要時(shí)還是不能省略的。修改后的代碼如下:

if(IsLunaMenuStyle()) {
if(!xp_space_accelerators) return;
} else {
if(!original_space_accelerators) return;
}

四、格式化輸出錯(cuò)誤

[#1] ReactOS項(xiàng)目 – 錯(cuò)誤地輸出WCHAR字符

static void REGPROC_unescape_string(WCHAR* str)
{

default:
fprintf(stderr,
"Warning! Unrecognized escape sequence: \\%c'\n",
str[str_idx]);

}

%c是用來格式化輸出非寬字符的,這里用來輸出WCHAR顯然會(huì)得到錯(cuò)誤的結(jié)果,fix solution是將%c換位%C。

[#2] Intel AMT SDK項(xiàng)目 – 缺少%s 【VS2010,運(yùn)行可能會(huì)崩潰】

void addAttribute(…)
{

int index = _snprintf(temp, 1023,
"%02x%02x:%02x%02x:%02x%02x:%02x%02x:"
"%02x%02x:02x%02x:%02x%02x:%02x%02x",
value[0],value[1],value[2],value[3],value[4],
value[5],value[6],value[7],value[8],
value[9],value[10],value[11],value[12],
value[13],value[14],value[15]);

}

 

不解釋了,自己慢慢數(shù)和對(duì)照吧。

[#3] Intel AMT SDK項(xiàng)目 – 未使用的參數(shù)

bool GetUserValues(…)
{

printf("Error: illegal value. Aborting.\n", tmp);
return false;
}

然tmp是多余的。

五、書寫錯(cuò)誤

[#1] Miranda IM項(xiàng)目 – 在if中賦值

void CIcqProto::handleUserOffline(BYTE *buf, WORD wLen)
{

else if (wTLVType = 0×29 && wTLVLen == sizeof(DWORD))

}

“wTLVType = 0×29”顯然是筆誤,應(yīng)該是“wTLVType == 0×29”才對(duì)。

[#3] Clang項(xiàng)目 – 對(duì)象名書寫錯(cuò)誤

static Value *SimplifyICmpInst(…) {

case Instruction::Shl: {
bool NUW =
LBO->hasNoUnsignedWrap() && LBO->hasNoUnsignedWrap();
bool NSW =
LBO->hasNoSignedWrap() && RBO->hasNoSignedWrap();

}

從最后一行先后使用了LBO和RBO來看,前面只用了LBO的那行很可能是有問題的,正確的應(yīng)該是:

bool NUW =
LBO->hasNoUnsignedWrap() && RBO->hasNoUnsignedWrap();

[#6] G3D Content Pak項(xiàng)目 – 一對(duì)括號(hào)放錯(cuò)了地方

bool Matrix4::operator==(const Matrix4& other) const {
if (memcmp(this, &other, sizeof(Matrix4) == 0)) {
return true;
}

}

由于括號(hào)放錯(cuò)了地方,導(dǎo)致memcmp最后的參數(shù)變成了sizeof(Matrix4) == 0,這行代碼的正確寫法應(yīng)該是:

if (memcmp(this, &other, sizeof(Matrix4)) == 0) {

[#8] Apache Http Server項(xiàng)目 – 多余的sizeof

PSECURITY_ATTRIBUTES GetNullACL(void)
{
PSECURITY_ATTRIBUTES sa;
sa  = (PSECURITY_ATTRIBUTES)
LocalAlloc(LPTR, sizeof(SECURITY_ATTRIBUTES));
sa->nLength = sizeof(sizeof(SECURITY_ATTRIBUTES));

}

最后一行顯然是筆誤,sizeof(sizeof(SECURITY_ATTRIBUTES))應(yīng)該寫為sizeof(SECURITY_ATTRIBUTES)才對(duì)。

[#10] Notepad++項(xiàng)目 – 在本來應(yīng)該用&的地方使用了&&

TCHAR GetASCII(WPARAM wParam, LPARAM lParam)
{

result=ToAscii(wParam,
(lParam >> 16) && 0xff, keys,&dwReturnedValue,0);

}

(lParam >> 16) && 0xff沒有什么意義,求值結(jié)果總是true。這里的代碼應(yīng)該是(lParam >> 16) & 0xff。

[#12] Fennec Media Project項(xiàng)目 – 額外的分號(hào)

int settings_default(void)
{

for(i=0; i<16; i++);
for(j=0; j<32; j++)
{
settings.conversion.equalizer_bands.boost[i][j] = 0.0;
settings.conversion.equalizer_bands.preamp[i]   = 0.0;
}
}

這又是一個(gè)實(shí)際邏輯與代碼縮進(jìn)不符的例子。作者的原意是這樣的:

for(i=0; i<16; i++)
{
for(j=0; j<32; j++)
{
settings.conversion.equalizer_bands.boost[i][j] = 0.0;
settings.conversion.equalizer_bands.preamp[i]   = 0.0;
}
}

但實(shí)際執(zhí)行代碼邏輯卻是:

for(i=0; i<16; i++)
{
;
}

for(j=0; j<32; j++)
{
settings.conversion.equalizer_bands.boost[i][j] = 0.0;
settings.conversion.equalizer_bands.preamp[i]   = 0.0;
}

這一切都是那個(gè);導(dǎo)致的。

六、對(duì)基本函數(shù)和類的誤用

[#2] TortoiseSVN項(xiàng)目 – remove函數(shù)的誤用

STDMETHODIMP CShellExt::Initialize(….)
{

ignoredprops = UTF8ToWide(st.c_str());
// remove all escape chars ('\\')
std::remove(ignoredprops.begin(), ignoredprops.end(), '\\');
break;

}

作者意圖刪除所有'\\',但他用錯(cuò)了函數(shù),remove函數(shù)只是交換元素的位置,將要?jiǎng)h除的元素交換到尾部trash,并且返回指向trash首地址的iterator。正確的做法應(yīng)該是"v.erase(remove(v.begin(), v.end(), 2), v.end())"。

[#5] Pixie項(xiàng)目 – 在循環(huán)中使用alloca函數(shù)

inline  void  triangulatePolygon(…) {

for (i=1;i<nloops;i++) {

do {

do {

CTriVertex  *snVertex =
(CTriVertex *)alloca(2*sizeof(CTriVertex));

} while(dVertex != loops[0]);

} while(sVertex != loops[i]);

}

}

alloca函數(shù)在棧上分配內(nèi)存,因此在循環(huán)中使用alloca可能會(huì)很快導(dǎo)致棧溢出。

七、無意義的代碼

[#1] IPP Samples項(xiàng)目 – 不完整的條件

void lNormalizeVector_32f_P3IM(Ipp32f *vec[3],
Ipp32s* mask, Ipp32s len)
{
Ipp32s  i;
Ipp32f  norm;

for(i=0; i<len; i++) {
if(mask<0) continue;
norm = 1.0f/sqrt(vec[0][i]*vec[0][i]+
vec[1][i]*vec[1][i]+vec[2][i]*vec[2][i]);
vec[0][i] *= norm; vec[1][i] *= norm; vec[2][i] *= norm;
}
}

mask是Ipp32s類型指針,這樣if (mask< 0)這句代碼顯然沒啥意義,正確的代碼應(yīng)該是:

if (mask[i] < 0) continue;

[#2] QT項(xiàng)目 – 重復(fù)的檢查

Q3TextCustomItem* Q3TextDocument::parseTable(…)
{

while (end < length
&& !hasPrefix(doc, length, end, QLatin1String("</td"))
&& !hasPrefix(doc, length, end, QLatin1String("<td"))
&& !hasPrefix(doc, length, end, QLatin1String("</th"))
&& !hasPrefix(doc, length, end, QLatin1String("<th"))
&& !hasPrefix(doc, length, end, QLatin1String("<td"))
&& !hasPrefix(doc, length, end, QLatin1String("</tr"))
&& !hasPrefix(doc, length, end, QLatin1String("<tr"))
&& !hasPrefix(doc, length, end, QLatin1String("</table"))) {


}

這里對(duì)"<td"做了兩次check。

八、總是True或False的條件

[#1] Shareaza項(xiàng)目 – char類型的值范圍

void CRemote::Output(LPCTSTR pszName)
{


CHAR* pBytes = new CHAR[ nBytes ];
hFile.Read( pBytes, nBytes );

if ( nBytes > 3 && pBytes[0] == 0xEF &&
pBytes[1] == 0xBB && pBytes[2] == 0xBF )
{
pBytes += 3;
nBytes -= 3;
bBOM = true;
}

}

表達(dá)式"pBytes[0] == 0xEF"總是False。char類型的值范圍是-128~127 < 0xEF,因此這個(gè)表達(dá)式總是False,導(dǎo)致整個(gè)if condition總是為False,與預(yù)期邏輯不符。

[#3] VirtualDub項(xiàng)目 – 無符號(hào)類型總是>=0

typedef unsigned short wint_t;

void lexungetc(wint_t c) {
if (c < 0)
return;
g_backstack.push_back(c);
}

c是unsigned short類型,永遠(yuǎn)不會(huì)小于0,也就是說if (c < 0)永遠(yuǎn)為False。

[#8] MySQL項(xiàng)目 – 條件錯(cuò)誤

enum enum_mysql_timestamp_type
str_to_datetime(…)
{

else if (str[0] != ‘a’ || str[0] != 'A')
continue; /* Not AM/PM */

}

if (str[0] != ‘a’ || str[0] != 'A')這個(gè)條件永遠(yuǎn)為真。也許這塊本意是想用&&。

九、代碼漏洞

導(dǎo)致漏洞的代碼錯(cuò)誤實(shí)際上也都是筆誤、不正確的條件以及不正確的數(shù)組操作等。但這里還是想將一些特定錯(cuò)誤劃歸為一類,因?yàn)槿肭终呖梢岳眠@些錯(cuò)誤來攻擊你的代碼,獲取其利益。

[#1] Ultimate TCP/IP項(xiàng)目 – 空字符串的錯(cuò)誤檢查

char *CUT_CramMd5::GetClientResponse(LPCSTR ServerChallenge)
{

if (m_szPassword != NULL)
{

if (m_szPassword != '\0')
{

}

第二個(gè)if condition check意圖檢查m_szPassword是否為空字符串,但卻錯(cuò)誤的將指針與'\0'進(jìn)行比較,正確的代碼應(yīng)該是這樣的:

if (*m_szPassword != '\0')

[#2] Chromium項(xiàng)目 – NULL指針的處理

bool ChromeFrameNPAPI::Invoke(…)
{
ChromeFrameNPAPI* plugin_instance =
ChromeFrameInstanceFromNPObject(header);
if (!plugin_instance &&
(plugin_instance->automation_client_.get()))
return false;

}

一旦plugin_instance為NULL,!plugin_instance為True,代碼對(duì)&&后面的子條件求值,引用plugin_instance將導(dǎo)致程序崩潰。正確的做法應(yīng)該是:

if (plugin_instance &&
(plugin_instance->automation_client_.get()))
return false;

[#5] Apache httpd Server項(xiàng)目 – 不完整的緩沖區(qū)clear

#define MEMSET_BZERO(p,l)       memset((p), 0, (l))

void apr__SHA256_Final(…, SHA256_CTX* context) {

MEMSET_BZERO(context, sizeof(context));

}

這個(gè)錯(cuò)誤前面提到過,sizeof(context)只是指針的大小,將之改為sizeof(*context)就OK了。

[#7] PNG Library項(xiàng)目 – 意外的指針clear

png_size_t
png_check_keyword(png_structp png_ptr, png_charp key,
png_charpp new_key)
{

if (key_len > 79)
{
png_warning(png_ptr, "keyword length must be 1 – 79 characters");
new_key[79] = '\0';
key_len = 79;
}

}

new_key的類型為png_charpp,顧名思義,這是一個(gè)char**類型,但代碼中new_key[79] = ‘\0′這句顯然是要給某個(gè)char賦值,但new_key[n]得到的應(yīng)該是一個(gè)地址,給一個(gè)地址賦值為’\0′顯然是有誤的。正確的寫法應(yīng)該是(*new_key)[79] = '\0'。

[#10] Miranda IM項(xiàng)目 – 保護(hù)沒生效

void Append( PCXSTR pszSrc, int nLength )
{

UINT nOldLength = GetLength();
if (nOldLength < 0)
{
// protects from underflow
nOldLength = 0;
}

}

nOldLength椒UINT類型,其值永遠(yuǎn)不會(huì)小于0,因此if (nOldLength < 0)這行成了擺設(shè)。

[#12] Ultimate TCP/IP項(xiàng)目 – 不正確的循環(huán)結(jié)束條件

void CUT_StrMethods::RemoveSpaces(LPSTR szString) {

size_t loop, len = strlen(szString);
// Remove the trailing spaces
for(loop = (len-1); loop >= 0; loop–) {
if(szString[loop] != ' ')
break;
}

}

環(huán)中的結(jié)束條件loop >= 0將永遠(yuǎn)為True,因?yàn)閘oop變量的類型是size_t是unsigned類型,永遠(yuǎn)不會(huì)小于0。

十、拷貝粘貼

和筆誤不同,程序員們決不因該低估拷貝粘貼問題,這類問題發(fā)生了太多。程序員們花費(fèi)了大量時(shí)間在這些問題的debug上。

[#1] Fennec Media Project項(xiàng)目 – 處理數(shù)組元素時(shí)出錯(cuò)

void* tag_write_setframe(char *tmem,
const char *tid, const string dstr)
{

if(lset)
{
fhead[11] = '\0';
fhead[12] = '\0';
fhead[13] = '\0';
fhead[13] = '\0';
}

}

 

咋看一下,fhead[13]做了兩次賦值,似乎沒啥問題。但仔細(xì)想一下,最后那行程序員的原意極可能是想寫fhead[14] = '\0'。問題就在這里了。

[#2] MySQL項(xiàng)目 – 處理數(shù)組元素時(shí)出錯(cuò)

static int rr_cmp(uchar *a,uchar *b)
{
if (a[0] != b[0])
return (int) a[0] – (int) b[0];
if (a[1] != b[1])
return (int) a[1] – (int) b[1];
if (a[2] != b[2])
return (int) a[2] – (int) b[2];
if (a[3] != b[3])
return (int) a[3] – (int) b[3];
if (a[4] != b[4])
return (int) a[4] – (int) b[4];
if (a[5] != b[5])
return (int) a[1] – (int) b[5];
if (a[6] != b[6])
return (int) a[6] – (int) b[6];
return (int) a[7] – (int) b[7];
}

 

編寫這類代碼時(shí),我猜絕大多數(shù)人會(huì)選擇Copy-Paste,然后再逐行修改,問題就發(fā)生在修改過程中,上面的代碼中當(dāng)處理a[5] != b[5]時(shí)就忘記修改一個(gè)下標(biāo)了:return (int) a[1] – (int) b[5];顯然這里的正確代碼應(yīng)該是return (int) a[5] – (int) b[5]。

[#3] TortoiseSVN項(xiàng)目 文件名不正確

BOOL GetImageHlpVersion(DWORD &dwMS, DWORD &dwLS)
{
return(GetInMemoryFileVersion(("DBGHELP.DLL"),
dwMS,
dwLS)) ;
}

BOOL GetDbgHelpVersion(DWORD &dwMS, DWORD &dwLS)
{
return(GetInMemoryFileVersion(("DBGHELP.DLL"),
dwMS,
dwLS)) ;
}

GetImageHlpVersion和GetDbgHelpVersion都使用了"DBGHELP.DLL"文件,顯然GetImageHlpVersion寫錯(cuò)文件名了。應(yīng)該用"IMAGEHLP.DLL"就對(duì)了。

[#4] Clang項(xiàng)目 – 等同的函數(shù)體

MapTy PerPtrTopDown;
MapTy PerPtrBottomUp;

void clearBottomUpPointers() {
PerPtrTopDown.clear();
}

void clearTopDownPointers() {
PerPtrTopDown.clear();
}

我們看到雖然兩個(gè)函數(shù)名不同,但是函數(shù)體的內(nèi)容是相同的,顯然又是copy-paste惹的禍。做如下修改即可:

void clearBottomUpPointers() {
PerPtrBottomUp.clear();
}

 

十一、Null指針的校驗(yàn)遲了

這里的“遲了”的含義是先使用指針,然后再校驗(yàn)指針是否為NULL。

[#1] Quake-III-Arena項(xiàng)目 – 校驗(yàn)遲了

void Item_Paint(itemDef_t *item) {
vec4_t red;
menuDef_t *parent = (menuDef_t*)item->parent;
red[0] = red[3] = 1;
red[1] = red[2] = 0;
if (item == NULL) {
return;
}

}

 

校驗(yàn)item是否為NULL前已經(jīng)使用過item了,一旦item真的為NULL,那程序必然崩潰。

十二、其他雜項(xiàng)

[#1] Image Processing 項(xiàng)目 – 八進(jìn)制數(shù)

inline
void elxLuminocity(const PixelRGBus& iPixel,
LuminanceCell< PixelRGBus >& oCell)
{
oCell._luminance = uint16(0.2220f*iPixel._red +
0.7067f*iPixel._blue + 0.0713f*iPixel._green);
oCell._pixel = iPixel;
}

inline
void elxLuminocity(const PixelRGBi& iPixel,
LuminanceCell< PixelRGBi >& oCell)
{
oCell._luminance = 2220*iPixel._red +
7067*iPixel._blue + 0713*iPixel._green;
oCell._pixel = iPixel;
}

第二個(gè)函數(shù),程序員原意是使用713這個(gè)十進(jìn)制整數(shù),但0713 != 713,在C中,0713是八進(jìn)制的表示法,Compiler會(huì)認(rèn)為這是個(gè)八進(jìn)制數(shù)。

[#2] IPP Sample工程 – 一個(gè)變量用于兩個(gè)loop中

JERRCODE CJPEGDecoder::DecodeScanBaselineNI(void)
{

for(c = 0; c < m_scan_ncomps; c++)
{
block = m_block_buffer + (DCTSIZE2*m_nblock*(j+(i*m_numxMCU)));

// skip any relevant components
for(c = 0; c < m_ccomp[m_curr_comp_no].m_comp_no; c++)
{
block += (DCTSIZE2*m_ccomp

[/c]

.m_nblocks);
}

}

變量c用在了兩個(gè)loop中,這會(huì)導(dǎo)致只有部分?jǐn)?shù)據(jù)被處理,或外部循環(huán)中止。

[#3] Notepad++項(xiàng)目 – 怪異的條件表達(dá)式

int Notepad_plus::getHtmlXmlEncoding(….) const
{

if (langT != L_XML && langT != L_HTML && langT == L_PHP)
return -1;

}

代碼中的那行if條件等價(jià)于 if (langT == L_PHP),顯然似乎不是作者原意,猜測(cè)正確的代碼應(yīng)該是這樣的:

int Notepad_plus::getHtmlXmlEncoding(….) const
{

if (langT != L_XML && langT != L_HTML && langT != L_PHP)
return -1;

}

posted @ 2013-05-19 21:10 郭龍 閱讀(719) | 評(píng)論 (1)編輯 收藏

字符串匹配:

---willamette

在匹配串中尋找模式串是否出現(xiàn),注意和最長(zhǎng)公共子序列相區(qū)別(LCS: Longest Common Substring)

最簡(jiǎn)單的Brute Force算法:

首先將匹配串和模式串左對(duì)齊,然后從左向右一個(gè)一個(gè)進(jìn)行比較,如果不成功則模式串向右移動(dòng)一個(gè)單位。

速度最慢。

那么,怎么改進(jìn)呢?

我們注意到Brute Force算法是每次移動(dòng)一個(gè)單位,一個(gè)一個(gè)單位移動(dòng)顯然太慢,是不是可以找到一些辦法,讓每次能夠讓模式串多移動(dòng)一些位置呢?

當(dāng)然是可以的。

我們也注意到,Brute Force是很不intelligent的,每次匹配不成功的時(shí)候,前面匹配成功的信息都被當(dāng)作廢物丟棄了,當(dāng)然,就如現(xiàn)在的變廢為寶一樣,我們也同樣可以將前面匹配成功的信息利用起來,極大地減少計(jì)算機(jī)的處理時(shí)間,節(jié)省成本。^_^

首先介紹的就是KMP算法。

原始論文:Knuth D.E., Morris J.H., and Pratt V.R., Fast pattern matching in strings, SIAM Journal on Computing, 6(2), 323-350, 1977.

這個(gè)算法實(shí)在是太有名了,大學(xué)上的算法課程除了最笨的Brute Force算法,然后就介紹了KMP算法。也難怪,呵呵。誰讓Knuth D.E.這么world famous呢,不僅拿了圖靈獎(jiǎng),而且還寫出了計(jì)算機(jī)界的Bible <The Art of Computer Programming>(業(yè)內(nèi)人士一般簡(jiǎn)稱TAOCP).稍稍提一下,有個(gè)叫H.A.Simon的家伙,不僅拿了Turing Award,順手拿了個(gè)Nobel Economics Award,做了AI的爸爸,還是Chicago Univ的Politics PhD,可謂全才。

KMP的思想是這樣的:

利用不匹配字符的前面那一段字符的最長(zhǎng)前后綴來盡可能地跳過最大的距離

比如

模式串a(chǎn)babac這個(gè)時(shí)候我們發(fā)現(xiàn)在c處不匹配,然后我們看c前面那串字符串的最大相等前后綴,然后再來移動(dòng)

下面的兩個(gè)都是模式串,沒有寫出來匹配串

原始位置ababac

移動(dòng)之后 ababac

因?yàn)楹缶Y是已經(jīng)匹配了的,而前綴和后綴是相等的,所以直接把前綴移動(dòng)到原來后綴處,再從原來的c處,也就是現(xiàn)在的第二個(gè)b處進(jìn)行比較。這就是KMP。

當(dāng)然,有市場(chǎng)就有競(jìng)爭(zhēng),字符串匹配這么大一個(gè)市場(chǎng),不可能讓BF和KMP全部占了,于是又出現(xiàn)了幾個(gè)強(qiáng)勁的對(duì)手。

第一個(gè)登場(chǎng)的是Horspool算法。

論文:Horspool R.N., 1980, Practical fast searching in strings, Software - Practice & Experience, 10(6):501-506

Horspool算法的思想很簡(jiǎn)單的。不過有個(gè)創(chuàng)新之處就是模式串是從右向左進(jìn)行比較的。很好很強(qiáng)大,為后來的算法影響很大。

匹配串:abcbcsdxzcxx

模式串:cbcac

這個(gè)時(shí)候我們從右向左進(jìn)行對(duì)暗號(hào),c-c,恩對(duì)上了,第二個(gè)b-a,不對(duì)啊,我們應(yīng)該怎么辦?難道就這么放棄么。于是,模式串從不匹配的那個(gè)字符開始從右向左尋找匹配串中不匹配的字符b的位置,結(jié)果發(fā)現(xiàn)居然有,趕快對(duì)上趕快對(duì)上,別耽誤了。

匹配串:abcbcsdxzcxx

模式串: cbcac

然后繼續(xù)從最右邊的字符從右向左進(jìn)行比較。這時(shí)候,我們發(fā)現(xiàn)了,d-c不匹配啊,而且模式穿里面沒有噢,沒辦法,只好移動(dòng)一個(gè)模式串長(zhǎng)度的單位了。

匹配串:abcbcsdxzcxx

模式串: cbcac

第二個(gè)上來的是Boyer-Moore算法。

是一個(gè)很復(fù)雜的算法,當(dāng)然,雖然理論上時(shí)間復(fù)雜度和KMP差不多,但是實(shí)際上卻比KMP快數(shù)倍,可見實(shí)踐是檢驗(yàn)真理的唯一標(biāo)準(zhǔn)。

原始論文:R.S.Boyer, J.S.Moore, A fast string searching algorithm , Communications of the ACM,20(10):762-772 ,1977

分為兩步預(yù)處理,第一個(gè)是bad-character heuristics,也就是當(dāng)出現(xiàn)錯(cuò)誤匹配的時(shí)候,移位,基本上就是做的Horspool那一套。

第二個(gè)就是good-suffix heuristics,當(dāng)出現(xiàn)錯(cuò)誤匹配的時(shí)候,我還要從不匹配點(diǎn)向左看啊,以前匹配的那段子字符串是不是在模式串本身中還有重復(fù)的啊,有重復(fù)的話,那么我就直接把重復(fù)的那段和匹配串中已經(jīng)匹配的那一段對(duì)齊就是了。再比較

匹配串:abaccbabbazz

模式串:cbadcba

我們看到已經(jīng)匹配好了cba,但是c-d不匹配,這個(gè)時(shí)候我們發(fā)現(xiàn)既可以采用bad-character heuristics,也可以使用good-suffix heuristics(模式串:cbadcba),在這種情況下,邪不壓正。毅然投奔good。移動(dòng)得到

匹配串:abaccbabbazz

模式串: cbadcba

可是,我們有時(shí)候也發(fā)現(xiàn),已經(jīng)匹配好的那一部分其實(shí)并沒有再有重復(fù)了的啊。這個(gè)時(shí)候,我們發(fā)現(xiàn)已經(jīng)匹配好的那串字符串有一部分在開頭重新出現(xiàn)了,那么,趕快,對(duì)齊吧。

匹配串:abacccbbbazz

模式串:cbadccb

然后得到

匹配串:abacccbbbazz

模式串: cbadccb

當(dāng)兩種Good-Suffix出現(xiàn)的時(shí)候,取移動(dòng)距離最大的那個(gè)。

最后一個(gè)是Sunday算法,實(shí)際上比Boyer-Moore還快,呵呵。長(zhǎng)江后浪推前浪。

原始論文:Daniel M. Sunday, A very fast substring search algorithm, Communications of the ACM, v.33 n.8, p.132-142, Aug. 1990

看原始論文的題目,D.M. Sunday貌似是故意想氣氣Boyer-Moore兩位大牛似的。呵呵。不過實(shí)際上的確Sunday算法的確比BM算法要快,而且更簡(jiǎn)單。

Sunday的算法思想和Horspool有些相似,但是。當(dāng)出現(xiàn)不匹配的時(shí)候,卻不是去找匹配串中不匹配的字符在模式串的位置,而是直接找最右邊對(duì)齊的右一位的那個(gè)字符在模式串的位置。

比如:

匹配串:abcbczdxzc

模式串:zbcac

恩,這里我們看到b-a沒有對(duì)上,我們就看匹配串中的z在模式串的位置,然后,嘿嘿。

匹配串:abcbczdxzc

模式串: zbcac

如果模式串中的沒有那個(gè)字符怎么辦呢?很簡(jiǎn)單,跳過去唄。

匹配串:abcbcedxzcs

模式串:zbcac

e不在模式串中出現(xiàn)

那么我們就

匹配串:abcbcedxzcs

模式串: zbcac

 

實(shí)際上,現(xiàn)在還有很多很多字符串匹配算法,這里只是簡(jiǎn)單介紹了一下最常使用的五種算法,更多算法可以參考一下http://www.inf.fh-flensburg.de/lang/algorithmen/algo.htm,8過這個(gè)是德文網(wǎng)站,有的網(wǎng)頁沒有英文版的哦。

posted @ 2013-05-19 16:58 郭龍 閱讀(744) | 評(píng)論 (0)編輯 收藏

2012年5月15日 #

1:指針問題:
錯(cuò)誤代碼:
//A.cpp
T gTemp;
void GetA(T *p)
{
   p = &gTemp;
}

//B.cpp
T iInfo;
GetA(&iInfo);
或者
T *piInfo;
GetA(piInfo);

正確的是
//A.cpp
T gTemp;
T* GetA()
{
  return &gTemp;
}

//B.cpp
T *piInfo = GetA();

解決方案:
<<你必須知道的495個(gè)C語言問題>>
5.4 我有個(gè)函數(shù),它應(yīng)該接受并初始化一個(gè)指針 void f(int *ip) { static int dummy = 5; ip = &dummy;} 但是當(dāng)我如下調(diào)用時(shí): int *ip; f(ip); 調(diào)用者的指針卻沒有任何變化。 你確定函數(shù)初始化的是你希望它初始化的東西嗎?請(qǐng)記住在 C 中, 參數(shù)是通過值傳遞的。被調(diào)函數(shù)僅僅修改了傳入的指針副本。你需要傳入指針的地址 (函數(shù)變成接受指針的指針), 或者讓函數(shù)返回指針。


同理下面也是錯(cuò)誤的
void Swap(T* rht, T* lht)
{
T *pTemp = rht;
rht = lht;
lht = pTemp;
}

2: 計(jì)算算法時(shí)間問題

start = beginTime();
for (int i = 0; i < 100; ++ i)
   for (int j = 0; j < 1000; ++ j)
{
      //轉(zhuǎn)化函數(shù):
      A......
      //算法
      B.......
}

End = beginTime();

錯(cuò)誤地方:A....花費(fèi)2毫秒

   結(jié)果測(cè)試出現(xiàn)很大問題:
   A....花費(fèi)兩毫秒
   100*1000*2 = 200s = 3.3分鐘

 修改方案:
 
   //轉(zhuǎn)化函數(shù):
   A......
   放在外面進(jìn)行轉(zhuǎn)化
   

   start = beginTime();
   for (int j = 0; j < 1000; ++ j)
   {
      //轉(zhuǎn)化函數(shù):
     A......
   }

   for (int i = 0; i < 100; ++ i)
      for (int j = 0; j < 1000; ++ j)
   {
      //算法
      B.......
   }

  End = beginTime();

3: Hash 算法

4:for(u_short i = 100; i >= 0; --i)
   修改:
     for (u_short i = 100; i > 0; --i)
     for(int i = 100; i >= 0; --i)

5:讀寫文件, 發(fā)送消息,最好定義一個(gè)頭,那樣
   容易知道讀取的是什么,讀取的是否錯(cuò)誤
 // 消息頭
 struct TMSG_HEADER
 {
  char    cMsgID;   // 消息標(biāo)識(shí)

  TMSG_HEADER(char MsgID = INVALID_MSG)
   : cMsgID(MsgID)
  {
  }
 };


 // 請(qǐng)求傳送的文件名
 // 客戶端傳給服務(wù)器端的是全路徑名稱
 // 服務(wù)器傳回給客戶端的是文件名
 struct TMSG_FILENAME : public TMSG_HEADER
 {
  char szFileName[256];  // 保存文件名的字符數(shù)組

  TMSG_FILENAME()
   : TMSG_HEADER(MSG_FILENAME)
  {
  }
 };

 // 傳送文件長(zhǎng)度
 struct TMSG_FILELENGTH : public TMSG_HEADER
 {
  long lLength;

  TMSG_FILELENGTH(long length)
   : TMSG_HEADER(MSG_FILELENGTH), lLength(length)
  {

  }
 };


累了,以后再寫吧,↖(^ω^)↗
posted @ 2012-05-15 23:27 郭龍 閱讀(517) | 評(píng)論 (3)編輯 收藏

2012年2月6日 #

2012 目標(biāo)

1.
學(xué)一種腳本語言 python
學(xué)習(xí)一下數(shù)據(jù)結(jié)構(gòu), 練習(xí)編程之美

2.
學(xué)習(xí)網(wǎng)絡(luò)通信
看書自學(xué)

3.
研讀CppUnit自動(dòng)化測(cè)試
學(xué)習(xí)交叉編譯環(huán)境


復(fù)習(xí)去年學(xué)習(xí)的Linux知識(shí) C/C++知識(shí)
復(fù)習(xí)工作中總結(jié)點(diǎn)點(diǎn)滴滴

posted @ 2012-02-06 23:09 郭龍 閱讀(257) | 評(píng)論 (0)編輯 收藏

2011年11月27日 #

     摘要: 回調(diào)函數(shù)應(yīng)用 Code highlighting produced by Actipro CodeHighlighter (freeware)http://www.CodeHighlighter.com/-->  1#include <iostream>  2using namespace std; &...  閱讀全文
posted @ 2011-11-27 21:05 郭龍 閱讀(392) | 評(píng)論 (0)編輯 收藏

     摘要: 越來越感到自己基礎(chǔ)差了今天看到 李先靜老師 系統(tǒng)程序員成長(zhǎng)計(jì)劃 那本書上寫道 編寫通用的鏈表的于是自己練習(xí)寫了一下,主要是 void* --> int*  int*--> void*沒想到指針的生命周期,整暈了,調(diào)試了好久。  typedef struct tagNode_t{    struct tagNode_t...  閱讀全文
posted @ 2011-11-27 16:02 郭龍 閱讀(313) | 評(píng)論 (0)編輯 收藏

[轉(zhuǎn)自] http://hi.baidu.com/brady_home/blog/item/6b92aa8ffdfee2e6f01f369b.html

gdb調(diào)試正在運(yùn)行的進(jìn)程
2009年04月18日 星期六 下午 08:21
有時(shí)會(huì)遇到一種很特殊的調(diào)試需求,對(duì)當(dāng)前正在運(yùn)行的其它進(jìn)程進(jìn)行調(diào)試(正是我今天遇到的情形)。這種情況有可能發(fā)生在那些無法直接在調(diào)試器中運(yùn)行的進(jìn)程身上,例如有的進(jìn)程 只能在系統(tǒng)啟動(dòng)時(shí)運(yùn)行。另外如果需要對(duì)進(jìn)程產(chǎn)生的子進(jìn)程進(jìn)行調(diào)試的話,也只能采用這種方式。GDB可以對(duì)正在執(zhí)行的程序進(jìn)行調(diào)度,它允許開發(fā)人員中斷程序 并查看其狀態(tài),之后還能讓這個(gè)程序正常地繼續(xù)執(zhí)行。

GDB提供了兩種方式來調(diào)試正在運(yùn)行的進(jìn)程:一種是在GDB命令行上指定進(jìn)程的PID,另一種是在GDB中使用“attach”命令。例如,開發(fā)人員可以先啟動(dòng)debugme程序,讓其開始等待用戶的輸入。示例如下:

#./debugme
Enter a string to count words:


接下去在另一個(gè)虛擬控制臺(tái)中用下面的命令查出該進(jìn)程對(duì)應(yīng)的進(jìn)程號(hào):

# ps -ax | grep debugme
555 pts/1 S 0:00 ./debugme


得到進(jìn)程的PID后,就可以使用GDB對(duì)其進(jìn)行調(diào)試了:

# gdb debugme 555
GNU gdb Red Hat Linux (5.3post-0.20021129.18rh)
Attaching to program: /home/xiaowp/debugme, process 555
Reading symbols from /lib/libc.so.6...done.
……


在上面的輸出信息中,以Attaching to program開始的行表明GDB已經(jīng)成功地附加在PID為555的進(jìn)程上了。另外一種連接到其它進(jìn)程的方法是先用file命令加載調(diào)試時(shí)所需的符號(hào)表,然后再通過“attaché”命令進(jìn)行連接:

(gdb) file /home/xiaowp/debugme
Reading symbols from /home/xiaowp/debugme...done.
(gdb) attach 555
……


如果想知道程序現(xiàn)在運(yùn)行到了哪里,同樣可以使用“backtrace”命令。當(dāng)然也可以使用“step”命令對(duì)程序進(jìn)行單步調(diào)試。

在完成調(diào)試之后,不要忘記用detach命令斷開連接,讓被調(diào)試的進(jìn)程可以繼續(xù)正常運(yùn)行。
posted @ 2011-11-27 00:22 郭龍 閱讀(468) | 評(píng)論 (0)編輯 收藏

2011年11月26日 #

[轉(zhuǎn)自]http://www.wutianqi.com/?p=1822

二維數(shù)組和二級(jí)指針的傳遞問題

再次看這篇文章,感覺說的好多都是廢話,在文章最前面補(bǔ)充一句話:
[]的優(yōu)先級(jí)高于*”,大家可以帶著這句話看下面的~~~
========================
再一次的見證了自己的基礎(chǔ)不牢靠。。。幸好發(fā)現(xiàn)得早,看見網(wǎng)上說,華為的一個(gè)面試題就考了這個(gè)方面的。

借那道華為的面試題引出問題,題目:

char **p, a[16][8]; 問:p=a是否會(huì)導(dǎo)致程序在以后出現(xiàn)問題?為什么?

可能有一部分朋友會(huì)回答正確,這里他們認(rèn)為,a[]是一級(jí)指針,a[][]就是二級(jí)指針。那這個(gè)到底對(duì)不對(duì)呢?

OK,用事實(shí)說話:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
// Author: Tanky Woo
// Blog:    www.WuTianQi.com
// Note:   驗(yàn)證二維數(shù)組與二級(jí)指針的傳遞問題
#include <iostream> 
using namespace std; 
 
void Test(char **p) 
{ 
    cout << p[0][0] << endl; 
} 
 
int main() 
{ 
    char a[2][3]; 
    Test(a); 
    return 0; 
}

結(jié)果報(bào)錯(cuò):

1
2
// error C2664: “Test”: 不能將參數(shù) 1 從“char [2][3]”轉(zhuǎn)換為“char  **”
//                          與指向的類型無關(guān);轉(zhuǎn)換要求 reinterpret_cast、C  樣式轉(zhuǎn)換或函數(shù)樣式轉(zhuǎn)換

于是乎,我看了下《C專家編程》里10.5節(jié)—使用指針向函數(shù)傳遞一個(gè)多維數(shù)組

方法一:

函數(shù)是:

1
void fun1(int arr[2][3]);

這種方法導(dǎo)致只能處理2行3列的int型數(shù)組。

方法二:

可以省略第一維的長(zhǎng)度。

函數(shù)是:

1
void fun2(int arr[][3]);

這種方法的限制略微寬松了一些,但是還是只能處理每行是3個(gè)整數(shù)長(zhǎng)度的數(shù)組。

函數(shù)也可以寫成:

1
void fun2_2(int (*arrr)[3]);

方法三:

創(chuàng)建一個(gè)一維數(shù)組,數(shù)組中的元素是指向其他東西的指針。也可以說是二級(jí)指針。

函數(shù)是:

1
int fun3(int **arr);

注意:只有把二維數(shù)組改為一個(gè)指向向量的指針數(shù)組的前提下才可以這么做!

比如:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
#include <iostream> 
using namespace std; 
 
void test(char **ptr) 
{ 
    cout << *ptr << endl; 
} 
 
int main() 
{ 
    char *p[3] = {"abc", "def", "ghi"}; 
    test(p); 
    return 0; 
}

在《C專家編程》10.3節(jié)的小啟發(fā)里講的很透徹:(以下這段文字及對(duì)比一定要認(rèn)真分析!)

數(shù)組和指針參數(shù)是如何被編譯器修改的?

數(shù)組名被改寫成一個(gè)指針參數(shù)”規(guī)則并不是遞歸定義的。數(shù)組的數(shù)組會(huì)被改寫成“數(shù)組的指針”,而不是“指針的指針”:

實(shí)參 所匹配的形參

數(shù)組的數(shù)組 char c[8][10]; char (*)[10]; 數(shù)組指針

指針數(shù)組 char *c[10]; char **c; 指針的指針

數(shù)組指針(行指針) char (*c)[10]; char (*c)[10]; 不改變

指針的指針 char **c; char **c; 不改變

我在CSDN上專門為這個(gè)問題提問過:

http://topic.csdn.net/u/20101221/12/da817bda-4e88-44df-bdf8-40e8f44aacb8.html?2076366575

最后我總結(jié)下討論結(jié)果:

只要實(shí)參的類型與形參的類型一致(或可轉(zhuǎn)換)就行。

為什么這么說呢?

piaojun_pj朋友給了一段代碼,分析得很給力:

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
// VectorTest.cpp : 定義控制臺(tái)應(yīng)用程序的入口點(diǎn)。 
// 
 
#include "stdafx.h" 
#include <iostream> 
using namespace std; 
 
int _tmain(int argc, _TCHAR* argv[]) 
{ 
    int arr1[3]; 
    int arr2[3]; 
    int arr3[3]; 
    int * ptr; 
    // ptr1是一個(gè)指向 int [3] 的指針,即ptr的類型和&arr1的類型是一樣的,注意:arr1指向的內(nèi)存區(qū)域定長(zhǎng) 
    int ptr1[3][3]={{1,2,3},{1,2,3},{1,2,3}}; 
    // ptr2是一個(gè)指向 int * 的指針,即ptr2的類型和&ptr是一樣的,注意:ptr指向的內(nèi)存區(qū)域不定長(zhǎng) 
    int * ptr2[3]={arr1,arr2,arr3}; 
    // ptr3是一個(gè)指向 int [3] 的指針,即ptr3的類型和&arr1的類型是一樣的,注意:arr1指向的內(nèi)存區(qū)域定長(zhǎng) 
    int(* ptr3)[3]=&arr1; 
    ptr3=ptr1; // 沒錯(cuò),他們的類型相同 
    // ptr3=ptr2;//error 無法從“int *[3]”轉(zhuǎn)換為“int (*)[3] 
    // ptr4是一個(gè)指向 int * 的指針,即ptr4的類型和&ptr是一樣的,注意:ptr指向的內(nèi)存區(qū)域不定長(zhǎng) 
    int ** ptr4; 
    //ptr4=&arr1; //error 無法從“int (*)[3]”轉(zhuǎn)換為“int ** 
    ptr4=ptr2; // 沒錯(cuò),他們的類型相同 
    //ptr4=ptr3; // error 無法從“int (*)[3]”轉(zhuǎn)換為“int ** 
    return 0; 
}
posted @ 2011-11-26 23:41 郭龍 閱讀(427) | 評(píng)論 (0)編輯 收藏

2011年11月21日 #

     摘要:     入職一年了,這一年自己學(xué)到許多,但是忘記也很多,于是決定定下心來整理以前學(xué)到的,并且繼續(xù)學(xué)習(xí)        二維數(shù)組和二級(jí)指針,這真是頭疼的問題,困擾了我好幾次,       先轉(zhuǎn)一下wanpengcoder的二維數(shù)組和二級(jí)指針 ...  閱讀全文
posted @ 2011-11-21 23:55 郭龍 閱讀(5621) | 評(píng)論 (0)編輯 收藏

2010年10月31日 #

      由于自己以前是學(xué)數(shù)學(xué)的,許多計(jì)算機(jī)知識(shí)都不懂,所以學(xué)許多東西
時(shí)候感覺的很累.......于是記錄一下最近學(xué)習(xí)經(jīng)歷,一致勉勵(lì)自己,繼續(xù)努力,繼續(xù)奮斗!   

     C++程序設(shè)計(jì)看到了異常,感覺真是受益匪淺,許多東西講的很深,于是反復(fù)看,
并結(jié)合effect c++(看了兩遍,還是有許多東西不懂)
 
     Linux_c編程一戰(zhàn)式學(xué)習(xí)據(jù)說是將Linux最好的書之一,看了文件,進(jìn)程,線程,信號(hào)
     感覺講的卻是很好,許多知識(shí)反復(fù)看了兩遍,才看懂....

     看到了一段時(shí)候又買了UNIX環(huán)境高級(jí)編程,看了幾十頁,正在繼續(xù)......

      在這其中又把林銳的c/c++ 高質(zhì)量編程看了兩遍,覺得指針,內(nèi)存那塊
 講的太好了,\(^o^)/~
   
      沒事隨手看看C語言程序設(shè)計(jì)現(xiàn)代方法,和編程之美,很不錯(cuò)了C
  語言書,和算法書。
 
  
posted @ 2010-10-31 22:48 郭龍 閱讀(478) | 評(píng)論 (0)編輯 收藏

僅列出標(biāo)題  下一頁
青青草原综合久久大伊人导航_色综合久久天天综合_日日噜噜夜夜狠狠久久丁香五月_热久久这里只有精品
  • <ins id="pjuwb"></ins>
    <blockquote id="pjuwb"><pre id="pjuwb"></pre></blockquote>
    <noscript id="pjuwb"></noscript>
          <sup id="pjuwb"><pre id="pjuwb"></pre></sup>
            <dd id="pjuwb"></dd>
            <abbr id="pjuwb"></abbr>
            久久九九电影| 在线日韩av永久免费观看| 亚洲人成在线播放| 亚洲国产91色在线| 欧美国产在线视频| 亚洲一区在线播放| 亚洲欧美日韩国产精品| 精品白丝av| 亚洲国产欧美日韩另类综合| 欧美日韩午夜剧场| 久久精品国产精品亚洲综合| 久久久精品国产一区二区三区 | 狠狠色狠狠色综合日日tαg| 欧美成人亚洲成人| 欧美欧美在线| 久久亚洲综合| 欧美日韩国产麻豆| 久久视频精品在线| 欧美精品一区二| 久久精品国产999大香线蕉| 美女网站久久| 欧美一区日韩一区| 欧美国产日产韩国视频| 午夜亚洲性色视频| 牛夜精品久久久久久久99黑人| 亚洲欧美久久久| 久热国产精品| 久久国产99| 欧美日韩国产综合视频在线观看| 久久久久久久综合日本| 欧美视频在线观看| 欧美高清自拍一区| 国产原创一区二区| 亚洲视频一区在线观看| 亚洲精品免费网站| 久久精品女人的天堂av| 亚洲欧美精品一区| 欧美日韩国产精品一区| 欧美成年视频| 国产一区二区看久久| 99国产精品私拍| 日韩网站在线| 免费久久精品视频| 噜噜噜91成人网| 国产人妖伪娘一区91| 中文高清一区| 亚洲视频www| 欧美精品 国产精品| 欧美激情第1页| 亚洲国产成人av好男人在线观看| 欧美在线首页| 久久精品免费观看| 国产亚洲成av人片在线观看桃| 99这里只有久久精品视频| 亚洲精品视频在线观看网站| 夜夜精品视频| av成人免费| 一区二区精品| 欧美日韩亚洲视频一区| 亚洲美女免费视频| 99精品国产热久久91蜜凸| 欧美激情视频免费观看| 亚洲高清成人| 99热免费精品| 欧美日韩国产成人精品| 一区二区三区精品视频| 亚洲一区在线看| 国产精品毛片高清在线完整版| 亚洲深夜影院| 久久成人精品无人区| 国产丝袜一区二区| 久久精品国产一区二区电影| 久久久精品性| 亚洲国产91精品在线观看| 美日韩精品免费| 亚洲精品国精品久久99热一| 99视频在线精品国自产拍免费观看| 欧美日韩大片| 亚洲综合精品四区| 久热精品在线| 9色精品在线| 国产精品免费看| 久久九九热re6这里有精品| 欧美国产精品v| 一本色道综合亚洲| 国产精品制服诱惑| 老牛影视一区二区三区| 亚洲免费高清视频| 久久久久88色偷偷免费| 亚洲人体影院| 国产精品日韩专区| 久久五月激情| 一区二区三区免费观看| 久久人人爽爽爽人久久久| 亚洲乱码国产乱码精品精 | 欧美影院精品一区| 亚洲国产专区| 久久精品一区二区国产| 亚洲毛片一区| 国产性色一区二区| 欧美日韩午夜视频在线观看| 久久国产精品久久久久久电车| 亚洲精品女人| 久久爱www久久做| 一本一道久久综合狠狠老精东影业| 国产区在线观看成人精品| 欧美精品色综合| 久久精品在这里| 亚洲亚洲精品三区日韩精品在线视频 | 欧美日韩一区二区三区在线视频| 欧美在线视频免费| 一区二区免费在线观看| 欧美电影免费观看| 久久九九久久九九| 亚洲一区二区在线视频| 亚洲激情啪啪| 伊人激情综合| 国产一区二区三区丝袜| 国产精品福利在线| 欧美精品久久久久久久久老牛影院 | 在线综合+亚洲+欧美中文字幕| 欧美在线影院| 国产精品青草综合久久久久99| 欧美激情在线| 媚黑女一区二区| 久久久无码精品亚洲日韩按摩| 亚洲欧美国产视频| 亚洲一区观看| 亚洲网站视频| 亚洲深夜福利在线| 亚洲视频电影在线| 一区二区三区四区国产| 日韩一级裸体免费视频| 亚洲精品亚洲人成人网| 亚洲欧洲美洲综合色网| 最新国产乱人伦偷精品免费网站 | 久久精品国内一区二区三区| 欧美亚洲视频在线观看| 亚洲免费影视| 欧美一区二区大片| 午夜精彩视频在线观看不卡 | 久久久精品999| 久久天堂国产精品| 麻豆精品在线播放| 蜜桃久久精品乱码一区二区| 欧美a级片一区| 亚洲国产精品福利| 亚洲精品在线视频| 夜夜爽99久久国产综合精品女不卡| 亚洲毛片在线看| 亚洲午夜高清视频| 欧美在线观看日本一区| 久久久www免费人成黑人精品| 久久久久久亚洲精品杨幂换脸| 久久伊人免费视频| 欧美精品久久久久久久久老牛影院 | 欧美激情免费观看| 欧美日韩中文字幕综合视频| 国产精品每日更新| 国产在线观看91精品一区| 亚洲国产精品福利| 一本色道久久88综合亚洲精品ⅰ | 一区二区三区四区国产精品| 午夜精品视频在线| 久久人人爽人人爽爽久久| 欧美黑人一区二区三区| 国产精品成人在线| 精品成人一区二区三区| 99re6这里只有精品视频在线观看| 亚洲一区一卡| 免费成人在线视频网站| 日韩视频一区二区在线观看 | 香蕉久久精品日日躁夜夜躁| 久热精品视频在线免费观看 | 欧美成人黄色小视频| 日韩亚洲欧美一区二区三区| 欧美伊人久久久久久久久影院 | 欧美黄免费看| 国产一区二区三区黄视频| 亚洲日韩欧美视频| 久久躁日日躁aaaaxxxx| 欧美激情精品久久久久久黑人| 欧美日韩国产综合网| 激情久久综合| 亚洲欧美精品中文字幕在线| 亚洲电影网站| 欧美中文字幕视频| 欧美涩涩网站| 亚洲精品国久久99热| 久久精品日产第一区二区三区| 亚洲日本一区二区| 久久久亚洲综合| 国产欧美一区二区三区久久 | 国产精品免费福利| 一区二区三区日韩| 欧美成人免费va影院高清| 午夜精品福利一区二区三区av | 欧美日韩亚洲综合| 亚洲精品一区在线观看香蕉| 久久久亚洲一区|