旧代码升级计划之第一篇




题目来源:

东华大学(C++)OJ题目收集(代码详解版)

鼠标悬停于此可预览题目

旧代码:

#include <iostream>
#include <cstdlib>
#include <cstring>
 
using namespace std;
 
int myatoi(char *);
 
int main() {
	char str[100];
	while (cin >> str) {
		cout << myatoi(str) << endl;
	}
	return 0;
 
}
int myatoi(char *str) {
	if ('-' == str[0]) {
		cout << "-";
	}
	for (unsigned int i = 0; i < strlen(str); ++i) {
		str[i] = str[i + 1];
	}
	return atoi(str);
}

bug描述:

1、不符合题目要求:如果字符串真的很长了(long long int至多支持64位长度),
则无法如此转换——因为已经属于超精度范畴知识了。如此设计,至多表示int的范围,即:-2147483648至2147483647 (区间长度即:2^32) 

2、函数设计不够上心,直接用了库函数、没有达到锻炼自身的效果。故,特此加以完善代码设计。

3、如此代码,C不像C,C++又不是,只能推倒重来。

新代码:

#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
#define N 100
using namespace std;

size_t myatoi(char *);
char* mySubstr(char* , size_t, size_t);
size_t myStrlen(char* );

int
main() {
	char* str;
	str = (char*)malloc((N + 1) * sizeof(char));
	assert(str);// 即 str!=NULL(空指针)
	while ( 1 == scanf_s("%s",str,N)) {
		// 处理并输出首字符;
		if ('+' != str[0]) {
			printf("%c", str[0]);
		}

		// 下一行:之所以 -1 是为了与之前提前输出首字符之后相对应;
		// 思路是:除了首字符外,剩余按照每8个字符进行分块处理、分割输出;
		size_t len = myStrlen(str) - 1;
		size_t slice = 8;
		size_t times = len / slice;
		size_t  remainder = len % slice;
		char* s; // 切割后的小字符串;
		s = (char*)malloc((slice + 1) * sizeof(char));
		assert(s);

		for (size_t i = 0; i < times; ++i) {
			s = mySubstr(str, 1 + i * slice, slice);
			//printf(" 1 + i * slice = %u", 1 + i * slice);
			//printf("substr = %s\n", s);
			printf("%u", myatoi(s));
		}
		if (remainder) {
			s = "\0"; // 重置为空(程序健壮性);
			s = mySubstr(str, 1 + times * slice, remainder); // 最后剩余的一小部分;
			//printf("substr = %s\n", s);
			printf("%u", myatoi(s));
		}
		free(s);
		puts("\n");
	}
	free(str);

	return 0;

}
// C语言有库函数 atoi 字符转整型函数,头文件 <stdlib.h>;
size_t myatoi(char *str) {
	//return atoi(str);//直接引用
	size_t num = 0;
	for (size_t i = 0; str[i] != '\0'; ++i) {
		num = num * 10 + (str[i] - '0');
	}
	return num;
}
// C++有库函数substr,用于处理string类的实例(对象);
char* mySubstr(char* str, size_t offset, size_t len) {
	char* arr;
	arr = (char*)malloc((len + 1) * sizeof(char));
	assert(arr);
	for (size_t i = 0; i < len; ++i) {
		arr[i] = str[offset + i];
	}
	arr[len] = '\0';
	return arr;
}
// char 型指针(或数组)可以直接使用strlen(s)求得长度(长度是指元素个数);
// string则是对象调用类的方法(或称之函数)返回长度,size()、length() 二选一;
size_t myStrlen(char* str) {
	size_t len = 0;
	while (str[len] != '\0') {
		++len;
	}
	return len;
}

代码讲解:

1、用的C语言描述,C代码的设计和码字的过程,就是一个人思维方式和能力展示的过程。

2、全部用的自定义函数实现程序功能,不借助任何库函数。

3、设计的知识有:
(1)动态内存分配:
内存空间:有申请就得有释放,这是设计原则;
C语言版本不同于C++:C++用的new和delete(当然malloc和free也是可行),但C只能用malloc和free。

(2)字符数组和字符指针比较:
指针往往与动态内存分配结合起来使用,在声明指针的时候是不分配地址空间的,是一个虚的、不存在地址的野指针,往往需要先申请、分配了内存地址,才能够用于赋值等操作(这往往疏忽大意时的致命陷阱);
而数组则不然,因为数组是定长的数据存储结构,声明的时候内存地址和空间大小就已经定下来了。

(3)整型数的拼凑问题:
记得自己大一时候,问的C语言老师人家就是不说,就一句话——“看书去”。
其实不就是:
A. 通过 %10 实现取余即取得个位数的数字,
B. 通过 /=10 实现当前数字所处的位数前挪即不断舍弃个位数上的数字。
但是这种思维,对初学者往往是很难去理解的,只有当自己真的读懂之后,举一反三、融会贯通。
本次涉及的代码是每8个字符长度当做一个数据块进行处理,这种思想在与密码学相关的算法设计上尤为凸出。
当然算法课的长精度运算,也是一种类似东西。

一个简单的测试:

鼠标悬停于此实现预览效果

易错点:

Top1: 没有使用判断条件,忘记了担长度刚好能够整除时的情形;
if (remainder) {
			s = "\0"; // 重置为空(程序健壮性);
			s = mySubstr(str, 1 + times * slice, remainder); // 最后剩余的一小部分;
			//printf("substr = %s\n", s);
			printf("%u", myatoi(s));
		}
Top2: 字符指针s在使用之前忘记分配内存空间:
s = mySubstr(str, 1 + i * slice, slice);
s = mySubstr(str, 1 + times * slice, remainder);

以及 忘记了判断内存分配是否成功:
assert(str);// 即 str!=NULL(空指针
Top3: 忘记在末尾处添加'\0\,其实也就是内存地址越界问题:
arr[len] = '\0';
Top4: malloc使用之后忘记了free
Top5: 实参列表的参数可能会出错,如果头脑不清醒些的话:
s = mySubstr(str, 1 + i * slice, slice);
s = mySubstr(str, 1 + times * slice, remainder); // 最后剩余的一小部分;

后记

欢迎评论区留言,如能指出问题则是万分感谢!
也可发送私信、邮件:
联系方式: [email protected]
2019/11/27 21:22
发布了89 篇原创文章 · 获赞 159 · 访问量 5万+

猜你喜欢

转载自blog.csdn.net/I_love_you_dandan/article/details/103282645