3767|9

7815

帖子

56

TA的资源

裸片初长成(中级)

楼主
 

俺的C习题(2) [复制链接]

这个是第七章 指针的第一个题目
编写一个程序,计算从键盘输入的任意个浮点数,将所有的存储到动态分配的内存中,之后计算并显示平均值。用户不需要事先制定输入多少个数。
(我忽然想起,我上班后第一个项目,一个小键盘上,我曾做过这件事,但当时我怎么就没想到动态分配存储呢???也许因为当时的精力全集中在读键盘和其他地方去了......)
  1. /*practise 7.1*/
    #include<stdio.h>
    #include<stdlib.h>
    #include <ctype.h>


    int main(void)
    {
    int count=0;
    int capacity=0;
    int increment=5;
    double *values=NULL;
    double *buffer=NULL;
    double sum=0.0;
    char answer = 'n';

    do
    {
    //动态分配方式
    if(count == capacity)
    {
    capacity +=increment ;
    buffer=(double*)malloc((capacity) * sizeof(double));
    if(!buffer)
    {
    printf("Memory allocation is failed.Terminating the program.");
    exit(1);
    }

    if(!values) //用于第一次,value还没分配空间
    values=buffer; //把初次分配的空间传递给它,两者指向同一个地址
    else
    {
    for(int i=0;i<count;i++)
    {
    *(buffer+i)=*(values+i); //第一次过后,每次都要先用缓存buffer备份原来的value
    }
    free(values); //然后释放value
    values=buffer; //得到buffer的内容
    }
    //free(buffer); //这么干是不行的,原因当然很好理解,因为buffer的空间被values引用了。
    //那么下面那一句指向NULL,又是怎么回事?
    buffer= NULL; //这一句,为什么就没事呢?
    //查了一下百度,理由很简单。free掉一个指针指向的地址空间好理解,而赋值成NULL呢,只是把地址丢了。但
    //那块空间还在。这就好比你把钱包里的钱拿出来,但如果你不把钱包扔了,它还在你手上,只是钱包已经空了。
    //但如果你直接把钱包扔了,钱还在那里头——不过你就亏大了。
    //把free类比成把钱拿出来,把指向NULL类比成把钱包扔了。
    }

    printf("Enter a value:");
    scanf("%lf",values+count++); //扩大了空间后的values继续读入新值。
    printf("Do you want another?yes or no.\n");

    scanf(" %c",&answer);
    //这个地方,有个微小的细节,在%c前面有一个空格,不要小看它,有和没有有时差别很大
    //差别是没这个空格时,因为前边的ENTER,会直接被它读到,因为不是y,导致直接结束输入
    //至于为什么...果断查,不然我在干嘛?
    //本来,scanf是会忽略空格符的,只有指定符为%c等时偏偏不会省略。
    //这句是搜百度时搜到的。------------------------------------
    //scanf()中会用到空格 是用作分隔符的 因为scanf()可以输入多个变量
    //看来,我应该学习 小帅了,直接看源码
    //因为这个问题实在有点复杂。先MARK下,不百度了,直接找源码看吧。
    //目前我的简单理解是,那个没被忽略的 空格符 作为 分隔符,让这个%c保存的是本次输入的 y or n
    }while(tolower(answer) == 'y');


    for(int i=0;i<count;i++) //这部分没什么技术含量,就是汇总求平均。
    {
    sum += *(values+i);
    }
    printf("The average is %lf",sum/count);
    free(values);
    values = NULL; //后补,忘了指向NULL。
    return 0;
    }


复制代码

此帖出自编程基础论坛

最新回复

我在做这些题目的时候,也碰到当一个程序有两个scanf的时候,后面的scanf老是不能正常工作,后来总结经验,发现是键盘缓冲区没有清除的原因;因为在之前操作的时候,键盘缓冲区可能有很多数据没有被读走,导致后面的SCANF直接读取了前面的垃圾数据而无法正常工作!所以,我认为当一个程序有几次键盘读入数据的话,全部实行清除缓冲区的操作,否则问题太多!  详情 回复 发表于 2012-9-28 08:58
点赞 关注
个人签名

强者为尊,弱者,死无葬身之地

 

回复
举报

7815

帖子

56

TA的资源

裸片初长成(中级)

沙发
 
看这个程序费了些时间。
除了总是没搞清楚的scan以后。
就是清扫了一个盲点。
指针赋成NULL和free掉的差别。
此帖出自编程基础论坛
 
个人签名

强者为尊,弱者,死无葬身之地

 
 

回复

7815

帖子

56

TA的资源

裸片初长成(中级)

板凳
 
想找scanf的源码看看,结果费了半天劲没找着,想顺带下载一个C标准库的源码更加没戏。
找了找,就要放弃的时候,看到 博客园 上有人贴了一个实现源码。 先贴在这里,毕竟不好找,
不过乍看之下是晕的可以,好多符号没看懂,还有一些宏是不认识的

  1. scanf的实现源码

    /***
    *scanf.c - read formatted data from stdin
    *
    * Copyright (c) 1985-1997, Microsoft Corporation. All rights reserved.
    *
    *Purpose:
    * defines scanf() - reads formatted data from stdin
    *
    *******************************************************************************/

    #include <cruntime.h>
    #include <stdio.h>
    #include <dbgint.h>
    #include <stdarg.h>
    #include <file2.h>
    #include <internal.h>
    #include <mtdll.h>

    /***
    *int scanf(format, ...) - read formatted data from stdin
    *
    *Purpose:
    * Reads formatted data from stdin into arguments. _input does the real
    * work here.
    *
    *Entry:
    * char *format - format string
    * followed by list of pointers to storage for the data read. The number
    * and type are controlled by the format string.
    *
    *Exit:
    * returns number of fields read and assigned
    *
    *Exceptions:
    *
    *******************************************************************************/

    int __cdecl scanf (
    const char *format,
    ...
    )
    /*
    * stdin 'SCAN', 'F'ormatted
    */
    {
    int retval;

    va_list arglist;

    va_start(arglist, format);

    _ASSERTE(format != NULL);

    _lock_str2(0, stdin);

    retval = (_input(stdin,format,arglist));

    _unlock_str2(0, stdin);

    return(retval);
    }
复制代码

此帖出自编程基础论坛
 
个人签名

强者为尊,弱者,死无葬身之地

 
 

回复

44

帖子

0

TA的资源

一粒金砂(高级)

4
 
for(int i=0;i {
sum += *(values+i);
}

从理论上来讲,sum尽管是double,也有溢出的可能性,(count的可能性更大),呵呵,谁让楼主说是可输入任意个数呢.
这次,我承认我是来找茬的,哈哈.
此帖出自编程基础论坛
 
个人签名能力越大,责任越大;知道越多,未知更多
 
 

回复

44

帖子

0

TA的资源

一粒金砂(高级)

5
 

既然砖拍出去了,我自己来试着接一下.
刚才说了,有两个变量的溢出要注意一下.

一是这里
scanf(\"%lf\",values+count++); //扩大了空间后的values继续读入新值。

这儿count应该加入溢出判断,本来想着是查一下C语言整型最大值的宏定义,

可是刚才搜的时候查到一个关于判断通用无符合数据溢出的更理想的办法,

(原文见http://www.91tech.net/Article/SoftTech/vctech/200811/5413.html)
这样,这个地方可以改成:
scanf(\"%lf\",values+count); //扩大了空间后的values继续读入新值。
if(counter+1>counter)
counter++;
else
printf("error .......... ");//在...处加上提示信息,比如你输入数的个数超过了32767之类的

还有就是这个地方
for(int i=0;i {
sum += *(values+i);
}
同样就是加入对sum 的溢出判断,具体代码我就偷懒不敲哈.

此帖出自编程基础论坛
 
个人签名能力越大,责任越大;知道越多,未知更多
 
 

回复

7815

帖子

56

TA的资源

裸片初长成(中级)

6
 

回复 4楼 能圈就圈 的帖子

唔,这个问题.......
是的是的。
那时候刚学,没有考虑这个东西,这里的确应该考虑这个。

然后对于count那个也一样。

PS:
这个位置还有个地方,我一直不是太清楚。

就是for(int i)
这个写法。
这个写法在VC6这个编译器上好像还没遇到过不行的时候。
但是在其他时候遇到问题。
第一次是在gcc上,提示不行,还说到C99.后来才知道,只有C99支持在代码中再次定义变量后才使用。
但是一直以来没有太彻底地清查这个问题。

因为手头做的这个活,编译器手册里自称完全支持ANSI C。
然而我们试过这么做也可以,但是有的时候又不行。
看来我把这个错误归结到不同标准也是不完全的。
此帖出自编程基础论坛
 
个人签名

强者为尊,弱者,死无葬身之地

 
 

回复

7815

帖子

56

TA的资源

裸片初长成(中级)

7
 

回复 5楼 能圈就圈 的帖子

2.     防止溢出的一个方法:

#define  INC_SAT(val)  (val = ((val)+1 > (val)) ? (val)+1 : (val))

还可以做成循环计数的(加入计数器val是个无符号整数):

#define  INC_SAT(val)  (val = ((val)+1 > (val)) ? (val)+1 : (0))


老大,你说的是这个么?
恩恩,这是个不错的方法,有点像我最近写的
if(k <= 0xffff)
k++;

不过,可惜的是它没有给出警报信息
此帖出自编程基础论坛
 
个人签名

强者为尊,弱者,死无葬身之地

 
 

回复

44

帖子

0

TA的资源

一粒金砂(高级)

8
 
if(K < K+1) 比 if(k <= 0xffff)  强太多
后者严重依赖K的数据类型,
就算K是整型,有的平台上是16位,有的平台是32位,
例如,从51到STM32的移植就会出问题.
此帖出自编程基础论坛
 
个人签名能力越大,责任越大;知道越多,未知更多
 
 

回复

7815

帖子

56

TA的资源

裸片初长成(中级)

9
 

回复 8楼 能圈就圈 的帖子

额,,,,
表示突然理解。
3Q!
此帖出自编程基础论坛
 
个人签名

强者为尊,弱者,死无葬身之地

 
 

回复

2

帖子

0

TA的资源

一粒金砂(中级)

10
 

这个地方,有个微小的细节,在%c前面有一个空格,不要小看它,有和没有有时差别很大

我在做这些题目的时候,也碰到当一个程序有两个scanf的时候,后面的scanf老是不能正常工作,后来总结经验,发现是键盘缓冲区没有清除的原因;因为在之前操作的时候,键盘缓冲区可能有很多数据没有被读走,导致后面的SCANF直接读取了前面的垃圾数据而无法正常工作!所以,我认为当一个程序有几次键盘读入数据的话,全部实行清除缓冲区的操作,否则问题太多!
此帖出自编程基础论坛
 
 
 

回复
您需要登录后才可以回帖 登录 | 注册

随便看看
查找数据手册?

EEWorld Datasheet 技术支持

相关文章 更多>>
关闭
站长推荐上一条 1/6 下一条

 
EEWorld订阅号

 
EEWorld服务号

 
汽车开发圈

About Us 关于我们 客户服务 联系方式 器件索引 网站地图 最新更新 手机版

站点相关: 国产芯 安防电子 汽车电子 手机便携 工业控制 家用电子 医疗电子 测试测量 网络通信 物联网

北京市海淀区中关村大街18号B座15层1530室 电话:(010)82350740 邮编:100190

电子工程世界版权所有 京B2-20211791 京ICP备10001474号-1 电信业务审批[2006]字第258号函 京公网安备 11010802033920号 Copyright © 2005-2025 EEWORLD.com.cn, Inc. All rights reserved
快速回复 返回顶部 返回列表