栏目分类:
子分类:
返回
名师互学网用户登录
快速导航关闭
当前搜索
当前分类
子分类
实用工具
热门搜索
名师互学网 > IT > 软件开发 > 后端开发 > Java

C和指针 第16章 标准函数库 16.13 编程练习

Java 更新时间: 发布时间: IT归档 最新发布 模块sitemap 名妆网 法律咨询 聚返吧 英语巴士网 伯小乐 网商动力

C和指针 第16章 标准函数库 16.13 编程练习

1. 计算机人群中颇为流行的一个笑话是“我29岁,但我不告诉你这个数字的基数!”如果基数是16,这个人实际上是41岁。编写一个程序,接受一个年龄作为命令行参数,并在2~36的范围中计算那个字面值小于等于29的最小基数。例如,如果用户输入41,程序应该计算出这个最小基数为16。因为在十六进制中,十进制41的值是29。 
#include
#include

int main( int argc, char **argv ){
    int result_value;
    int initial_value;
    int result_base;
    int base;
    int flag;
    
    result_value = atoi( *++argv );
    printf( "result_value = %dn", result_value );
    initial_value = 29;
    while( initial_value >= 10 ){
        int dec = initial_value / 10;
        int unit = initial_value % 10;
        flag = 0;
        base = 2;
        while( base <= 36 ){
            int compute_value = dec * base + unit;
            if( compute_value > result_value ){
                break;
            } else if( compute_value == result_value ){
                result_base = base;
                flag = 1;
                break;
            } 
            ++base;
        }
        if( flag == 1 ){
            break;
        }
        --initial_value;
    } 
    printf( "result_base = %dn", result_base );
    
    return EXIT_SUCCESS;
}
 
2.编写一个函数,通过返回一个范围为1~6的随机整数来模拟掷骰子。注意,这6个值出现的概率应该相同。当这个函数第一次调用时,它应该用当天的当前时间作为种子来产生随机数。
解析:
除了“概率相等”这个要求,这个问题的其他部分非常简单。这里有个例子。普通情况下你将把一个随机数对6取模,产生一个0~5的值,将这个值加上1并返回。但是,如果随机数生成函数所返回的最大值是32767,那么这些值就不是“概率相等”。从0~32765返回的值所产生的0~5之间各个值的概率是相等。但是,最后两个值(32766和32767)的返回值将分别是0和1,这使它们的出现概率有所增加(是5462/32768而不是5461/32768)。由于我们需要的答案的范围很窄,因此这个差别是非常小的。如果这个函数试图产生一个范围在1和30000之间的随机数,那么前2768个值的出现概率将是后面那些值的两倍。程序中的循环用于消除这种错误,方法是一旦出现最后两个值,就产生另一个随机值。 
*/

#include
#include
#include

 
#define MAX_OK_RAND (int)((((long)RAND_MAX + 1) / 6 ) * 6 - 1)

int throw_die( void ); 

int main( void ){
    printf( "RAND_MAX = %d, MAX_OK_RAND = %dn", RAND_MAX, MAX_OK_RAND );
    printf( "%d %d %d", throw_die(), throw_die(), throw_die() );
    
    return EXIT_SUCCESS;
}

int throw_die( void ){
    static int is_seeded = 0;
    int value;
    
    if( !is_seeded ){
        is_seeded = 1;
        srand( (unsigned int)time( NULL ) );
    }
    do{
        value = rand();
    } while( value > MAX_OK_RAND );
    
    return value % 6 + 1;
}
 
3. 编写一个程序,以一种3岁小孩的方式来说明当前的时间(例如,时针在5上面,分在在12上面)。 
#include
#include
#include  

int main( void ){
    time_t t;
    struct tm *ptm;
    
    t = time( NULL );
    ptm = localtime( &t );
    printf( "at present, hour hand locates on the %d digit, minute hand locates on the %d digit.n",
            ptm->tm_hour, ptm->tm_min );
    return EXIT_SUCCESS;
}

4. 编写一个程序,接受3个整数为命令行参数,把它们分别解释为月(1~12),日(1~31)和年(0~?)。然后,它应该打印这个日子是星期几(或将是星期几)。对于那个范围的年份,这个程序的结果才是正确的? 
#include
#include
#include

int main( int argc, char **argv ){
    const char *str[] = { "Sunday", "Monday", "Tuesday", "Wednesday", "Thursday", "Friday", "Saturday" };
    struct tm var_tm;
    
    var_tm.tm_mon = atoi( *++argv );
    var_tm.tm_mday = atoi( *++argv );
    var_tm.tm_year = 1900 + atoi( *++argv );
    printf( "var_tm.tm_mon = %02d, var_tm.tm_mday = %02dn"
            "var_tm.tm_year = %4d, var_tm.tm_wday = %dn",
            var_tm.tm_mon, var_tm.tm_mday, var_tm.tm_year, var_tm.tm_wday );
    printf( "%sn", str[var_tm.tm_wday - 1] );
     
    return EXIT_SUCCESS;
}
 


#include
#include
#include

double wind_chill( double temp, double velocity );


int main( void ){
    double temp;
    double velocity;
    double result;
    
    temp = -5.0;
    velocity = 10.0;
    result = wind_chill( temp, velocity );
    printf( "temp = %.1f, velocity = %.1f, result = %.1fn", temp, velocity, result );
    
    return EXIT_SUCCESS;
}

double wind_chill( double temp, double velocity ){
    const double var_a = 10.45;
    const double var_b = 10.0;
    const double var_c = -1.0;
    double var_x = 1.78816 ;
    double var_t = 33.0 - temp; 
    double result;
    
    result = 33.0 - (var_a + var_b * sqrt( velocity ) + var_c * velocity ) * var_t / 
    (var_a + var_b * sqrt( var_x ) + var_c * var_x );
    
    return result;
}
 
6. 用于计算抵押的月付金额的公式如下所示:
    P = AI / (1 - (1 + I)^(-N))
A是贷款的数量,I是每个时段的利率(小数形式,而不是百分比形式),N是贷款需要支付的时段。例如,一笔100000美元的20年期利率8%的贷款,每月需要支付836.44美元(20年共有240个支付时段,每个支付时段的利率为0.66667)。
    double payment( double amount, double interest, int years );
year指定贷款的时期,amount是贷款的数量,interest是用百分比形式(例如12%)表示的利率。函数应该计算并返回贷款的月付金额。(四舍五入至美分)。 
#include
#include
#include

double payment( double amount, double interest, int years );

int main( void ){
    double amount;
    double interest;
    int years;
    double pay;
    
    amount = 100000.0;
    years = 20;
    interest = 0.08;
    pay = payment( amount, interest, years );
    printf( "amount = %.2lf, interest = %.5lf, years = %d, pay = %.2lfn",
    amount, interest / 12, years, pay );
    
    return EXIT_SUCCESS;
}

double payment( double amount, double interest, int years ){
    return (amount * interest / 12) / (1 - pow( 1 + interest / 12, -(years * 12) )); 
}
 
7.设计良好的随机数生成函数所生成的值看上去很像随机数,但随着时间的延长,其结果会显示出一致性。从随机值派生而来的数字也具有这些属性。例如,一个设计欠佳的随机数生成函数的返回值看上去像是随机数,但实际上却是奇数和偶数交替出现。如果将这些看似的随机数对2取模(例如,用于模拟硬币的结果),其结果将是一个0和1交叉的序列。另一种较差的随机数生成函数只返回奇数值,将这些值对2取模的结果将是一个连续的0序列。这两类值都无法作为随机值使用,因为它们不够“随机”。 
编写一个程序,在你的系统中测试随机数生成函数。你应该生成10000个随机数并执行两种类型的测试。首先是频率测试,把每个随机数对2取模,看看结果0和1的次数各有多少。然后对3~10进行同样的测试。这些结果将不会具有精确地一致性,但各个余数在频率上的峰谷差异不应该太大。

其次是周期型频率测试,取每个随机数和它之前的那个随机数,将它们对2取模,使用这两个余数作为一个二维数组的下标并增加指定位置的值。对3~10重复进行上面的取模测试。同样,这些结果将不会具有很严格的规律,但应该具有近似的一致性。
修改你的程序,以便可以为随机数生成函数提供不同的种子,并对使用几个不同的种子所产生的随机值进行测试。你的随机数生成函数是不是足够优秀?
解析:
这个程序从本质上来说是一个一次性程序,这个不优雅的解决方案用于完成这个任务是绰绰有余的。 
 
#include
#include

 
int frequency2[2];
int frequency3[3];
int frequency4[4]; 
int frequency5[5];
int frequency6[6];
int frequency7[7];
int frequency8[8];
int frequency9[9];
int frequency10[10];
 
int cycle2[2][2];
int cycle3[3][3];
int cycle4[4][4]; 
int cycle5[5][5];
int cycle6[6][6];
int cycle7[7][7];
int cycle8[8][8];
int cycle9[9][9];
int cycle10[10][10];


#define CHECK( number, f_table, c_table )
    remainder = x % number;
    f_table[remainder] += 1;
    c_table[remainder][last_x % number] += 1

 
#define PRINT_F( number, f_table )
    printf( "nFrequency of random numbers modulo %dnt", number );
    for( i = 0; i < number; i += 1 )
        printf( " %5d", f_table[i] );
    printf( "n" );

 
#define PRINT_C( number, c_table )
    printf("nCyclic frequency of random numbers modulo %dn", number );
    for( i = 0; i < number; i += 1 ){
        printf( "t" );
        for( j = 0; j < number; j += 1 ){
            printf( " %5d", c_table[i][j] );
        }
        printf( "n" );
    }
     
int main( int ac, char **av ){
    int i;
    int j;
    int x;
    int last_x;
    int remainder;
    
    
    if( ac > 1 ){
        srand( atoi( av[1] ) );
    } 
    last_x = rand();
    
    
    for( i = 0; i < 10000; i += 1 ){
        x = rand();
        CHECK( 2, frequency2, cycle2 );
        CHECK( 3, frequency3, cycle3 );
        CHECK( 4, frequency4, cycle4 );
        CHECK( 5, frequency5, cycle5 );
        CHECK( 6, frequency6, cycle6 );
        CHECK( 7, frequency7, cycle7 );
        CHECK( 8, frequency8, cycle8 );
        CHECK( 9, frequency9, cycle9 );
        CHECK( 10, frequency10, cycle10 );
        last_x = x;
    } 
    
    
    PRINT_F( 2, frequency2 );
    PRINT_F( 3, frequency3 );
    PRINT_F( 4, frequency4 );
    PRINT_F( 5, frequency5 );
    PRINT_F( 6, frequency6 );
    PRINT_F( 7, frequency7 );
    PRINT_F( 8, frequency8 );
    PRINT_F( 9, frequency9 );
    PRINT_F( 10, frequency10 );
    
    PRINT_C( 2, cycle2 );
    PRINT_C( 3, cycle3 );
    PRINT_C( 4, cycle4 );
    PRINT_C( 5, cycle5 );
    PRINT_C( 6, cycle6 );
    PRINT_C( 7, cycle7 );
    PRINT_C( 8, cycle8 );
    PRINT_C( 9, cycle9 );
    PRINT_C( 10, cycle10 );
    
    return EXIT_SUCCESS;
}

8. 某个文件包含了家庭成员的年龄。同一个家庭成员的年龄位于一行,中间由一个空格分隔。例如,下面的数据
    45 42 22
    36 35  7  3  1
    22 20 
描述了3个分别具有3个、5个和2个成员的家庭的年龄。
编写一个程序,计算用这种文件形式表示的每个家庭的平均年龄。它应该使用%5.2f格式打印平均年龄,后面跟一个冒号和输入数据。这个问题和前一章的编程练习类似,但它没有家庭成员的数量的限制!但是,可以假定每个输入行的长度不超过512字符。 
#include
#include
#include

#define BUFFER_SIZE 512

void average( FILE *input );

int main( void ){
    FILE *age_file;
    char age_file_name[] = "age_db.txt";
    age_file = fopen( age_file_name, "r" );
    if( !age_file ){
        printf( "fail to open age_db_txt file.n" );
        exit( EXIT_FAILURE );
    } 
    average( age_file );
    fclose( age_file );
    
    return EXIT_SUCCESS;
}

void average( FILE *input ){
    char buffer[BUFFER_SIZE];
    
    char temp[BUFFER_SIZE]; 
    while( fgets( buffer, BUFFER_SIZE, input ) ){
        strcpy( temp, buffer );
        char *token;
        int age;
        float average;
        int sum;
        int counter;
        
        average = 0.0;
        sum = 0;
        counter = 0;
        for( token = strtok( buffer, " "); token != NULL; token = strtok( NULL, " ") ){
            age = atoi( token );
            sum += age;
            ++counter;
        }
        average = sum * 1.0 / counter;
        printf( "%5.2f:%sn", average, temp );
    }
}


9. 在一个有30名学生的班级里,两个学生的生日是同一天的概率有多大?如果一群人中有两个成员的生日是同一天的概率为50%,那么这个人群应该有多少人?
编写一个程序,回答这些问题。取30个随机数,并把它们对365取模,分别表示一年内的各天(忽略闰年)。然后对这些值进行检查,看看有没有相同的。重复这个测试10000次,对这个频率做一个估计。
为了回答第2个问题,对程序进行修改,使其把人数作为一个命令行参数,把当天的时间作为随机数生成函数的种子,数次运行这个程序,以获得这个概率较为精确的估计值。 
#include
#include
#include

#define ARR_LEN 30
#define TEST_NUM 10000

int main( int argc, char **argv ){
    int counter; 
    int array[ARR_LEN];
    int *p;
    int *p2;
    int i;
    
    
    
    int num = atoi( *++argv );
    int *person;
    person = (int *)malloc( sizeof(int) * num );
    
    for( i = 0; i < TEST_NUM; ++i ){
        srand( (unsigned int)time( NULL) );
        p = person;
        p2 = person + num;
        while( p < p2 ){
            *p++ = rand() % 365;
        } 
        counter = 0;
        for( p = person; p < p2; ++p ){
            printf( "%3d ", *p );
            ++counter;
            if( counter % 5 == 0 ){
                printf( "n" );
                counter = 0;
            }
        }
        counter = 0;
        for( p = person; p < p2 - 1; ++p ){
            int *p3;
            for( p3 = p + 1; p3 < p2; ++p3 ){
                if( *p == *p3 ){
                    printf( "%d ", *p );
                    ++counter;
                }
            }
        }
        printf( "n" );
        printf( "counter = %dn", counter );
        printf( "the probability of two persons have a birthday day together in %d persons is %f%%n",
        ARR_LEN, counter * 100.0 / 30 );
    }
    free( person );
    
    return EXIT_SUCCESS;
}

10.插入排序(insertion sort)就是把值逐个插入到一个数组中。第一个值存储于数据的起始位置,后续的每个值在数组中寻找合适的插入位置。如果需要的话,可以对数组中原有的值进行移动以留出空间,然后再插入该值。
编写一个名叫insertion_sort的函数执行这个任务。它的原型应该和qsort函数一样。
提示:考虑把数组的左边作为已排序的部分,右边作为未排序的部分。最初已排序部分为空。在函数插入每个值时,已排序部分和未排序部分的边界向右移动,以便插入。当所有的元素都插入完毕时,未排序部分为空,数组排序完毕。 

#include
#include

int compare( void const *a, void const *b );
void insertion_sort( void *base, size_t n_elements, size_t el_size, 
            int (*compare)( void const *, void const * ) );
int main( void ){
    int array[] = { 8, 10, -6, 4 };
    size_t array_len = sizeof(array) / sizeof(*array);
    size_t elem_size = sizeof(*array);
    int i;
    
    printf( "print original elements of array:n" );
    for( i = 0; i < array_len; ++i ){
        printf( "%d ", array[i] );
    } 
    printf( "n" );
    insertion_sort( array, array_len, elem_size, compare );
    printf( "after insertion_sort( array, array_len, elem_size, compare ),n"
    "print original elements of array:n" );
    for( i = 0; i < array_len; ++i ){
        printf( "%d ", array[i] );
    } 
    
    return EXIT_SUCCESS;
}

int compare( void const *a, void const *b ){
    return *(char const *)a - *(char const *)b;    
}

void insertion_sort( void *base, size_t n_elements, size_t el_size, 
            int (*compare)( void const *a, void const *b ) ){
    
    int j;
    for( j = 1; j < n_elements; ++j ){
        char temp[el_size]; 
        int m;
        for( m = 0; m < el_size; ++m ){
            temp[m] = *((char *)base + j * el_size + m);
        } 
        printf( "1n" );
        int i;
        i = j;
        while( i > 0 ){
            int k;
            int flag = 0;
            for( k = 0; k < el_size; ++k ){
                if( compare( (char const *)base + (i - 1) * el_size + k, (char const *)base + i * el_size + k ) > 0 ){
                    printf( "2.1n" );
                    flag = 1;
                    break;
                } else if( compare( (char const *)base + (i - 1) * el_size + k, (char const *)base + i * el_size + k ) < 0 ){
                    printf( "2.2n" );
                    flag = 0;
                    break;
                } 
            }
            if( flag == 1 ){
                printf( "3.1n" );
                int n;
                for( n = 0; n < el_size; ++n ){
                    char temp2;
                    temp2 = *((char *)base + i * el_size + n); 
                    *((char *)base + i * el_size + n) = *((char *)base + (i - 1) * el_size + n); 
                    *((char *)base + (i - 1) * el_size + n) = temp2; 
                }
            } else{ 
                printf( "3.2n" );
                break;
            }
            --i;
        }
        for( m = 0; m < el_size; ++m ){
            *((char *)base + i * el_size + m) = temp[m];
        }
        printf( "n" );
    }                
}

 

转载请注明:文章转载自 www.mshxw.com
本文地址:https://www.mshxw.com/it/1013982.html
我们一直用心在做
关于我们 文章归档 网站地图 联系我们

版权所有 (c)2021-2022 MSHXW.COM

ICP备案号:晋ICP备2021003244-6号