<C语言>数据文件自动生成的实现

功能描述程序自动生成.txt文件,内部存放生成的数据,其中第一行存储数据的条数n,从第二行开始存储随机生成的三元组数据,共n条。条数参数n和文件名称参数FileName通过cmd中的命令行参数传入,两参数顺序不定,缺少参数时,条数n随机生成,文件名可以指定。

关键词命令行参数随机函数rand();文件读写操作


0 绪论

任何工程项目都是模块的有机结合,C语言程序也不例外。所以我们可以建立一种先拆分后组装的思想,把该项目设计为三个过程模块:命令行参数获取、随机数据生成、数据写入文件。

1 命令行参数获取

命令行参数是一个人机交互的概念。用户在cmd窗口某一路径下,可用输入可执行文件名(.exe)的方式启动程序,此文件名与其后的字符串都是命令行参数,各命令行参数间以空格划分。

在C或C++语言中,程序想要获得命令行参数,则其main函数形式需为:int main(int argc, char *argv[]),其中argc是命令行参数个数,char *argv[]是指向命令行参数(字符串)的指针数组。这两个关键信息将为我们的程序提供判断条件,也就是说,我们可以藉此分情况讨论不同输入状态和内容下程序执行情况的不同。我们程序需要从命令行参数获取的两个参数(条数参数n和文件名称参数FileName),都是在指针数组指向的字符串之中。必须明确,C语言中操作字符串是通过其在内存中存储单元的首地址进行的,也就是说,数组argv[]中的元素存储的是字符串,每一个都是char *指针类型,指针变量通过存储字符串地址(实际是字符串的首地址)存储字符串。以下我们按照输入命令行参数个数argc的不同展开分析讨论:

  1. 【argc == 1】首先,第1个命令行参数必然是一个完整无误的可执行文件的文件名(有无格式后缀.exe不影响),如“ Lab2.exe ”、“ Lab2 ”均可,则argc至少取1,argv[0]所指向的该文件名字符串也与我们所需参数无关,实际上目标参数需要从第2个及之后的命令行参数中获取。这意味着当输入的命令行参数只有1个的情况下,也就是argc == 1时,程序是无法获取两个参数的,此时设定条数参数n随机生成、文件名称参数FileName由程序指定
  2. 【argc == 2】再考虑命令行参数只有2个的情况下,也就是argc == 2时,程序能且仅能获取其中1个参数,但具体是哪个参数需要我们对第2个命令行参数的字符串(argv[1])进行特征识别。我们可以这样划分特征:若字符串首字符为数字字符,则该字符串作为条数参数n的获取来源,否则将其作为文件名称参数FileName的获取来源。这个特征可用程序语言表示为对语句(*argv[1] >= '0' && *argv[1] <= '9')运用条件语句。第2个命令行参数若满足上述特征,则从中获取条数参数n,文件名称参数FileName由程序指定;若不满足上述特征,则从中获取文件名称参数FileName,而条数参数n由程序随机生成。如前文所强调的,argv[1]通过存储第2个字符串的地址(实际是字符串首地址)存储字符串,而这里的*argv[1]就是第2个字符串存储地址(首地址)所指向的内容,也就是其首字符。
  3. 【argc >= 3】考虑到命令行参数有3个及以上的情况,也就是argc >= 3时,程序至少可以获取其中1个参数。我们始终将特征性强的条数参数n作为筛选依据,这时可能筛选出现所有命令行参数均都不满足上述特征的情况,为了在一定程度上保证程序的健壮性,我们在argc值较大时应该避免字符串逐一进行特征筛选,为此我们可以设定特征筛选最多进行2次。若第2个命令行参数满足上述特征,则从中获取条数参数n,文件名称参数FileName从第3个命令行参数中获取;若第2、3个命令行参数分别不满足、满足上述特征,则从第3个命令行参数获取条数参数n,文件名称参数FileName从第2个命令行参数中获取;若第2、3个命令行参数均不满足上述特征,对此我们可以直接设定条数参数n随机生成,从第2个命令行参数中获取文件名称参数FileName

将以上过程展现为程序流程图如下图所示:



将以上过程展现为程序代码如下所示:

void get_n_and_FileName(int argc, char *argv[])
{
	//判断命令行参数的用户指令输入情况
	if (argc == 1)                              //用户只输入了一个命令行参数字符串
	{
		srand((int)time(0));
		n = random(100);                         //未输入条数参数,随机生成
		FileName = "test.txt";                  //未输入文件名,指定其为test
		printf("条数参数未输入,已随机生成:%d\n",n);
	}
	else if (argc == 2)                         //用户输入了两个命令行参数字符串
	{
		if (*argv[1] >= '0' && *argv[1] <= '9') //判断第二个命令行参数字符串首位是否为数字字符
		{
			int j = 1;
			n = get_n(argv, j);              //调用函数计算n的值并返回
			FileName = "test.txt";              //未输入文件名,指定其为"test.txt"
		}
		else                                   //第二个命令行参数字符串首位不为数字字符
		{
			FileName = argv[1];                //令第二个命令行参数字符串为文件名
			srand((int)time(0));
			n = random(100);                   //未输入条数参数,随机生成
			printf("条数参数未输入,已随机生成:%d\n",n);
		}  
	}
	else if (argc >= 3)                         //用户输入了三个及以上命令行参数字符串
	{
		if (*argv[1] >= '0' && *argv[1] <= '9')//判断第二个命令行参数字符串首位是否为数字字符
		{
			int j = 1;
			n = get_n(argv, j);
			FileName = argv[2];                //令第三个命令行参数字符串为文件名
		}
		   
		else if	(*argv[2] >= '0' && *argv[2] <= '9') //判断第三个命令行参数字符串首位是否为数字字符
		{
			int j = 2;
			n = get_n(argv, j);
			FileName = argv[1];                //令第二个命令行参数字符串为文件名
		}
		else                                   //第二、三个命令行参数字符串首位均不为数字字符
		{
			FileName = argv[1];                //令第二个命令行参数字符串为文件名
			srand((int)time(0));
			n = random(100);                   //条数参数未输入,随机生成
			printf("条数参数未输入,已随机生成:%d\n",n);
		}
	}
}

在两个参数来源是命令行参数时需要注意,很有可能命令行参数字符串是不规范的,导致程序处理有误。比如说字符串“ 1a/2b+c ”要给到条数参数n,则规范的n应取“ 12 ”;比如字符串“ a1/b2+c ”要给到文件名称参数FileName,则规范的FileName应取 “a1/b2+c.txt ”。所以前文中保守性的采用了“ 从命令行参数获取参数 ”的语句来分析叙述,而非是“ 赋值 ”、“ 作为 ”等字眼,意在表明还需要对字符串进行进一步处理。此外我们知道,字符串中的数字字符固然可以对照ASCII码表转换为数值,即(argv[j][i] - '0')其中argv[ j ]自然表示第 j 个字符串,而 i 表示的是字符串中的第 i 个字符),但整合在一起的数值之间彼此是孤立的,多个“数值”和一个“数”之间缺少一个“进制”的概念。而FileName也不是一味的补充格式后缀,对于已有规范后缀的,需要保持原貌。以上几点归结于获取参数的规范性问题,接下来进一步讨论分析:

  1. 【获取规范的条数参数n】首先通过strlen()函数获取该字符串的长度len,方便遍历整个字符串以逐个找到数字字符,各数值通过按位相乘相加的方法得到条数参数n的值,即n = n * 10 + (argv[j][i] - '0')。此处我们必须考虑条数参数n作为int整型变量,其值范围为-2147483648至2147483647,在字符串数字字符足够多的时候有可能会溢出,而且条数参数n值过大在之后的数据生成过程中会极大占用程序运行内存从而可能导致系统崩溃。所以我们这里可以设定当条数参数n的值大于等于100时,便取前两位有效数字(有效指首位不为0),那么条数参数n取值范围为0~99,同时也很容易设定条数参数n随机生成范围也为0~99,即rand() % 100。显然,条数参数n取值为0是我们不愿意看到的,那就意味着没有数据生成了,所以还需做一次筛值。条数参数n取值为0的情况有两种,一是作为条数参数n来源的命令行参数中除了首位为数字字符“ 0 ”以外,其他字符均不为数字字符;二是条数参数n来源于随机生成过程中出现极端情况,恰好生成“ 0 ”。针对第一种情况,我们在条数参数n规范完毕后判断其值是否为0,若事件为真,则提示并随机生成其值。我们为什么不通过将首位数字字符的范围从0~9变为1~9解决此问题,是因为我们想将参数的划分特征强化,毕竟“ 是数字则满足特征 ”和“ 是1~9的数字则满足特征 ”在感官上还是有差别的。针对第二种情况,我们可以在数据生成前做一个while循环,若条数参数n为0则再次随机生成其值,直到其值不为0,如下图程序所示。或者我们从开始就直接设定条数参数n随机生成范围为1~99,这是更高效的解决方法,即(rand() % (100-1)) + 1。本文为便于理解相关概念,使用的是前述方法。
  2. 【获取规范的文件名称参数FileName】文件名称参数FileName的不规范,都表现在“ .txt ”的格式后缀上。为了字符串识别的高效,我们一样可以通过strlen()函数获取其长度len。当其值小于4时,文件名称参数FileName自然不会有完整的格式后缀,都默认由函数strcat(FileName, Name)在其末尾添加“ .txt ”,因为函数的两个形参要为字符指针,故定义了char *Name = ".txt"。当其值大于等于4时,我们可以将FileName后4位字符与字符“ .txt ”逐位比较ASCII码值是否都相同,该功能由函数strcmp(FileName + (len - 4),".txt")实现。若返回值是为真,说明文件名称参数FileName是规范的,无需处理;若为假,同样由函数strcat(FileName, Name)在其末尾添加“ .txt ”即可。

将以上过程展现为程序流程图如下两图所示:


                                             

 


将以上过程展现为程序代码如下所示:

int get_n(char *argv[], int j)
{
	int len = strlen(argv[j]);                 //获取第j+1个命令行参数字符串的长度
	int k = 0;
	for (int i = 0; i < len; i++)     
	{
		while (argv[j][i] >= '0' && argv[j][i] <= '9') //依次获取数字字符串的数值
		{
			k = n;
			n = n * 10 + (argv[j][i] - '0');   //位乘相加,恢复数字字符串的int数值
			if (n >= 100)
			{
				n = k;
				i = len;
				printf("条数参数过大,已取有效前两位:%d\n",n);
			}
			else i++;
		}
	}
	if (n == 0)
	{
		srand((int)time(0));
		n = random(100);                       //随机生成条数参数n
		printf("条数参数不规范,已随机生成:%d\n",n);
	}
	return n;
}
    while (n == 0)
	{
		Sleep (1000);                           //延时1秒以产生不同的种子
		srand((int)time(0));                    //设置随机数种子
		n = random(100); 
		printf("条数参数不规范,已随机生成:%d\n",n);
	}
void norm_FileName()
{
	char *Name = ".txt";
	int len = strlen(FileName);       //取文件名字符串长度
	if (len < 4)                     //文件名字符串长度小于等于4,则认为其无格式后缀
	{
		strcat(FileName, Name);       //给文件名字符串添加“.txt”格式后缀
	}
	else
	{
		int flag = strcmp(FileName + (len - 4),".txt");
										//判断文件名字符串中有无“.txt”格式后缀
		if (flag != 0)
		{
		strcat(FileName, Name);       //给文件名字符串添加“.txt”格式后缀
		}
	}
}

2 随机数据生成

首先说明,计算机中一般不使用真随机数,使用的随机数一般是伪随机数替代的,下文中提及的随机数也是如此。我们使用到的是伪随机数发生器PRNG技术,使用某个数(称之为随机数种子)作用于一个确定性算法,就可以得到[0,1]均匀分布的序列,该序列就是伪随机比特流/位流,其具有类似于随机数的均匀性、独立性等统计特征。在这之中,我们程序的确定性算法一般固定不变,我们使用不同的种子就能得到不同的随机数序列,而使用相同的种子,则会复现随机数序列。

C/C++里是没有自带的random(int number)函数的,我们可以使用rand()函数来进行构造。rand()函数会产生随机数,随机数值的范围没有限定的话,是在0~RAND_MAX之间,RAND_MAX在头文件stdlib.h中定义, 其值为2147483647。要设定随机数值的范围也很简单,可以用模运算rand() % x取范围为0~x之间的数,比如 x 取100则实现了上文中0~99的随机数。为方便使用,我们直接宏定义随机数函数 #define  random(x)  (rand() % x)但生成随机数据还应注意以下两点:

  1. 【种子设定】我们将上述函数放到一个循环体中多次生成随机数序列,可以观察到数与数之间的确没有明显规律,当我们再次运行程序时,会发现随机数序列与上次相同。这意味着每次运行其实并不随机,相同的输入会有相同的输出。复现的随机数序列自然是因为相同的种子作用于了相同的算法,我们通过使用srand()函数设定种子可以验证,观察到的复现序列就是种子为1时的序列。也就是说,程序不调用srand()函数将会默认将随机数种子取为1。那么有没有一种机制保证我们每次运行程序时种子都不尽相同?我们可以考虑具有一维性的时间,因为每时每刻都在变化且不重复。在C语言中用time()函数获取自Unix标准时间戳(1970年1月1日0点0分0秒,GMT)到当前的秒数。我们只需要其返回秒数值,则函数参数为空指针(NULL),NULL的定义是(void *) 0,所以time(0)与time(NULL)均可获取秒数值。我们可在每次调用random()函数前用srand((int)time(0))设定种子解决多次复现问题,前文中的随机生成条数参数n的过程也都使用了种子设定。
  2. 【延时函数】还应该考虑到,我们程序一次运行过程中,内部可能不止一次的使用了random()函数,若多次使用种子设定的时间间隔过短,相同的秒数值得到相同的种子,相同的种子则得到相同的序列。一般两次种子设定之间添加sleep()函数做1秒以上的延时可以确保种子不同。但是在循环体内部,尤其要避免随机生成和种子设定函数同时存在,在循环体内部固然可以添加sleep()函数做延时使每次循环的种子都不同,但其代价是程序会数次执行延时函数,导致极大的资源浪费。

种子设定和延时函数实际使用如下所示:

	Sleep (1000);                              //延时1秒以产生不同的种子
	srand((int)time(0));                       //设置随机数种子
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			a[i][j] = random(100);            //随机生成100范围内的数,赋给数组
		}
	}

解决了随机数据的生成问题,我们还要为数据找到一个集中存储的地方,以便在后面的文件操作过程中一次性的完成所有输出,而不是每生成一个数据便操作一次文件写入的策略,以求精简程序的操作量。从功能描述的n条三元组:<元素1, 元素2, 元素3>形式的数据来看,确实应该采用n\times3的数组完成存储。但在C语言中,直接定义一个数组是不能使用变量的,而直接以最大值100\times3来定义数组虽然简单,却造成了程序内存资源的浪费,所以考虑用动态内存分配(malloc)的方法完成数组的定义。

动态内存分配定义数组的程序代码如下所示:

	int **a = (int**)malloc(sizeof(int*) * n);       //申请n行动态内存分配空间
	for (int i = 0; i < n; i++)
	{
		a[i] = (int *)malloc(sizeof(int) * 3);       //申请3列动态内存分配空间
	}
	for (int i = 0; i < n; i++)       
	{
		free(a[i]);                                  //逐个释放指针内存
	}
	free(a);                                         //释放指向指针的二级指针内存
  1. int **a = (int**)malloc(sizeof(int*) * n);  这里malloc()函数在堆区分配n个int *指针类型的内存空间,完成后将其分配的内存空间首元素(指针)地址返回给二级指针a,用二级指针保存一级指针的地址,相当于int *a[n]。注意这里的int **a因为涉及到数据在函数间传递,所以会用全局变量来定义,此时在函数中用“a”而不用“int **a”。
  2. a[i] = (int*)malloc(sizeof(int)*3); 这里malloc()函数在堆区对n个指针逐个分配3个int类型的内存空间,相当于分配二维数组a[n][3]。
  3. free(a[i]);  free(a);  当内存不再使用时,要释放在堆区分配的内存空间,不然会造成内存泄漏,先对n个指针分配的空间逐一释放,再释放指向n个指针的二级指针a分配的空间。

将以上过程展现为程序流程图如下左图所示:


                                             


3 数据写入文件

在C语言中,文件的操作都是通过库函数来完成的,所以大部分都是流程化的操作,此处不再具体讲解。这里提点一些文件打开和关闭过程的小细节:

  1. 【文件打开】我们打开的文件在“写”操作下可以是已存在的,也可以是新创建的,而“读”操作下只能是已存在的文件,我们以“w”方式写时,如果有已存在文件,文件会被先删除再创建。我们创建的文件在不指定存放地址(包括绝对路径和相对路径)的情况下会存放在当前目录之中,比如我程序的可执行文件在E:\Projects\Lab2\Debug路径下,所以生成的.txt文件(以ASCII码值存储的文本文件)就在这个Debug目录下。还有,打开(创建)文件时文件名可以以字符串的方式命名,如“abc.txt”,也可以用指针,本文采用的文件名指针就是FileName,指针的好处就是可以改变指针指向的内容。
  2. 【文件关闭】虽然文件在没有关闭操作命令下,在程序结束时也会被关闭,但这样做很不安全。对于缓冲文件系统来说,文件的操作是通过缓冲区进行的,在写入数据时,首先是写到文件缓冲区里,只有写满512B,才会由系统真正写入磁盘扇区。如果写的数据不到512B,程序异常终止,那么缓冲区的数据将被丢失。文件关闭操作能强制将缓冲区的数据写入磁盘扇区,还将释放文件缓冲区单元和FILE结构,使文件指针与具体文件脱钩(文件指针变量依然存在)。

将写入过程展现为程序流程图如上右图所示:

将写入过程展现为程序代码如下所示:

void write_File()
{
	FILE *fp = fopen(FileName, "w");           //建立文件指针,将文件指针指向.txt文件
	fprintf(fp, "%d\n", n);                    //将条数参数打印到文件中
	for (int i = 0; i < n; i++)
	{
		for (int j = 0; j < 3; j++)
		{
			if (j != 2)
				fprintf(fp, "%d,", a[i][j]);  //将int型数字打印到文件中
			else
				fprintf(fp, "%d", a[i][j]);   //将int型数字打印到文件中
		}
		fprintf(fp,"\n");
	}
	fclose(fp); //关闭文件
}

4 测试运行

本程序在Visual Studio 2010中进行测试(高版本可能会认定个别函数名不安全,根据报错修改即可),我们在可执行文件的目录下(E:\Projects\Lab2\Debug)对文件路径键入cmd可打开命令窗口(或者通过WIN+R,运行cmd到可执行文件所在目录),我们在程序中添加了多个关键信息的打印语句,所以可根据窗口打印结果初步判定程序运行是否正常,然后再查看生成文档内容。

我们根据功能要求来设计我们要输入的命令行参数如下:

  1. "Lab"  可执行文件不完整,无第2、3个命令行参数。应:不能运行程序;
  2. "Lab2"  有可执行文件,无第2、3个命令行参数。应:参数n未输入,随机生成条数参数n,n值范围为1~99,文件名指定为“test.txt”;
  3. "Lab2 012"  有可执行文件、第2个命令行参数(数字),无第3个命令行参数。应:获取条数参数n为12,文件名指定为“test.txt”;
  4. "Lab2 0343"  有可执行文件、第2个命令行参数(数字,大于100),无第3个命令行参数。应:取有效前两位,条数参数n为34,文件名指定为“test.txt”;
  5. "Lab2 0abc"  有可执行文件、第2个命令行参数(数字,n取0),无第3个命令行参数。应:输入不规范,随机生成条数参数n,n值范围为1~99,文件名为“test.txt”;
  6. "Lab2 0ab12"  有可执行文件、第2个命令行参数(数字,n取12),无第3个命令行参数。应:获取条数参数n为12,文件名指定为“test.txt”;
  7. "Lab2 abc"  有可执行文件、第2个命令行参数(小于4),无第3个命令行参数。应:参数n未输入,随机生成条数参数n,n值范围为1~99,文件名为“abc.txt”;
  8. "Lab2 .txt"  有可执行文件、第2个命令行参数(等于4,格式后缀),无第3个命令行参数。应:参数n未输入,随机生成条数参数n,n值范围为1~99,文件名为“.txt”;
  9. "Lab2 abc.txx"  有可执行文件、第2个命令行参数(大于4),无第3个命令行参数。应:参数n未输入,随机生成条数参数n,n值范围为1~99,文件名为“abc.txx.txt”;
  10. "Lab2 abc.txt"  有可执行文件、第2个命令行参数(大于4,格式后缀),无第3个命令行参数。应:参数n未输入,随机生成条数参数n,n值范围为1~99,文件名为“abc.txt”;
  11. "Lab2 abd.txt"  有可执行文件、第2个命令行参数(大于4,格式后缀),无第3个命令行参数。应:参数n未输入,随机生成条数参数n,n值范围为1~99(种子不同),文件名为“abd.txt”;
  12. "Lab2 567 abe"  有可执行文件、第2个命令行参数(数字)、第3个命令行参数。应:取有效前两位,条数参数n为56,文件名为“abe.txt”;
  13. "Lab2 abf 890"  有可执行文件、第2个命令行参数、第3个命令行参数(数字)。应:取有效前两位,条数参数n为89,文件名为“abf.txt”;
  14. "Lab2 a12 0000"  有可执行文件、第2个命令行参数、第3个命令行参数(数字)。应:输入不规范,随机生成条数参数n,n值范围为1~99,文件名为“a12.txt”;
  15. "Lab2 +03456 0789"  有可执行文件、第2个命令行参数(大于4)、第3个命令行参数(数字)。应:取有效前两位,条数参数n为78,文件名为“+03456.txt”;
  16. "Lab2 01234 12345"  有可执行文件、第2个命令行参数(数字)、第3个命令行参数(数字,大于4)。应:取有效前两位,条数参数n为12,文件名为“12345.txt”;
  17. "Lab2 AbCdE fGhIj"  有可执行文件、第2个命令行参数(大于4)、第3个命令行参数(大于4)。应:参数n未输入,随机生成条数参数n,n值范围为1~99,文件名为“AbCdE.txt”;
  18. "Lab2 AbCde fGhIj 01234"  有可执行文件、第2个命令行参数(大于4)、第3个命令行参数(大于4)、第4个命令行参数(数字)。应:参数n未输入,随机生成条数参数n,n值范围为1~99,文件名为“AbCde.txt”;
  19. "Lab2 0000 01234 0000"  有可执行文件、第2个命令行参数(数字)、第3个命令行参数(数字)、第4个命令行参数(数字)。应:输入不规范,随机生成条数参数n,n值范围为1~99,文件名为“01234.txt”;
  20. "Lab2 0000 01235 0000"  有可执行文件、第2个命令行参数(数字)、第3个命令行参数(数字)、第4个命令行参数(数字)。应:输入不规范,随机生成条数参数n,n值范围为1~99(种子不同),文件名为“01235.txt”;

以上共列举了20种测试情况,覆盖所有要求的功能范围,同时也测试我们的相关设定是否有效,但不对超长字符、超多命令行参数等极端个别情况进行测试。由于连续测试,指定生成的同名文件会被最新文件覆盖,预计可得到14个.txt文件,我们将重点对比(6, 16)、(10, 11)、(19, 20)这3个对照组中随机值是否正常。

命令窗口测试情况如下图所示:

我们从命令窗口观察到所有测试项返回值均为预期值,下面查看文档生成情况:

除去原有3个非文本文档,实际得到的.txt文档实际为13个,必预期的少1个,经查询,欠缺文档的文件名为“AbCde.txt”。再次在命令窗口输入命令行参数"Lab2 AbCde fGhIj 01234",发现窗口正常返回:n的值为25,文件名为“AbCde.txt”,而文件目录下始终没有该文件名的文档。因为文件名极为相似,我们打开文件“AbCdE.txt”查看其内容是否正常,发现其内部存储的行数值正好是最新运行返回的行数值25。加上其他6个重点关注的文档,展示其内容如下(个别过长数据未截满):

根据上述情况,我们合理怀疑是程序在打开/创建文件并进行“写”操作的过程中,系统不能分辨文件名存在大小写的差别而导致的,故在百度中搜索“C语言中文件名区分大小写字母吗”的问题,果然发现有网友回答如下:

所以可以断定是Windows的文件名大小写的识别机制造成的上述情况。在我们重点关注的6个文档内容中,前两个对照组中值都不相同,验证了数据的随机性,而最后考察随机数种子是否发生改变的对照组(19,20)巧合性的同时产生了值为41的条数参数,不过两者数据内容并不相同也无直接联系,说明设定种子的功能正常。

5 工程代码

工程项目下载路径:https://download.csdn.net/download/qq_41804982/15916303

本工程对各功能模块进行了函数封装,格式规范、注释详细、易于阅读。

6 写在后面

如果理解了程序设计思路中所说的三个过程,我们可以想象一下在地铁站的售票机上买票的场景,也是三个阶段:

  1. 人通过点击售票机屏幕告诉机器目标站点,并完成投币(人通过命令行参数告诉程序关键信息,并启动程序);
  2. 售票机程序生成找零数额和卡片数额信息(程序生成随机数据和文件名信息);
  3. 信息传给硬币仓退币,卡片仓写额吐卡(数据传给目标文件写入并关闭)。

我们把程序抽象的过程具化开来,有助于我们去理解各中环节,我们也能体会技术和生活的交融,融汇的不仅是应用场景,甚至是思路逻辑。

我想,如果说技术修炼之路除了靠实践经验的累积之外没有捷径可走的话,那我们能不能在思维上弯道超车?其实在动手写这篇文章之前,程序已经完工,运行结果也较为满意。但是当我对这个程序的思考随着文章逐渐深入时,却发现这个程序变得陌生了,因为编辑的每段文字在引导读者的思路之前,都是在引导我自己的思路,各处探究性的表述都是自己给自己挖的坑,需要更详细的查阅、更缜密的思考来填补,文章写作衍生出来的诸多细枝末节是我很难回答不上来的,这之中竟然还发现了两三处设计思路在逻辑上的不能自洽。所以整个写作过程,就是一个暴露问题、解决问题,再暴露、再解决的过程,我也借此机会扫掉了一些盲点、消除了一些误解、加深了一些认知。虽然写得不轻松,但还是要说,写技术文章也是一件挺美妙的事情,享受这种感觉,并且有点上头。

题外话:这是本人的首篇文章,漏洞可能比较多,希望读者多批评多给意见。在之后的学习生活中,争取每月能发布1~2篇。我们致力技术,也分享技术。

7 参考资料

函数参数:https://blog.csdn.net/weixin_40162095/article/details/113992025

随机函数:https://blog.csdn.net/u013745804/article/details/82379266

指针数组:https://blog.csdn.net/liusicheng2008_liu/article/details/80412586

感谢众多网友的系列参考资料,在此向所列资料作者致谢,也向一些缺漏的作者致歉。尤其感谢好友龙某提供的顾问服务。

评论 6
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

自矜不待

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值