正文:
在编程中,无论是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;
}
return @"您的输入有误!";
}
@end