我的編程樂園
積累,堅持!
---------我是一只IT小小鳥
首頁
新隨筆
聯系
聚合
管理
隨筆-145 評論-173 文章-70 trackbacks-0
【歡迎各位留言討論】C++中運算符New的一個疑問【新的問題!】【各位繼續關注討論啊!】
最近突然發現自己曾經建立的C++體系出現了很多漏洞,對很多問題都產生了疑問,不知道自己是鉆了牛角尖還是探究C++的底層或者細節,不過既然碰到了,就解決之吧,或許在某一天之后,會驚奇的發現,原來自己的這些問題會出現某天的筆試或者工作中呢。
言歸正傳,這個問題是關于new操作符的。今天在完成C++作業的時候,需要自己實現一個strlen來,其實就是調用C語言函數就可以,不過我突發奇想,寫下了下面的這個代碼:
code 1:
1
#include
<
iostream
>
2
using
namespace
std;
3
4
int
main()
5
{
6
char
*
str
=
new
char
[
4
];
7
strcpy(str,
"
fjifejfief
"
);
8
cout
<<
str
<<
endl;
9
}
code 2:
1
#include
<
iostream
>
2
using
namespace
std;
3
4
int
main()
5
{
6
char
*
str
=
new
char
[
5
];
7
strcpy(str,
"
Good
"
);
8
strcat(str,
"
I Love C++
"
);
9
cout
<<
str
<<
endl;
10
}
上面的兩個代碼都是用到了new操作符,動態分配了一個固定的存儲空間,OK。
然后通過strcpy來實現賦值,從而將原來的那個分配的區域填充??墒窃?和2中都有一個問題,那就是,填充的字符串超過了動態分配的大小,在code1中,實際分配的只有4個字節,而自己拷貝過去的確有10個字節(不含null),而code2中,首先初始化的時候沒有問題,后面的連接函數也是。為何我會產生這個問題呢?
因為曾經在《C++ Primer》一書中講到,當進行字符串操作的時候,需要特別注意到那個null要占用一個空間,而對于strcat和其他函數,特別要注意是否超過表示的范圍,而我自己曾經碰到過這個問題,所以比較疑惑,上面的那個沒有溢出嗎?為何可以輸出正確的結果呢?
下面,列出個錯誤的例子來看看:
code3
1
#include
<
iostream
>
2
using
namespace
std;
3
4
int
main()
5
{
6
char
str[
4
]
=
"
goo
"
;
7
cout
<<
str
<<
endl;
8
strcat(str,
"
sfsfefe
"
);
9
cout
<<
str
<<
endl;
10
return
0
;
11
}
明顯code3會出錯(剛開始的時候居然沒有出錯,后來程序才崩潰的,以為靈異事件呢。),固定分配的數組的話,需要特別注意像strcat函數,因為這種連接函數就可能超過范圍,發生錯誤。
ok:
匯總如下:固定分配的時候,不能夠超過數組的范圍,而且字符串的話需要注意總是有一個null在其中的,所以大小要自己把握好。
但是,對于new動態分配的話,可以超過范圍,不管是strcat還是直接在分配的時候超過范圍都可以,Why?
============================================================================================================
經過網友留言匯總,同時自己測試,發現了一些新的問題,也有了新的體會! Version 1
============================================================================================================
留言匯總(解答):
經過和網友的討論,我初步了解了錯誤可能的原因,現羅列如下,如有遺漏和錯誤,還望各位指教。
1.兩者的分配方式不同。使用關鍵字new操作符分配的話,分配的空間是在堆當中(heap),而直接使用數組的話,分配的空間在堆棧中(stack)。
2.操作。對于堆棧的溢出,由于變量的填充時按照從高地址到低地址的方式,所以,溢出的話會修改函數的返回值,造成運行的錯誤。而對于堆分配的話,這里即使溢出了,由于沒有對它進行進一步操作,所以沒有出現問題。
3
.我的一點理解。對于堆棧溢出的錯誤,我想大家都知道了,可是上面的這個堆溢出的話,好像即使有錯誤也沒有什么問題。我嘗試了使用
delete []str,或者是輸出str[8]等單元,都是顯示正確的結果,也沒有出現錯誤。所以懷疑的是,難道堆上的這種分配這么安全,那我delete的話,到底是刪除的分配的4個字節,還是拷貝過去的溢出的那個超過4個字節的那么多單元內容呢?我的理解是,堆上分配的單元由于太隨意,靈活性太強,所以對于錯誤的發生就可能性很小。
4.
我寫的調試代碼的一個新的問題:
1
#include
<
iostream
>
2
using
namespace
std;
3
4
int
main()
5
{
6
char
*
str1
=
new
char
[
4
];
7
str1
=
"
sfe
"
;
//如果去掉這一行,那么程序就可以正常運行了……可是這個僅僅是初始化指針的啊。
8
char
str2[
4
]
=
"
adf
"
;
9
cout
<<
"
賦值前:
"
<<
endl;
10
cout
<<
"
str1指向:
"
<<&
str1
<<
endl;
11
cout
<<
"
str1內容:
"
<<
str1
<<
endl;
12
cout
<<
"
str2指向:
"
<<&
str2
<<
endl;
13
cout
<<
"
str2內容:
"
<<
str2
<<
endl;
14
strcpy(str2,
"
ooo
"
);
15
cout
<<
"
str2先賦值后:
"
<<
endl;
16
cout
<<
"
str1指向:
"
<<&
str1
<<
endl;
17
cout
<<
"
str1內容:
"
<<
str1
<<
endl;
18
cout
<<
"
str2指向:
"
<<&
str2
<<
endl;
19
cout
<<
"
str2內容:
"
<<
str2
<<
endl;
20
strcpy(str1,
"
iiiiii
"
);
21
cout
<<
"
str1后賦值后:
"
<<
endl;
22
cout
<<
"
str1指向:
"
<<&
str1
<<
endl;
23
cout
<<
"
str1內容:
"
<<
str1
<<
endl;
24
cout
<<
"
str2指向:
"
<<&
str2
<<
endl;
25
cout
<<
"
str2內容:
"
<<
str2
<<
endl;
26
27
}
28
程序在運行一半后崩潰,典型的溢出了。但是,此代碼如果去掉上面初始化的那一行,程序就沒有錯誤,而且我這里還計算發現對于堆棧的話沒有任何錯誤,而堆的話故意寫了個溢出的賦值,就是下面strcpy(str1,"iiiiii");
此時加上初始化的代碼后,問題就來了,上個截圖。
從錯誤的信息來看,
就是指向到 strcpy(str1,"iiiiii")的時候出錯了的。
這個說明:在我沒有對堆上的變量初始化的時候,如果越界了,沒有發現出錯(它會自動擴展那個大小嗎?)。
而如果我對堆上的變量初始化的話,那么,再次復制的時候,如果越界了,就會發生錯誤!
各位,知道為什么嗎?(
問題好像更明朗了些,而且好像更深入了些。當然,鉆這個牛角尖或許沒有必要!)
posted on 2010-01-13 23:14
deercoder
閱讀(2197)
評論(23)
編輯
收藏
引用
評論:
#
re: 【歡迎各位留言討論】C++中運算符New的一個疑問[未登錄] 2010-01-14 00:54 |
Steven
你需要去了解下 堆(stack) 和 棧(heap) 的區別.
回復
更多評論
#
re: 【歡迎各位留言討論】C++中運算符New的一個疑問 2010-01-14 02:06 |
陳梓瀚(vczh)
因為new的時候,系統可以選擇多給你幾個字節,而且這并不是固定的數字。
回復
更多評論
#
re: 【歡迎各位留言討論】C++中運算符New的一個疑問 2010-01-14 02:20 |
OwnWaterloo
1. 在C/C++代碼正確且C/C++實現(編譯器,運行庫)正確的情況下, C/C++語言保證得到正確的結果。
如果出現了錯誤的結果, 可以問why。
是"C/C++代碼正確"這個假設有誤? 還是"C/C++實現正確"這個假設有誤?
2. 如果C/C++代碼本身有某種錯誤, C/C++實現不保證得到正確的結果, 也不保證得到錯誤的結果, 更不保證會報告錯誤的結果。
代碼的錯誤有可能會被隱藏, 到其他時候發作。
這時候, 詢問"為什么沒有出現錯誤", 是不明智的。
C/C++實現沒有義務保證產生一個錯誤。
回復
更多評論
#
re: 【歡迎各位留言討論】C++中運算符New的一個疑問 2010-01-14 09:22 |
bluegene
我是這樣理解的,你用 new 分配的空間是放在堆(heap)里的,超出了的空間如果不被其它數據覆蓋暫時是沒有問題的。固定分配的時候是在棧(stack)里分配的,其空間肯定是不能益處的。
回復
更多評論
#
re: 【歡迎各位留言討論】C++中運算符New的一個疑問 2010-01-14 10:26 |
飯中淹
new分配的在堆里,你溢出了,只會導致堆出問題。而你下面又沒有再使用堆,所以不會出錯。
直接寫的局部變量,分配在堆棧里,堆棧里有函數的返回地址,所以溢出了,覆蓋了返回地址,函數執行完就出錯了。
另外,有些 編譯器會生成對固定長度數組的保護性檢測代碼,一旦溢出,就會彈出提示。早先在vs2003還是vs2002的時候見過。
回復
更多評論
#
re: 【歡迎各位留言討論】C++中運算符New的一個疑問 2010-01-14 10:27 |
zuhd
對于堆來講,生長方向是向上的,也就是向著內存地址增加的方向;對于棧來講,它的生長方向是向下的,是向著內存地址減小的方向增長??聪路磪R編代碼一切都明白了
回復
更多評論
#
re: 【歡迎各位留言討論】C++中運算符New的一個疑問 2010-01-14 10:31 |
zuhd
棧里有函數的返回地址,所以溢出了,覆蓋了返回地址,函數執行完就出錯了。
==========================================
這句話是重點,當ret的時候,call下條指令時異常了,如果你多定義了幾個變量,讓棧溢出不到函數的返回地址,錯誤依然不會出現的
回復
更多評論
#
re: 【歡迎各位留言討論】C++中運算符New的一個疑問[未登錄] 2010-01-14 12:43 |
vane
出錯是必然的,沒問題的時候你比較幸運。
#include <iostream>
using namespace std;
#pragma pack(push)
#pragma pack(1)
int main()
{
char *str = new char[5];
strcpy(str,"Good");
strcat(str,"I Love C++");
cout << str << endl;
}
#pragma pack(pop)
你可以這么試一下
回復
更多評論
#
re: 【歡迎各位留言討論】C++中運算符New的一個疑問 2010-01-14 15:53 |
壞人
越界,后果自負。
回復
更多評論
#
re: 【歡迎各位留言討論】C++中運算符New的一個疑問 2010-01-14 15:57 |
turygo
數組越界都是這樣的,錯誤不是立刻出現,而是不知道什么時候就出問題了,而且到那個時候代碼量一大,你根本無從找起錯誤。
回復
更多評論
#
re: 【歡迎各位留言討論】C++中運算符New的一個疑問 2010-01-14 17:30 |
零宇
建議樓主補充一下基礎知識
回復
更多評論
#
re: 【歡迎各位留言討論】C++中運算符New的一個疑問 2010-01-14 19:22 |
besterChen
LZ遇到的問題是堆和棧溢出的問題,您說的可能是靈異事件是因為程序對棧和堆檢查導致的。
不知道LZ用的是什么開發環境。我學習C語言也剛好學到這里,自己在VC6得開發環境下仔細調試過其過程并做了筆記,地址:
http://www.shnenglu.com/besterChen/archive/2010/01/13/105538.html
希望能對樓主有幫助,由于自己也是初學,希望LZ能多多指正日志中的錯誤……
回復
更多評論
#
re: 【歡迎各位留言討論】C++中運算符New的一個疑問 2010-01-14 22:30 |
wildpointer
這種越界的事,你知道會錯還用。
回復
更多評論
#
re: 【歡迎各位留言討論】C++中運算符New的一個疑問 2010-01-14 23:21 |
劉暢
@Steven
好的,謝謝。我覺得也應該是這方面的問題。
回復
更多評論
#
re: 【歡迎各位留言討論】C++中運算符New的一個疑問 2010-01-14 23:22 |
劉暢
@陳梓瀚(vczh)
可是多出來的字節是無法預知的啊。而且如果太多的話還是會溢出的吧。
回復
更多評論
#
re: 【歡迎各位留言討論】C++中運算符New的一個疑問 2010-01-14 23:25 |
劉暢
@bluegene
謝謝,之前一直覺得和內存的分配有關,堆棧和堆確實不大一樣。
回復
更多評論
#
re: 【歡迎各位留言討論】C++中運算符New的一個疑問 2010-01-14 23:27 |
劉暢
@飯中淹
@zuhd
謝謝你們的精彩解釋,受益匪淺。
回復
更多評論
#
re: 【歡迎各位留言討論】C++中運算符New的一個疑問 2010-01-14 23:29 |
劉暢
@besterChen
呵呵,一起學習!
回復
更多評論
#
re: 【歡迎各位留言討論】C++中運算符New的一個疑問 2010-01-14 23:29 |
劉暢
@零宇
好的,謝謝!
回復
更多評論
#
re: 【歡迎各位留言討論】C++中運算符New的一個疑問 2010-01-15 00:05 |
Benjamin
strcpy等在一些公司的編碼規范中是禁用的。
回復
更多評論
#
re: 【歡迎各位留言討論】C++中運算符New的一個疑問 2010-01-15 00:55 |
空明流轉
bushuoshale...
回復
更多評論
#
re: 【歡迎各位留言討論】C++中運算符New的一個疑問[未登錄] 2010-01-15 09:47 |
Steven
@劉暢
呵呵,我把堆和棧的英文寫反了。。。
以前寫C 程序的時候經常用到大量的 strcopy, strcat之類的函數,偶爾出錯是在所難免的,只要是人總是有算錯的時候,尤其有些時候混合處理unicode和ansi串的時候,算字符串長度是容易出錯的。
所以后來寫 C++ 的時候我盡量避免去使用這類函數了,而是傾向于用 stl的string wstring, 盡量用 stl的容器類去代替自己分配管理內存。
代碼規模大到一定程度,除了緩沖溢出實在是很難找。
順便說下,
http://www.coverity.com/products/static-analysis.html
這個東西很強大,可以檢測到你代碼里潛在的溢出問題。
回復
更多評論
#
re: 【歡迎各位留言討論】C++中運算符New的一個疑問
2010-01-15 12:43 |
劉暢
@Steven
謝謝,去看看,學習了……
回復
更多評論
刷新評論列表
只有注冊用戶
登錄
后才能發表評論。
【推薦】100%開源!大型工業跨平臺軟件C++源碼提供,建模,組態!
網站導航:
博客園
IT新聞
BlogJava
博問
Chat2DB
管理
堅持記錄,筆耕不輟,筆記是最好的學習方法!
<
2012年6月
>
日
一
二
三
四
五
六
27
28
29
30
31
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
29
30
1
2
3
4
5
6
7
常用鏈接
我的隨筆
我的評論
我參與的隨筆
留言簿
(12)
給我留言
查看公開留言
查看私人留言
隨筆分類
(87)
ACM(1)
Android(4)
C++(7)
CTeX和LateX(1)
Git(3)
Java(4)
MFC程序設計入門(8)
OpenCV(1)
Python(3)
Shell/Bash(1)
SQL(1)
Unix/Linux(23)
Vim(3)
大學公開課(3)
讀書(4)
環境配置(1)
生活感悟/日記(18)
圖像識別算法及原理(1)
隨筆檔案
(145)
2014年12月 (1)
2013年3月 (1)
2012年7月 (2)
2012年6月 (5)
2012年5月 (2)
2012年4月 (2)
2011年12月 (1)
2011年11月 (2)
2011年10月 (8)
2011年9月 (2)
2011年8月 (4)
2011年6月 (2)
2011年5月 (5)
2011年4月 (3)
2011年3月 (3)
2010年6月 (5)
2010年5月 (5)
2010年4月 (3)
2010年3月 (16)
2010年2月 (56)
2010年1月 (11)
2009年12月 (2)
2009年11月 (3)
2009年10月 (1)
文章分類
(70)
C/C++(14)
JAVA(6)
Linux/Unix(6)
MFC(5)
OpenCV / OpenGL(6)
編程體會和收獲(3)
常見編譯器錯誤解決辦法(5)
深入理解計算機系統(2)
生活的體會和感悟(5)
實習/讀研(1)
數據結構和算法分析(9)
雜談(8)
文章檔案
(70)
2011年11月 (1)
2011年10月 (1)
2010年3月 (8)
2010年2月 (2)
2010年1月 (3)
2009年12月 (21)
2009年11月 (26)
2009年10月 (5)
2009年9月 (3)
相冊
computer picture
ACM與算法比賽
Google Code Jam
Top Coder
北大ACM
杭電ACM
LaTex和Tex學習
LaTex and Tex
Tex,LaTex,CTex學習
電子書下載
不錯的電子書免注冊下載
雜志下載(經濟學人等)
聯系方式
我的豆瓣主頁
學習論壇
C++編程
VC知識庫
超多C/C++資料和源碼下載
科研小木蟲
提問必答網站(牛人輩出啊?。?/a>
英語網站(長期學習)
New York Times
華爾街日報
記單詞,捐大米
經濟學英文網
普特網站
普特英語應用(有趣的學習)
譯言網|譯文庫
中國日報
源碼網站
codeproject
google代碼搜索
programersheaven
sourceforge
程序員聯合開發網
最新隨筆
1.?此博客停止更新
2.?Adboe Reader提示中文字體有問題
3.?Python字符串換行處理
4.?如何轉換^M行末符號
5.?斯坦福大學開放課程--編程范式(四)
搜索
積分與排名
積分 - 903415
排名 - 15
最新隨筆
1.?此博客停止更新
2.?Adboe Reader提示中文字體有問題
3.?Python字符串換行處理
4.?如何轉換^M行末符號
5.?斯坦福大學開放課程--編程范式(四)
最新評論
1.?re: Git Stash用法[未登錄]
@陳梓瀚(vczh)
人稱輪帶逛?。。?
--q
2.?re: Git Stash用法
@Loaden
這個B裝的好
--doubi
3.?re: Chrome神器Vimium快捷鍵學習記錄
哦啦啦啦啦
--阿里河
4.?re: Chrome神器Vimium快捷鍵學習記錄
希望能添加更新后的功能翻譯
--Vi.Ci
5.?re: Chrome神器Vimium快捷鍵學習記錄
@coolbit
謝謝,學會了
--xin
閱讀排行榜
1.?Git Stash用法(300675)
2.?Chrome神器Vimium快捷鍵學習記錄(67508)
3.?GitHub使用簡介(35350)
4.?Ubuntu下硬盤的自動掛載(23763)
5.?Ubuntu更新包管理器失?。篟equires installation of untrusted packages問題解決(18491)
評論排行榜
1.?【歡迎各位留言討論】C++中運算符New的一個疑問【新的問題!】【各位繼續關注討論啊!】(23)
2.?Git Stash用法(21)
3.?Chrome神器Vimium快捷鍵學習記錄(19)
4.?C++友元的一個問題-----------由派生類訪問基類的私有成員(10)
5.?OpenCV學習筆記(一)(7)
Powered by:
博客園
模板提供:
滬江博客
Copyright ©2025 deercoder
乱亲女H秽乱长久久久
|
思思久久99热免费精品6
|
要久久爱在线免费观看
|
精品久久久久中文字
|
青青青国产成人久久111网站
|
999久久久无码国产精品
|
久久精品国产99久久香蕉
|
97久久国产亚洲精品超碰热
|
久久水蜜桃亚洲av无码精品麻豆
|
久久久久久国产a免费观看黄色大片
|
欧美久久久久久午夜精品
|
狠狠人妻久久久久久综合
|
久久精品18
|
久久久久久精品免费看SSS
|
无码人妻久久一区二区三区免费
|
久久国产色AV免费观看
|
亚洲国产成人久久综合碰碰动漫3d
|
久久精品国产亚洲综合色
|
热久久这里只有精品
|
久久国产香蕉一区精品
|
亚洲国产成人精品无码久久久久久综合
|
欧美激情精品久久久久久久九九九
|
香港aa三级久久三级老师2021国产三级精品三级在
|
久久综合伊人77777
|
久久亚洲日韩看片无码
|
欧美一区二区三区久久综
|
久久久青草青青亚洲国产免观
|
久久国产三级无码一区二区
|
国产精品久久久久久五月尺
|
精品久久久久中文字幕日本
|
久久久久国产日韩精品网站
|
久久人人爽人人爽人人片av麻烦
|
日本五月天婷久久网站
|
国产精品久久久亚洲
|
婷婷久久综合九色综合绿巨人
|
伊人久久大香线蕉av一区
|
亚洲国产精品久久久久婷婷软件
|
国产一区二区精品久久凹凸
|
亚洲中文精品久久久久久不卡
|
青青热久久综合网伊人
|
久久久免费精品re6
|