【改正总结】指针的局限性,scanf() 和 void*指针


反思

【一些感悟】内存和指针
  针对这篇文章中 “scanf() 和 数组” 小节存在的事实错误,及我认为的,C 中存在的一些不得已的缺陷。
  我做了总结,并通过 Blog 记录下来。

本篇主要从两个点来阐述:
1.【一些感悟】内存和指针 中 “void* 空类型指针” 小节提到的代码。
2.scanf() 的参数。

 判断传入的指针类型

简单的冒泡排序:

void BubbleSort(void* array,int count)//注意第一个参数,我写的是 void*
{
	int i, j, temp, flag = 1;
	for (j = 0; flag == 1; j++)
	{	
		flag = 0;
		for (i = 0; i < count - j; i++)
		{
			if (array[i] < array[i + 1])
			{
				memswap(array[i + 1], array[i], sizeof array[i])
				//由于我并不知道传入数组的类型,交换数据只能通过操作内存
				//memcpy()用来交换内存,详细定义在下方
				flag = 1;
			}
		}
	}
}

memswap()的定义:

void memswap(void* a,void* b,int size){
	void* temp = malloc(size);
	memcpy(temp,a,size);memcpy(a,b,size);memcpy(b,temp,size);
	free(temp);
}

可以看出来,这段代码是错误的,因为我在排序函数中试图引用 void* 。

  我的目的是拓宽一个函数的适用范围,使得其不仅仅只针对一种数据类型排序,然而 C 对这样的传参方式无能为力,单从一个 void* 没办法判断实参的数据类型。

  老师为我提供了下图这样的解决方法:
在这里插入图片描述
  然而,很显然,这种解决方案的移植性很差(不同环境下,某些数据类型所占字节数不同)

  后来接触了标准库中的 qsort() 函数,琢磨了其思想后惊为天人——它使用了一个回调函数,通过让程序员完成比较工作来绕开 “无法判断实参数据类型” 的问题。
(详细解决方法移步.【一些感悟】内存和指针 中 “void* 空类型指针” 小节。)

  至此,问题算是解决了,但解决得并不完美。

  对于排序来说,使用一个回调函数并不能算是一个方便的做法,显然这个事情变得比以前更复杂了。那么,为什么 qsort() 函数不直接判断实参的数据类型而是使用更为复杂的回调函数呢?
  因为C 对这件事无能为力。
  也可能是认为没有必要,也可能是没考虑到,更可能的原因是,这是 C 底层性的一个表现。
  我再举一个例子,用来佐证 C 对判断实参数据类型确实无能为力的事实。

 从 scanf() 的参数的角度解释

  这里也是对 【一些感悟】内存和指针 中 “scanf() 和 数组” 小节的事实错误的改正。

  我们认为,scanf() 函数本身在设计上存在不周到的地方。
  无论你传入的指针是什么类型的,它只会傻傻地按照指定的格式化格式,从传入的指针位置开始写入数据,无论是否已经超出了变量的引用范围。
  尽管在号称更安全的 scanf_s() 中,也只是要求程序员多传入一个参数,来表示写入的最大长度,有没有感觉很傻?
  标准库都如此做了,那么我们就更加无法实现了。

  所以,C 对判断实参数据类型的的确确是无能为力的。

原文地址:https://www.cnblogs.com/gaolihai/p/13149770.html