您的位置:首页 > 编程语言 > C语言/C++

(C++练习)细节知识记录

2019-03-13 21:47 363 查看

  最近捡起很久没有复习过的C++,在编程的过程中发现了很多细节问题,也可以说是稍微深入一点的知识吧,决定在此文中一一记录下来,并且在以后的编程学习中无限期更新。


十进制转十六进制

问题描述

  十六进制数是在程序设计时经常要使用到的一种整数的表示方式。它有0,1,2,3,4,5,6,7,8,9,A,B,C,D,E,F共16个符号,分别表示十进制数的0至15。十六进制的计数方法是满16进1,所以十进制数16在十六进制中是10,而十进制的17在十六进制中是11,以此类推,十进制的30在十六进制中是1E。
  给出一个非负整数,将它表示成十六进制的形式。

输入格式

  输入包含一个非负整数a,表示要转换的数。0<=a<=2147483647

输出格式

  输出这个整数的16进制表示

样例输入

  30

样例输出

  1E

代码

#include <iostream>
using namespace std;

int main(int argc, char *argv[]) {
long int a;
char c[32] = {'0'};
int tag = 0;
cin >> a;
if (a < 0 || a > 2147483647){
cout << "error" << endl;
return 0;
}
int result = a, mod;
while(result != 0){
mod = result % 16;
switch(mod){
case 10: c[tag++] = 'A'; break;
case 11: c[tag++] = 'B'; break;
case 12: c[tag++] = 'C'; break;
case 13: c[tag++] = 'D'; break;
case 14: c[tag++] = 'E'; break;
case 15: c[tag++] = 'F'; break;
default:
c[tag++] = '0' + mod;
break;
}
result = result / 16;
}

for(int i = tag ; i >= 0; i--){
cout << c[i];
}
return 0;
}

知识点总结

  2147483647(二十一亿四千七百四十八万三千六百四十七)是2147483646与2147483648之间的自然数,也是欧拉在1772年所发现的一个梅森素数,它等于2^31-1,是32位操作系统中最大的符号型整型常量,也就是4个字节的int类型能表示的最大值,这就是为什么经常在游戏中碰到经验值或者金钱的上限是21E。


十六进制转十进制

问题描述

  从键盘输入一个不超过8位的正的十六进制数字符串,将它转换为正的十进制数后输出。
  注:十六进制数中的10~15分别用大写的英文字母A、B、C、D、E、F表示。

样例输入

  FFFF

样例输出

  65535

代码

#include <iostream>
#include <string.h>
using namespace std;

int main(int argc, char *argv[]) {
string s;
cin >> s;
char c[9];
strncpy(c,s.c_str(),s.length()+1);

int tag = 0;
for(int i = 0; i < 9; i++){
if(c[i] == '\0'){
tag = i - 1;
break;
}
}

int a[8] = {0};
for(int i = 0; i <= tag; i++){
switch(c[i]){
case 'A': a[i] = 10; break;
case 'B': a[i] = 11; break;
case 'C': a[i] = 12; break;
case 'D': a[i] = 13; break;
case 'E': a[i] = 14; break;
case 'F': a[i] = 15; break;
default:
a[i] = c[i] - '0';
break;
}
}
long long result = 0;
for(int i = 0; i < tag + 1; i++){
long long temp = 1;
for (int j = 0; j < tag - i; j++){
temp *= 16;
}
result += a[i] * temp;
}
cout << result << endl;
return 0;
}

知识点总结

1)字符数组转换成字符串:

char ch [] = "ABCDEFG";
string str(ch);//也可string str = ch;
char ch [] = "ABCDEFG";
string str;
str = ch;//在原有基础上添加可以用str += ch;

2)字符串转换成字符数组:

string str = "ABCDEFG";
char ch[8];
for(int i = 0; i < str.len(); i++){
ch[i] = str[i];
}
ch[str.len()] = '\0';
string str;
cin >> str;
char ch[100];
strncpy(ch,str.c_str(),str.length()+1);//str.length()+1表示要把'\0'也复制到数组

  c_str()函数返回一个指向正规C字符串的指针, 内容与本string串相同.,这是为了与C语言兼容,在C语言中没有string类型,故必须通过string类对象的成员函数c_str()把string 对象转换成C中的字符串样式。


十六进制转八进制

问题描述

  给定n个十六进制正整数,输出它们对应的八进制数。

输入格式

  输入的第一行为一个正整数n (1<=n<=10)。
  接下来n行,每行一个由09、大写字母AF组成的字符串,表示要转换的十六进制正整数,每个十六进制数长度不超过100000。

输出格式

  输出n行,每行为输入对应的八进制正整数。

  【注意】

  输入的十六进制数不会有前导0,比如012A。
  输出的八进制数也不能有前导0。

样例输入

  2
  39
  23ABC

样例输出

  71
  435274

错误代码示例

#include <iostream>
#include <string.h>
using namespace std;

int main(int argc, char *argv[]) {
int h[10][100000];
int b[400000];
int o[10][140000];
char temp[100000];
int n;
cin >> n;
if ( n < 1 || n > 10){
cout << "error" << endl;
return 0;
}
int len[10] = { 0 };

//赋值十六进制数组
string s;
for(int i = 0; i < n; i++){
memset(temp,'\0',sizeof(temp));
cin >> s;
strncpy(temp,s.c_str(),s.length()+1);
len[i] = s.length();
for(int j = 0; j < len[i]; j++){
switch(temp[j]){
case 'A': h[i][j] = 10; break;
case 'B': h[i][j] = 11; break;
case 'C': h[i][j] = 12; break;
case 'D': h[i][j] = 13; break;
case 'E': h[i][j] = 14; break;
case 'F': h[i][j] = 15; break;
default:
h[i][j] = temp[j] - '0';
break;
}
}
}

int tag;//记录二进制数组有多少位
int tag2[10] = { 0 };//记录每个八进制数组有多少位
//赋值二进制数组和八进制数组
for(int i = 0; i < n; i++){
//二进制数组赋值
tag = 0;
memset(b,0,sizeof(b));
for(int j = 0; j < len[i]; j++){
int x = h[i][j];
for(int k = 0; k < 4; k++){
tag++;
b[j * 4 + 3 - k] = x % 2;
x /= 2;
}
}
//八进制数组赋值
int mod = tag % 3;
if(mod == 1){
o[i][0] = b[0];
for(int j = 1; j < tag; j += 3){
o[i][(j + 2) / 3] = 4 * b[j] + 2 * b[j + 1] + b[j + 2];
}
tag2[i] = (tag + 2) / 3;
}
else if(mod == 2){
o[i][0] = 2 * b[0] + b[1];
for(int j = 2; j < tag; j += 3){
o[i][(j + 1) / 3] = 4 * b[j] + 2 * b[j + 1] + b[j + 2];
}
tag2[i] = (tag + 1) / 3;
}
else{
for(int j = 0; j < tag; j += 3){
o[i][j / 3] = 4 * b[j] + 2 * b[j + 1] + b[j + 2];
}
tag2[i] = tag / 3;
}
}

for(int i = 0; i < n; i++){
int flag = 0;
//找到第一个不为0的八进制开始输出
for(int j = 0; j < tag2[i]; j++){
if (o[i][j] != 0){
flag = j;
break;
}
}
for(; flag < tag2[i]; flag++){
cout << o[i][flag];
}
cout << endl;
}
return 0;
}

正确代码

#include <iostream>
#include <string.h>
using namespace std;

int h[10][100000];
int b[400000];
int o[10][140000];
char temp[100000];

int main(int argc, char *argv[]) {
int n;
cin >> n;
if ( n < 1 || n > 10){
cout << "error" << endl;
return 0;
}
int len[10] = { 0 };

//赋值十六进制数组
string s;
for(int i = 0; i < n; i++){
memset(temp,'\0',sizeof(temp));
cin >> s;
strncpy(temp,s.c_str(),s.length()+1);
len[i] = s.length();
for(int j = 0; j < len[i]; j++){
switch(temp[j]){
case 'A': h[i][j] = 10; break;
case 'B': h[i][j] = 11; break;
case 'C': h[i][j] = 12; break;
case 'D': h[i][j] = 13; break;
case 'E': h[i][j] = 14; break;
case 'F': h[i][j] = 15; break;
default:
h[i][j] = temp[j] - '0';
break;
}
}
}

int tag;//记录二进制数组有多少位
int tag2[10] = { 0 };//记录每个八进制数组有多少位
//赋值二进制数组和八进制数组
for(int i = 0; i < n; i++){
//二进制数组赋值
tag = 0;
memset(b,0,sizeof(b));
for(int j = 0; j < len[i]; j++){
int x = h[i][j];
for(int k = 0; k < 4; k++){
tag++;
b[j * 4 + 3 - k] = x % 2;
x /= 2;
}
}

//八进制数组赋值
int mod = tag % 3;
if(mod == 1){
o[i][0] = b[0];
for(int j = 1; j < tag; j += 3){
o[i][(j + 2) / 3] = 4 * b[j] + 2 * b[j + 1] + b[j + 2];
}
tag2[i] = (tag + 2) / 3;
}
else if(mod == 2){
o[i][0] = 2 * b[0] + b[1];
for(int j = 2; j < tag; j += 3){
o[i][(j + 1) / 3] = 4 * b[j] + 2 * b[j + 1] + b[j + 2];
}
tag2[i] = (tag + 1) / 3;
}
else{
for(int j = 0; j < tag; j += 3){
o[i][j / 3] = 4 * b[j] + 2 * b[j + 1] + b[j + 2];
}
tag2[i] = tag / 3;
}
}

for(int i = 0; i < n; i++){
int flag = 0;
//找到第一个不为0的八进制
for(int j = 0; j < tag2[i]; j++){
if (o[i][j] != 0){
flag = j;
break;
}
}
for(; flag < tag2[i]; flag++){
cout << o[i][flag];
}
cout << endl;
}

return 0;
}

知识点总结

  正确代码与错误代码不同之处只有一个地方,那就是将数组的声明放在了函数外,声明成了全局变量,那为什么放在函数内部声明成为局部变量就不行呢?为此我查阅了一番资料,弄清了其中的缘由。
  首先,数组的size是有限制的,在32位操作系统中,size数据类型是unsigned int,而在64位系统中,它的类型是unsigned long。前者能表示的最大值为232-1,后者能表示的最大值为264-1,这也就表示数组最大能有多大。
  其次,就是数据存放在不同的地方,也限制了这个数据类型最大能有多大。数据的分配方式有静态分配和动态分配两种,使用静态分配方法分配的局部数组是在栈中划分空间的,也就是说这一类型的数组所占空间最大不能超过栈的空间(栈有多少空间…能力有限…望大佬指点)。使用动态分配方法(new)分配的数组是在堆中划分空间的,堆的大小是与本机有效的虚存大小有关的,因此堆的空间大小一般比较大。
  一个C++程序的内存是怎样分配的呢?通常来说会分为5个区(见下表):

存放内容
全局数据区 全局变量、静态变量、全局常变量
代码区 程序运行的函数
栈区 局部变量、函数参数、程序返回地址
堆区 new产生的对象
字符串常量区 字符串常量

除字符串常量外的一般常量是一个“立即数”,在程序代码中。除字符串常量外的局部常变量与局部变量同等看待。也有将全局常变量与字符串常量划分到常量区的分法,实际上,全局变量、静态变量与常量的存储很难细分,也没必要区分,可统称为全局数据区。
  因此,想要解决数组过大的问题,有两种方法。一是将数组存放在堆上,二则是将数组声明为全局变量,也就是本例正确代码中采取的方法。(参考文章:C++如何定义一个长度超过一百万的数组C++中数组的最大长度

内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: