⭐ 欢迎来到虫虫下载站! | 📦 资源下载 📁 资源专辑 ℹ️ 关于我们
⭐ 虫虫下载站

📄 c.txt

📁 C语言编程常见问题解答 这个帖子将不断扩充、更新 罗列大部分C语言编程的常见问题 希望各位观众支持帮助 毕竟一人之力太有限
💻 TXT
📖 第 1 页 / 共 5 页
字号:
}

  其中的“=”符号是输入错误。如果在说明str时没有使用const修饰符,那么相应的程序能通过编译但不能被正确执行。
    第二个原因是效率。如果编译程序知道某个变量不会被修改,那么它可能会对生成的代码进行某些优化。    
    如果一个函数参数是一个指针,并且你不希望它所指向的数据被该函数或该函数所调用的函数修改,那么你应该把该参数说明为const指针。如果一个函数参数通过值(而不是通过指针)被传递给函数,并且你不希望其值被该函数所调用的函数修改,那么你应该把该参数说明为const。然而,在实际编程中,只有在编译程序通过指针存取这些数据的效率比拷贝这些数据更高时,才把这些参数说明为const。 
--------------------------------------------------------------------------------
 
--  作者:PrOve
--  发布时间:2005-4-5 23:11:23

--  
10.对不同类型的变量进行算术运算会有问题吗?
    C有三类固有的数据类型:指针类型、整数类型和浮点类型;
    指针类型的运算限制最严,只限于以下两种运算:
    -  两个指针相减,仅在两个指针指向同一数组中的元素时有效。运算结果与对应于两个指针的数组下标相减的结果相同。    
    +  指针和整数类型相加。运算结果为一个指针,该指针与原指针之间相距n个元素,n就是与原指针相加的整数。
    浮点类型包括float,double和longdouble这三种固有类型。整数类型包括char,unsigned char,short,unsigned short,int,unsigned int,long和unsigned long。对这些类型都可进行以下4种算术运算:
    +  加    
    -  减
    *  乘    
    /  除
    对整数类型不仅可以进行上述4种运算,还可进行以下几种运算:
    %    取模或求余    
    >>    右移
    <<    左移
    &    按位与
    |    按位或
    ^    按位异或
    !    逻辑非
    ~    取反
    尽管C允许你使用“混合模式”的表达式(包含不同类型的算术表达式),但是,在进行运算之前,它会把不同的类型转换成同一类型(前面提到的指针运算除外)。这种自动转换类型的过程被称为“运算符升级(operator promotion)”。 
--------------------------------------------------------------------------------
 
--  作者:PrOve
--  发布时间:2005-4-6 12:27:15

--  
11.什么时候应该使用类型强制转换(typecast)?
    在两种情况下需要使用类型强制转换。第一种情况是改变运算分量的类型,从而使运算能正确地进行。下面的程序与2.12中的例子相似,但有不同之处。变量n被赋值为整数i除以整数j的结果,因为是整数相除,所以结果为0。变量f2也被赋值为i除以j的结果,但本例通过(float)类型强制转换把i转换成一个float类型,因此执行的是浮点数除法运算(见2.11),结果为0.75。
#include <stdio.h>
main ( )
{
   int i = 3;
   int j = 4
   float f1 =i/j;
   float f2= (float) i/j;
   printf("3/4== %g or %g depending on the type used. \\n",f1, f2);
}

第二种情况是在指针类型和void * 类型之间进行强制转换,从而与期望或返回void指针的函数进行正确的交接。例如,下述语句就把函数malloc()的返回值强制转换为一个指向foo结构的指针:
    struct foo *p=(struct foo *)malloc(sizeof(struct foo)); 
--------------------------------------------------------------------------------
 
--  作者:PrOve
--  发布时间:2005-4-6 12:27:35

--  
12.什么时候不应该使用类型强制转换(typecast)?
   不应该对用const或volatile说明了的对象进行类型强制转换,否则程序就不能正确运行。
   不应该用类型强制转换把指向一种结构类型或数据类型的指针转换成指向另一种结构类型或数据类型的指针。在极少数需要进行这种类型强制转换的情况下,用共用体(union)来存放有关数据能更清楚地表达程序员的意图。 
--------------------------------------------------------------------------------
 
--  作者:PrOve
--  发布时间:2005-4-6 12:28:10

--  
13.可以在头文件中说明或定义变量吗?
    被多个文件存取的全局变量可以并且应该在一个头文件中说明,并且必须在一个源文件中定义。变量不应该在头文件中定义,因为一个头文件可能被多个源文件包含,而这将导致变量被多次定义。如果变量的初始化只发生一次,ANSIC标准允许变量有多次外部定义;但是,这样做没有任何好处,因此最好避免这样做,以使程序有更强的可移植性。

--------------------------------------------------------------------------------
 
--  作者:PrOve
--  发布时间:2005-4-6 13:06:19

--  
14.哪一种排序方法最方便?
    答案是C标准库函数qsort(),理由有以下三点:
    (1)该函数是现成的;    
    (2)该函数是已通过调试的;
    (3)该函数通常是已充分优化过的。
    qsort()函数通常使用快速排序算法,该算法是由C. A.R.Hoare于1962年提出的。以下是qsort()函数的原型:
    void qsort(void *buf,size_t hum,size_t size,
    int(*comp)(const void *ele1,const void *ele2));
    qsort()函数通过一个指针指向一个数组(buf),该数组的元素为用户定义的数据,数组的元素个数为num,每个元素的字节长度都为size。数组元素的排序是通过调用指针comp所指向的一个函数来实现的,该函数对数组中由ele1和ele2所指向的两个元素进行比较,并根据前者是小于、等于或大于后者而返回一个小于、等于或大于0的值。   
    例3.1中给出了一个函数sortStrings(),该函数就是通过qsort()函数对一个以NULL指针结束的字符串数组进行排序的。将例3.1所示的代码和本章结尾的有关代码一起编译成一个可执行程序后,就能按字母顺序对一个以NULL指针结束的字符串数组进行排序了。

1:#include<stdlib. h>
2:
3: /*
4:  * This routine is used only by sortStrings(), to provide a
5:  * string comparison {unction to pass to qsort().
6:  */
7: static int comp(const void * elel, const void * ele2)
8: {
9:    return strcmp( * (const char * * ) ele1,
10:                * (const char * * ) ele2);
11: }
12:
13: / * Sort strings using the library function qsort() * /
14: void sortStrings(const char * array[-\'])
15: {
16,       /* First, determine the length of the array * /
17:       int num;
18:
19:      for (num=O; array[num]; num++)
20:
21:      qsort(array, num, sizeof( * array), comp) ;
22: }

在例3.1中,第19行和第20行的for循环语句用来计算传递给qsort()函数的数组元素个数,函数comp()的作用是将函数qsort()传递给它的类型(const void *)转换为函数strcmp()
所要求的类型(const char *)。因为在函数qsort()中,ele1和ele2是指向数组元素的指针,而在例3.1中这些数组元素本身也是指针,因此,应该先将ele1和ele2转换为const char **类型,然后在转换结果前加上指针运算符“*”,才能得到函数strcmp()所要求的类型。
    尽管有qsort()函数,但程序员经常还要自己编写排序算法程序,其原因有这样几点:第一,在有些异常情况下,qsort()函数的运行速度很慢,而其它算法程序可能会快得多;第二,qsort()函数是为通用的目的编写的,这给它带来了一些不利之处,例如每次比较时都要通过用户提供的一个函数指针间接调用一个函数;第三,由于数组元素的长度在程序运行时才能确定下来,因此用来在数组中移动数组元素的那部分代码没有针对数组元素长度相同的情况进行优化;第四,qsort()函数要求所有数据都在同一个数组中,而在实际应用中,数据的长度和性质千变万化,可能很难甚至无法满足这一要求;第五,qsort()函数通常不是一种稳定的排序方法。

--------------------------------------------------------------------------------
 
--  作者:PrOve
--  发布时间:2005-4-6 13:07:41

--  
15.哪一种排序方法最快?
    首先,对大多数包含排序应用的程序来说,排序算法的速度并不重要,因为在程序中排序  的工作量并不是很多,或者,与排序相比,程序中其它操作所花费的时间要多得多。
    实际上,没有哪一种排序算法永远是最快的,在运行程序的软硬件环境相同的情况下,不同排序算法的速度还与数据的长度、性质以及数据的初始顺序有关。
    在笔者的“工具箱”中,有三种算法在不同的情况下都是最快、最有用的,这三种算法分别是快速排序、归并排序和基数排序。
    快速排序
    快速排序是一种分割处理式的排序算法,它将一个复杂的排序问题分解为若干较容易处理的排序问题,然后逐一解决。在快速排序算法中,首先要从数据集的数据中选择一个数据作为分割值,然后将数据分成以下3个子集:
    (1) 将大于分割值的数据移到分割值前面,组成子集1;
    (2) 分割值本身为子集2;    
    (3) 将小于分割值的数据移到分割值后面,组成子集3。
    等于分割值的数据可以放在任意一个子集中,这对快速排序算法没有任何影响。
    由于子集2已经是有序的,所以此后只需对子集1和子集3进行快速排序。
    需要注意的是,当数据集很小时,无法进行快速排序,而要使用其它排序算法。显然,当数据集中的数据只有两个或更少时,就不可能将数据集再分割成三个子集。实际上,当数据集比
较小时,程序员就应该考虑是否仍然采用快速排序算法,因为在这种情况下另外一些排序算法往往更快。
    例3. 2a用快速排序算法重写了例3.1中的字符串数组排序程序,你同样可以将它和本章末尾的有关代码一起编译成一个可执行程序。程序中定义了一个宏,它可使程序更易读,并能加快执行速度。
    快速排序算法是由程序中的myQsort()函数实现的,它是按升序对一个字符串数组进行排序的。函数myQsort()的具体工作过程如下:
    (1)首先检查最简单的情况。在第17行,检查数组中是否没有或只有一个元素——在这种情况下,数组已经是有序的,函数就可以返回了。在第19行,检查数组中是否只有两个元素——在这种情况下,要么数组已经是按升序排列的,要么交换这两个元素的位置,使它们按升序排列。
    (2)在第28行至第53行,将数组分割为两个子集:第一个子集中的数据大于或等于分割值,第二个子集中的数据小于分割值。
    在第28行,选择数组中间的元素作为分割值,并将其和数组中的第一个元素交换位置。
    在第37行至第39行,在数组中找到属于第二个子集的第一个元素;在第45行至第47行,在数组中找到属于第一个子集的最后一个元素。
    在第49行,检查属于第二个子集的第一个元素是否位于属于第一个子集的最后一个元素的后面,如果是,则第一个子集的所有元素都已在第二个子集的所有元素的前面,数据已经划分好了;否则,交换这两个元素的位置,然后重复上述这种检查。
    (3)当两个子集分割完毕后,在第55行,将分割值和第一个子集中的最后一个元素交换位置,排序结束时这个分割值将仍然排在现在这个位置。在第57行和第58行,分别调用myQsort()函数对分割所得的子集进行排序。当所有的子集都经过排序后,整个数组也就排好序了。

    例一个不使用qsort()函数的快速排序算法程序

1: #include <stdlib.h>
2:
3: #define exchange(A, B, T)  ((T) = (A), (A) = (B),(B)=(T))
4:                                        
5:
6: / * Sorts an array of strings using quick sort algorithm * /
7: static void myQsort(const char * array[], size_t num)
8: {
9:     const char * temp
10:     size_t i, j;
11:
12:       /*
13:       * Check the simple cases first:
14:       * If fewer than 2 elements, already sorted
15:       * If exactly 2 elements, just swap them (if needed).
16:          * /
17:       if (num <2)
18:                return;
19:       else if (num==2)
20:        {
21:           if (strcmp(array[O], array[1])>O)
22:                 exchange (array[0], array[1] ,temp)
23:        }
24:        / *
25:        * Partition the array using the middle (num/2)
26:        element as the dividing element.
27:          * /
28:       exchange (array[0], array[num / 2], temp)
29:       i=1;
30:       j=num;
31:       for (; ;)
32:         {
33:             / *
34:               * Sweep forward until and element is found that
35:               * belongs in the second partition.
36:               * /
37:              while (i<j && strcmp (array, array[0])
38:                                                   <=0)
39:                    i++;
40:              / *
41:                * Then sweep backward until an element
42:                * is found that belongs in the first
43:                * partition.
44:                * /
45:             while (i<j&& strcmp(array[j-1], array[O]
46:                                               >=0)
47:                  j--;
48:              / * If no out-of-place elements, you\'re done * /
49:            if (i>=j)
50:                  break
51:               / * Else, swap the two out-of-place elements * /
52:              exchange(array, array[j-l], temp)
53:        }
54:       / * Restore dividing element * /
55:       exchange(array[O], array[i-1], temp)
56:       / * Now apply quick sort to each partition * /
57:       myQsort (array, i-1 )
58:       myQsort (array + i, num-i)
59:  }
60:

⌨️ 快捷键说明

复制代码 Ctrl + C
搜索代码 Ctrl + F
全屏模式 F11
切换主题 Ctrl + Shift + D
显示快捷键 ?
增大字号 Ctrl + =
减小字号 Ctrl + -