首页 诗词 字典 板报 句子 名言 友答 励志 学校 网站地图
当前位置: 首页 > 教程频道 > 开发语言 > C++ >

您还在写像王寡妇的裹脚布一样又臭又长的main()函数吗

2012-10-10 
你还在写像王寡妇的裹脚布一样又臭又长的main()函数吗?《C++的十万个为什么》系列中的一篇原文来自:http://c

你还在写像王寡妇的裹脚布一样又臭又长的main()函数吗?
《C++的十万个为什么》系列中的一篇
原文来自:
http://chenlq.net/category/c%E7%9A%84%E5%8D%81%E4%B8%87%E4%B8%AA%E4%B8%BA%E4%BB%80%E4%B9%88

<strong><font size = "5">Q:</font></strong>

在<a href="http://chenlq.net/8-according-to-the-original-order-to-insert-a-number-in-a-sorted-array.html">[8]如何在一个已经排序的数组中按照原来的顺序插入一个数?</a>中,我们用一个main()函数完成了程序的所有功能。也就是整个函数只有一个main()函数,整个函数有60多行。我这里那样写,只是为了展示程序的整个过程,并不表示我认同这种方式(说心里话,也有偷懒的心理,我已经深刻检讨了)。
虽然功能实现了,然而,我却闻到了一股像王寡妇的裹脚布一样的又臭又长的味道。
将main()函数写的像裹脚布一样的又臭又长,是初学者最为常见的一个坏习惯。所以,我们决定将这个程序重构一下。

<strong><font size = "5">A:</font></strong>

初学者之所以会将所有内容都放到main()函数中,其一,可能是因为他们处于初学阶段,还没有学过函数的概念,不知道如何将一个程序划分到多个函数共同实现。其次,或者说更本质的原因是,缺乏模块化设计的概念,缺乏“自顶向下,逐步求精”的设计思想。
我们解决问题的最基本思路是“大事化小,小事化了”,反映到程序中,就是,我们在main()函数中解决整个问题,而这个问题比较大,我们需要将其划分成多个小问题(找到插入的位置,实现数据的插入),这样,每个小问题就可以从main()函数中独立出来,成为一个单独的函数,然后在主函数中加以调用即可。
体会下面这段程序对原程序的重构:
[source language="cpp"]
#include <iostream>
 
using namespace std;

// 在数组array中查找插入数据n的位置
int find(int* array, int count,int n)
{
  // 找到插入点
  // 这里,我们假设数据是从小到大顺序排列
  int p = 0; // 插入位置
   
  // 如果比第一个元素还小,放在第一个位置
  if(n<array[0])
  {
  p = -1;
  }
  // 如果比最后一个数据还大,超出范围,
  // 不进行插入
  else if(n > array[count-1])
  {
  p = count;
  cout<<n<<" is out of range"<<endl;
  }
  else // 如果在原来的范围内,查找位置
  {
  for (int i = 0; i <= count - 2 ; ++i)
  {
  // 是否在相邻两个数之间
  if(n>=array[i]&&n<array[i+1])
  {
  p = i;
  break; // 找到位置,结束查找
  }
  }
  }

  return p;
}

// 在数组array的位置p之后插入一个数据n
void insert(int* array,int count,int p,int n)
{
  // 以内存移动代替逐个数字移动
  // 创建一块临时内存,大小为需要移动的数据的个数
  int* temp = new int[count - p - 2];
   
  // 将需要移动的数据复制到临时内存
  memcpy(temp,
  array + p + 1, // 起始点之后的p+1开始的数据
  sizeof(int)*(count - p - 2)); // 移动的大小
   
  // 再从临时内存复制回来,
  memcpy(array + (p+2), // 复制回来时位置向后移动一个,P + 1 + 1
  temp,
  sizeof(int)*(count - p - 2)); // 少移动一个
   
  // 在空出来的位置插入数据
  array[p+1] = n;

  // 释放申请的临时空间
  delete[] temp;
}

int main()
{
  // 数组的大小
  const int count = 10;
  // 已经排序完成的数组(从小到大)
  int array[count] = {10,20,30,40,50,
  60,70,80,90,100};
   
  // 输入新插入的数据
  int n = 0;
  cout<<"Please input a number: ";
  cin>>n;
 
  // 用函数调用代替查找for循环
  int p = find(array,count,n);
 
  // 找到合适位置
  if(p != count)
  { 
  insert(array,count,p,n);
  }
 
  // 输出新的数组
  cout<<"the new array is: ";
  for(int i : array)
  {
  cout<<i<<'\t';
  }
  return 0;
}
[/source]

在改写后的程序中,我们将现对比较独立的查找插入位置和在指定位置插入数据从原来的main()函数中独立出来,形成了find()和insert()两个独立的函数,这样,main()函数只需要调用这两个函数实现相应的功能即可。整个main()函数也瘦身不少,再也不是又臭又长了。

也许你会问,所有功能在一个main()函数中实现不是挺好吗?干嘛整这么麻烦?
这是因为这个程序还比较短,全部在main()函数中勉强还可以接受,当程序越来越复杂,你能想象一个main()函数有上万行代码那将是怎样的一场噩梦吗?


反过来,这样划分可以带来实现和维护上的好处。实现的时候,只要我们约定好接口(一个函数的输入是什么,输出是什么),就可以将一个程序中的多个函数交给多个人去实现,达到分工协作。在维护的时候,如果某个函数出现了问题,我们只需要修改单个的函数就可以了,而不必去麻烦整个main()函数而大费周折。
所以,将整个程序划分到多个函数,是此刻实现的需要,也是后期维护的需要。
把王寡妇的裹脚布丢进历史的垃圾箱,和又臭又长的main()函数说个永别吧!

[解决办法]
继续修炼!

热点排行