正文: 在編程中,無論是OC還是C亦或是C++語言,所聲明的整數變數都會在記憶體中占有固定的存儲空間,而這些存儲空間都是固定的。 比如我們知道的int、long、short、unsigend int、unsigend long、unsigend long long等等,都有固定的存儲空間,而哪怕是64 ...
正文:
在編程中,無論是OC還是C亦或是C++語言,所聲明的整數變數都會在記憶體中占有固定的存儲空間,而這些存儲空間都是固定的。
比如我們知道的int、long、short、unsigend int、unsigend long、unsigend long long等等,都有固定的存儲空間,而哪怕是64位系統下的變數unsigend long long,能存儲的最大範圍只有1844674407370955161。
下邊複習一下基礎類型的存儲範圍以及所占位元組:
編程語言的基礎類型速查表
char -128 ~ +127 (1 Byte)
short -32767 ~ + 32768 (2 Bytes)
unsigned short 0 ~ 65536 (2 Bytes)
int -2147483648 ~ +2147483647 (4 Bytes)
unsigned int 0 ~ 4294967295 (4 Bytes)
long == int
long long -9223372036854775808 ~ +9223372036854775807 (8 Bytes)
double 1.7 * 10^308 (8 Bytes)
unsigned int 0~4294967295
long long的最大值:9223372036854775807
long long的最小值:-9223372036854775808
unsigned long long的最大值:1844674407370955161
__int64的最大值:9223372036854775807
__int64的最小值:-9223372036854775808
unsigned __int64的最大值:18446744073709551615
詳細:
====================
符號屬性 長度屬性 基本型 所占位數 取值範圍 輸入符舉例 輸出符舉例
-- -- char 8 -2^7 ~ 2^7-1 %c %c 、 %d 、 %u
signed -- char 8 -2^7 ~ 2^7-1 %c %c 、 %d 、 %u
unsigned -- char 8 0 ~ 2^8-1 %c %c 、 %d 、 %u
[signed] short [int] 16 -2^15 ~ 2^15-1 %hd
unsigned short [int] 16 0 ~ 2^16-1 %hu 、 %ho 、 %hx
[signed] -- int 32 -2^31 ~ 2^31-1 %d
unsigned -- [int] 32 0 ~ 2^32-1 %u 、 %o 、 %x
[signed] long [int] 32 -2^31 ~ 2^31-1 %ld
unsigned long [int] 32 0 ~ 2^32-1 %lu 、 %lo 、 %lx
[signed] long long [int] 64 -2^63 ~ 2^63-1 %I64d
unsigned long long [int] 64 0 ~ 2^64-1 %I64u 、 %I64o 、 %I64x
-- -- float 32 +/- 3.40282e+038 %f 、 %e 、 %g
-- -- double 64 +/- 1.79769e+308 %lf 、 %le 、 %lg %f 、 %e 、 %g
-- long double 96 +/- 1.79769e+308 %Lf 、 %Le 、 %Lg
幾點說明:
1. 註意 ! 表中的每一行,代表一種基本類型。 “[]” 代表可省略。
例如: char 、 signed char 、 unsigned char 是三種互不相同的類型;
int 、 short 、 long 也是三種互不相同的類型。
2. char/signed char/unsigned char 型數據長度為 1 位元組;
char 為有符號型,但與 signed char 是不同的類型。
註意 ! 並不是所有編譯器都這樣處理, char 型數據長度不一定為 1 位元組, char 也不一定為有符號型。
3. 將 char/signed char 轉換為 int 時,會對最高符號位 1 進行擴展,從而造成運算問題。
所以 , 如果要處理的數據中存在位元組值大於 127 的情況,使用 unsigned char 較為妥當。
程式中若涉及位運算,也應該使用 unsigned 型變數。
4. char/signed char/unsigned char 輸出時,使用格式符 %c (按字元方式); 或使用 %d 、 %u 、 %x/%X 、 %o ,按整數方式輸出; 輸入時,應使用 %c ,若使用整數方式, Dev-C++ 會給出警告,不建議這樣使用。
5. int 的長度,是 16 位還是 32 位,與編譯器字長有關。
16 位編譯器(如 TC 使用的編譯器)下, int 為 16 位; 32 位編譯器(如 VC 使用的編譯器 cl.exe )下, int 為 32位。
6. 整型數據可以使用 %d (有符號 10 進位)、 %o (無符號 8 進位)或 %x/%X (無符號 16 進位)方式輸入輸出。 而格式符 %u ,表示 unsigned ,即無符號 10 進位方式。
7. 整型首碼 h 表示 short , l 表示 long 。
輸入輸出 short/unsigned short 時,不建議直接使用 int 的格式符 %d/%u 等,要加首碼 h 。這個習慣性錯誤,來源於 TC 。 TC 下, int 的長度和預設符號屬性,都與 short 一致,於是就把這兩種類型當成是相同的,都用 int 方式進行輸入輸出。
8. 關於 long long 類型的輸入輸出:
"%lld" 和 "%llu" 是 linux 下 gcc/g++ 用於 long long int 類型 (64 bits) 輸入輸出的格式符。
而 "%I64d" 和 "%I64u" 則是 Microsoft VC++ 庫里用於輸入輸出 __int64 類型的格式說明。
Dev-C++ 使用的編譯器是 Mingw32 , Mingw32 是 x86-win32 gcc 子項目之一,編譯器核心還是 linux 下的 gcc 。
進行函數參數類型檢查的是在編譯階段, gcc 編譯器對格式字元串進行檢查,顯然它不認得 "%I64d" ,
所以將給出警告 “unknown conversion type character `I' in format” 。對於 "%lld" 和 "%llu" , gcc 理所當然地接受了。
Mingw32 在編譯期間使用 gcc 的規則檢查語法,在連接和運行時使用的卻是 Microsoft 庫。
這個庫里的 printf 和 scanf 函數當然不認識 linux gcc 下 "%lld" 和 "%llu" ,但對 "%I64d" 和 "%I64u" ,它則是 樂意接受,並能正常工作的。
9. 浮點型數據輸入時可使用 %f 、 %e/%E 或 %g/%G , scanf 會根據輸入數據形式,自動處理。
輸出時可使用 %f (普通方式)、 %e/%E (指數方式)或 %g/%G (自動選擇)。
10. 浮點參數壓棧的規則: float(4 位元組 ) 類型擴展成 double(8 位元組 ) 入棧。
所以在輸入時,需要區分 float(%f) 與 double(%lf) ,而在輸出時,用 %f 即可。
printf 函數將按照 double 型的規則對壓入堆棧的 float( 已擴展成 double) 和 double 型數據進行輸出。
如果在輸出時指定 %lf 格式符, gcc/mingw32 編譯器將給出一個警告。
11. Dev-C++(gcc/mingw32) 可以選擇 float 的長度,是否與 double 一致。
12. 首碼 L 表示 long ( double )。
雖然 long double 比 double 長 4 個位元組,但是表示的數值範圍卻是一樣的。
long double 類型的長度、精度及表示範圍與所使用的編譯器、操作系統等有關。
我們看到上面所有基礎數據類型都是有限的,如果要計算天文數字級的、哪怕是最簡單的相加演算法,也會造成數據溢出。
比如:
寫了個將年齡轉為秒的程式,前126年都可以,但是從127開始就overflow了……
在電腦中,當要表示的數據超出電腦所使用的數據的表示範圍時,則產生數據的溢出。具體的自己網上可以查看下資料,很好查
溢出原因
數據類型超過了電腦字長的界限就會出現數據溢出的情況。導致記憶體溢出問題的原因有很多,比如:
(1) 使用非類型安全(non-type-safe)的語言如 C/C++ 等。
(2) 以不可靠的方式存取或者複製記憶體緩衝區。
(3)編譯器設置的記憶體緩衝區太靠近關鍵數據結構。
因素分析
1.記憶體溢出問題是 C 語言或者 C++ 語言所固有的缺陷,它們既不檢查數組邊界,又不檢查類型可靠性(type-safety)。眾所周知,用 C/C++ 語言開發的程式由於目標代碼非常接近機器內核,因而能夠直接訪問記憶體和寄存器,這種特性大大提升了 C/C++ 語言代碼的性能。只要合理編碼,C/C++應用程式在執行效率上必然優於其它高級語言。然而,C/C++ 語言導致記憶體溢出問題的可能性也要大許多。其他語言也存在記憶體溢出問題,但它往往不是程式員的失誤,而是應用程式的運行時環境出錯所致。
2. 當應用程式讀取用戶(也可能是惡意攻擊者)數據,試圖複製到應用程式開闢的記憶體緩衝區中,卻無法保證緩衝區的空間足夠時(換言之,假設代碼申請了 N 位元組大小的記憶體緩衝區,隨後又向其中複製超過 N 位元組的數據)。記憶體緩衝區就可能會溢出。想一想,如果你向 12 盎司的玻璃杯中倒入 16 盎司水,那麼多出來的 4 盎司水怎麼辦?當然會滿到玻璃杯外面了!
3. 最重要的是,C/C++編譯器開闢的記憶體緩衝區常常鄰近重要的數據結構。假設某個函數的堆棧緊接在在記憶體緩衝區後面時,其中保存的函數返回地址就會與記憶體緩衝區相鄰。此時,惡意攻擊者就可以向記憶體緩衝區複製大量數據,從而使得記憶體緩衝區溢出並覆蓋原先保存於堆棧中的函數返回地址。這樣,函數的返回地址就被攻擊者換成了他指定的數值;一旦函數調用完畢,就會繼續執行“函數返回地址”處的代碼。非但如此,C++ 的某些其它數據結構,比如 v-table 、例外事件處理程式、函數指針等,也可能受到類似的攻擊。
然而,針對這種情況,該怎麼防止數據溢出?
一、創建結構體,將溢出的數據轉移到另一個變數中存儲;
二、創建或設計一個存儲器,將所有巨大的數值存儲在這個存儲器中,演算法類似於時鐘演算法,滿多少進一位。再設計一個取出器,將轉換後的變數轉換成巨大的數值,邊轉換邊計算;
三、創建數組來按位數來存儲數據;
顯然第三種方法簡單便捷,比如我們要存儲一個123(一百二十三)的數據類型,則創建一個數組int【3】,數組中每個元素對應一位數,怎麼設計可以自己去設定,在這裡我們使用OC的NSMutableArray數組來計算,在此講一下C數組和OC數組的區別:
OC 數組是一個對象,有大量的方法,c 沒有都需要自己寫
C 數組刪除是需要後面往前移動,oc 數組自動處理
OC中的數組算是一個封裝好的對象,一般的操作基本就能滿足了,但是C裡面的就僅僅是個連續的記憶體空間而已。一個是對象一個空間,另外一個C裡面的數組是要在定義的時候就要初始化個數,但是OC裡面的個數比較動態。
這也就是為什麼涉及到演算法或者比較底層的數據處理一般使用C語言,第一:執行效率高;其次:演算法接近初級易於理解和維護,並且大量方法和函數運算規律可以完全自定義。
所以OC涉及到演算法極少,一般邏輯居多。OC來做簡單的運算也不是不可以,優點在於對於數組的處理比較簡便,以下簡述一下運算邏輯:
一:多位數相乘,第一個數的個位依次向第二位數的每位依次相乘,個位數與個位數相乘使用int來運算,如果結果是個位數,那麼把他放進一個array數組中;
二:如果結果是二位數,則存儲個位數,十位數添加到進位變數中,等待下一次相乘時與下一次的結果相加,然後繼續進行一步驟;
三:將最後array數組中的元素首尾調換,因為數組元素存儲方式是從個位到最高位,與需求數據相反;
四:將這個數組對象存儲到另一個數組中,形成OC二維數組;
五:經過以上運算,會獲得一個梯形數據:
1234
1234
1234
1234
需要對二維數組中的前位數組進行補0,為下一步方便運算做準備;
六:補0後數據為:
0001234
0012340
0123400
1234000
之後從上向下依次相加,同樣的:
1.第一個數的個位依次向第二位數的每位依次相加,個位數與個位數相乘使用int來運算,如果結果是個位數,那麼把他放進一個array數組中;
2.如果結果是二位數,則存儲個位數,十位數添加到進位變數中,等待下一次相乘時與下一次的結果相加,並且執行1步驟;
七:最後會獲得一個最終結果的數組,同樣的,裡面數據結構依然與需求數據相反,需要首尾調換;
八:返回這個數組,這個數組的每一個元素(從第一位起到第N位)都是這個最終結果(超大數)從個位到最高位的相應數值:
比如這個超大數是:1231443256827659485683297465789236578263857658265892561856138456938
那麼這個數組的元素依次是:1、2、3、1、4、4、3、2、5、6、8、.......5、6、9、3、8
OC雖然可以進行處理演算法和數據類型,但是相對於C來說,它所占的記憶體還是比較高的,因為這個數組所開闢的記憶體空間遠遠大於相應C數組的空間,它可以存儲多個對象,自帶各種數據處理方法,靈活多變對於C數組來說操作性很強,畢竟NSArray用於開發。
以下我把OC超大數演算法的代碼貼出來,僅供參考。。如有不對望指正:
#import "Multiplication.h"
@implementation Multiplication
-(NSString *)MulOfOneString:(NSString *)strOne AndString:(NSString *)strTwo{
NSString *a = [NSString stringWithFormat:@"%lu",(unsigned long)strOne.length];
NSString *b = [NSString stringWithFormat:@"%lu",(unsigned long)strTwo.length];
int oneLength = [a intValue];
int twoLength = [b intValue];
NSMutableArray *arrOne = [[NSMutableArray alloc]init];
NSMutableArray *arrTwo = [[NSMutableArray alloc]init];
for (int i = 0;i < oneLength;i++) {
unichar c = [strOne characterAtIndex:i];
NSString *c1 = [NSString stringWithFormat:@"%c",c];
[arrOne addObject:c1];
}
for (int i = 0;i < twoLength;i++) {
unichar c = [strTwo characterAtIndex:i];
NSString *c1 = [NSString stringWithFormat:@"%c",c];
[arrTwo addObject:c1];
}
NSMutableArray *arrShi = [[NSMutableArray alloc]init];
if (oneLength > twoLength) {
for (int i = twoLength - 1 ;i >= 0;i--) {
NSMutableString *strJ = [[NSMutableString alloc]init];
int jin = 0;
int btwo = [arrTwo[i] intValue];
for (int j = oneLength - 1; j >= 0;j--) {
int aone = [arrOne[j] intValue];
int c = aone * btwo + jin;
int z = c%10;
jin = c/10;
if (j != 0) {
[strJ appendFormat:@"%d",z];
}else{
[strJ appendFormat:@"%d",c%10];
if (c/10!=0) {
[strJ appendFormat:@"%d",c/10];
}
}
}
NSMutableString *zheng = [[NSMutableString alloc]init];
for (NSInteger i = strJ.length-1 ;i>=0;i--) {
unichar s = [strJ characterAtIndex:i];
[zheng appendFormat:@"%c",s];
}
[arrShi addObject:zheng];
}
}else if(oneLength < twoLength){
for (int i = oneLength - 1 ;i >= 0;i--) {
NSMutableString *strJ = [[NSMutableString alloc]init];int jin = 0;
int aone = [arrOne[i] intValue];
for (int j = twoLength - 1; j >= 0;j--) {
int btwo = [arrTwo[j] intValue];
int c = aone * btwo + jin;
int z = c%10;
jin = c/10;
if (j != 0) {
[strJ appendFormat:@"%d",z];
}else{
[strJ appendFormat:@"%d",c%10];
if (c/10!=0) {
[strJ appendFormat:@"%d",c/10];
} }
}
NSMutableString *zheng = [[NSMutableString alloc]init];
for (NSInteger i = strJ.length-1 ;i>=0;i--) {
unichar s = [strJ characterAtIndex:i];
[zheng appendFormat:@"%c",s];
}
[arrShi addObject:zheng];
}
}else if (oneLength == twoLength){
for (int i = oneLength - 1 ;i >= 0;i--) {
NSMutableString *strJ = [[NSMutableString alloc]init];int jin = 0;
int aone = [arrOne[i] intValue];
for (int j = twoLength - 1; j >= 0;j--) {
int btwo = [arrTwo[j] intValue];
int c = aone * btwo + jin;
int z = c%10;
jin = c/10;
if (j != 0) {
[strJ appendFormat:@"%d",z];
}else{
[strJ appendFormat:@"%d",c%10];
if (c/10!=0) {
[strJ appendFormat:@"%d",c/10];
}
}
}
NSMutableString *zheng = [[NSMutableString alloc]init];
for (NSInteger i = strJ.length-1 ;i>=0;i--) {
unichar s = [strJ characterAtIndex:i];
[zheng appendFormat:@"%c",s];
}
[arrShi addObject:zheng];
}
}
NSMutableArray *arrBF = [[NSMutableArray alloc]init];
if (arrShi.count == 1) {
NSString *res = arrShi[0];
return res;
}else{
for (int i = 0;i<arrShi.count;i++) {
NSMutableString *str0 = arrShi[i];
for (int j = 1;j<=i;j++) {
[str0 appendFormat:@"0"];
}
arrBF[i] = str0;
}
for (int i =1;i<arrBF.count;i++) {
int J = 0;
NSMutableString *strConst = [[NSMutableString alloc]init];
NSString *strC = arrBF[i-1];
NSString *strB = arrBF[i];
if (strC.length == strB.length) {
for (NSInteger j = strB.length-1 ;j >= 0;j--) {
unichar b = [strB characterAtIndex:j];
unichar c = [strC characterAtIndex:j];
int B = [[NSString stringWithFormat:@"%c",b] intValue];
int C = [[NSString stringWithFormat:@"%c",c] intValue];
int counst = B + C + J;
int z = counst %10;
J = counst /10;
if (j != 0) {
[strConst appendFormat:@"%d",z];
}else{
[strConst appendFormat:@"%d",counst %10];
if (counst /10!=0) {
[strConst appendFormat:@"%d",counst /10];
}
}
}
NSMutableString *Lin = [[NSMutableString alloc]init];
for (NSInteger i = strConst.length-1 ;i>=0;i--) {
unichar s = [strConst characterAtIndex:i];
[Lin appendFormat:@"%c",s];
}
arrBF[i] = Lin;
}else{
NSUInteger a = strC.length;
for (NSInteger j = strB.length-1 ;j >= 0;j--) {
unichar b = [strB characterAtIndex:j];
unichar c = [strC characterAtIndex:a-1];
int B = [[NSString stringWithFormat:@"%c",b] intValue];
int C = [[NSString stringWithFormat:@"%c",c] intValue];
a--;
int counst = B + C + J;
int z = counst %10;
J = counst /10;
if (j != 0) {
[strConst appendFormat:@"%d",z];
}else{
[strConst appendFormat:@"%d",counst %10];
if (counst /10!=0) {
[strConst appendFormat:@"%d",counst /10];
}
}
}
NSMutableString *Lin = [[NSMutableString alloc]init];
for (NSInteger i = strConst.length-1 ;i>=0;i--) {
unichar s = [strConst characterAtIndex:i];
[Lin appendFormat:@"%c",s];
}
arrBF[i] = Lin;
}
}
NSString *res = arrBF[arrBF.count-1];
return res;
}
return @"輸入有誤";
}
@end
超大數相加演算法思路和相乘演算法後半段思路相似,相對簡單很多
以下是超大數相加演算法的代碼:
#import "Addition.h"
@implementation Addition
- (NSString *)additionOfString:(NSString *)strOne AndString:(NSString *)strTwo{
NSMutableString *One = [NSMutableString stringWithFormat:@"%@",strOne ];
NSMutableString *Two = [NSMutableString stringWithFormat:@"%@",strTwo ];
if (One.length > Two.length) {
NSInteger t = One.length - Two.length;
for (NSInteger i = 0;i < t;i++) {
[Two insertString:[NSString stringWithFormat:@"0"] atIndex:0];
}
int jin = 0;
NSMutableString *strJ = [[NSMutableString alloc]init];
for (NSInteger i = One.length -1 ; i >= 0 ;i--) {
unichar onenum = [One characterAtIndex:i];
unichar twonum = [Two characterAtIndex:i];
int onum = [[NSString stringWithFormat:@"%c",onenum] intValue];
int tnum = [[NSString stringWithFormat:@"%c",twonum] intValue];
int c = onum + tnum +jin;
int z = c%10;
jin = c/10;
if (i !=0 ) {
[strJ appendFormat:@"%d",z];
}else{
[strJ appendFormat:@"%d",c%10];
if (c/10 != 0) {
[strJ appendFormat:@"%d",c/10];
}
}
}
NSMutableString *zheng = [[NSMutableString alloc]init];
for (NSInteger i = strJ.length-1; i>=0;i--) {
unichar k = [strJ characterAtIndex:i];
[zheng appendFormat:@"%c",k];
}
return zheng;
}else if(One.length < Two.length){
NSInteger t = Two.length - One.length;
for (NSInteger i = 0;i < t;i++) {
[One insertString:[NSString stringWithFormat:@"0"] atIndex:0];
}
int jin = 0;
NSMutableString *strJ = [[NSMutableString alloc]init];
for (NSInteger i = Two.length - 1; i >= 0 ;i--) {
unichar onenum = [One characterAtIndex:i];
unichar twonum = [Two characterAtIndex:i];
int onum = [[NSString stringWithFormat:@"%c",onenum] intValue];
int tnum = [[NSString stringWithFormat:@"%c",twonum] intValue];
int c = onum + tnum +jin;
int z = c%10;
jin = c/10;
if (i !=0 ) {
[strJ appendFormat:@"%d",z];
}else{
[strJ appendFormat:@"%d",c%10];
if (c/10 != 0) {
[strJ appendFormat:@"%d",c/10];
}
}
}
NSMutableString *zheng = [[NSMutableString alloc]init];
for (NSInteger i = strJ.length-1; i>=0;i--) {
unichar k = [strJ characterAtIndex:i];
[zheng appendFormat:@"%c",k];
}
return zheng;
}else if(One.length == Two.length){
int jin = 0;
NSMutableString *strJ = [[NSMutableString alloc]init];
for (NSInteger i = One.length - 1; i >= 0 ;i--) {
unichar onenum = [One characterAtIndex:i];
unichar twonum = [Two characterAtIndex:i];
int onum = [[NSString stringWithFormat:@"%c",onenum] intValue];
int tnum = [[NSString stringWithFormat:@"%c",twonum] intValue];
int c = onum + tnum +jin;
int z = c%10;
jin = c/10;
if (i !=0 ) {
[strJ appendFormat:@"%d",z];
}else{
[strJ appendFormat:@"%d",c%10];
if (c/10 != 0) {
[strJ appendFormat:@"%d",c/10];
}
}
}
NSMutableString *zheng = [[NSMutableString alloc]init];
for (NSInteger i = strJ.length-1; i>=0;i--) {
unichar k = [strJ characterAtIndex:i];
[zheng appendFormat:@"%c",k];
}
return zheng;