约瑟夫环c语言出现段错误,算法竞赛入门经典 紫书 第四章
一点小问题
关于判断素数的几点
//该函数有严重缺点:
//不能用于n==1和n较大的情况
//在n接近int的最大值时:
//若i=46340时,i*i=2147395600//若i=46341时,i*i=2147488281超过了int的最大值,溢出变成了负数,就会继续进行下去
int is_prime(int n)
{
for (int i = 2; i * i <= n; i++)
{
if (n % i == 0)
return 0;
}
return 1;
}
//编写函数的时候,应该尽量保证该函数能对任何合法参数得到正确的结果
//改进后
//优点:避免了每次重复计算sqrt(n)
//通过四舍五入避免了浮点误差
int is_prime(int n)
{
if (n <= 1)
return 0;
int m = floor(sqrt(n) + 0.5);
for (int i = 2; i<=m; i++)
{
if (n % i == 0)
return 0;
}
return 1;
}
谨慎地使用全局变量
调用栈
调用栈描述的是函数之间的调用关系
由多个栈帧组成,每个栈帧对应着一个未运行完的函数
栈帧中保存了该函数的返回地址和局部变量,因而不仅能在执行完毕后找到正确的返回地址,还能自然地保证了不同函数间的局部变量互不相干——因为不同函数之间对应不同的栈帧
指针易翻
这有一段错误的程序
void swap(int* a, int* b)
{
int* t;
*t = *a;
*a = *b;
*b = *t;
}
这个程序错误的原因是:
指针 t 在使用之前必须赋值
t在赋值之前是不确定的。如果这个不确定的值所代表的内存单元恰好是能写入的,那么这段程序将正常工作;但如果不是,而是只读的,那么程序就会可能崩溃
数组作参数易翻
这有一段错误的程序:
int sum(int a[])
{
int ans = 0;
for (int i = 0; i < sizeof(a); i++)
{
ans += a[i];
}
return ans;
}
错误的原因:
sizeof(a)是无法得到数组的大小的
因为,数组作为参数传递给函数时,实际上只有数组的首地址作为指针传递给了函数。
在函数定义中的int a[]等价于int *a。
在只有地址信息的情况下,是无法知道数组里有多少个元素的
正确的做法:
加一个参数,即数组的元素个数
一般的,若p是指针,k是正整数,那么p+k就是指针p后面的第k个元素,p-k是p前面的第k个元素,而如果p1和p2是类型相同的指针,则p2-p1是从p1到p2的元素个数
那么我们对计算数组和的函数可以用两种写法:
1.
int sum(int* begin, int* end)
{
int n = end - begin;
int ans = 0;
for (int i = 0; i < n; i++)
{
ans += begin[i];
}
return ans;
}
int sum(int* begin, int* end)
{
int* p = begin;
int ans = 0;
for (int* p = begin; p != end; p++)
{
ans += *p;
}
return ans;
}
上述两种写法都是左闭右开
第二种写法更为普遍
把数组作为指针传递给函数时,数组内容是可以修改的。
如果要写一个“返回数组“的函数,可以加一个数组参数,然后在函数中修改这个数组的内容
递归
在C语言的函数中,调用自己和调用其他函数并没有任何本质区别,都是建立新栈帧,传递参数并修改当前代码行。
在函数体执行完毕后,删除栈帧,处理返回值并修改当前代码行。
段错误
编译后产生的可执行文件里都保存着与操作系统相关的内容。
段。是指二进制文件内的区域,所有某种特定类型的信息被保存在里面。
在可执行文件里,正文段用于存储指令
数据段用于存储已初始化的全局变量
BSS段用于存储未赋值的全局变量所需的空间
调用栈不存储在可执行文件中,而是在运行时创建
调用栈所在段称为堆栈段
堆栈段也有自己的大小,不能被越界访问,否则就会出现段错误
栈溢出,那么就是每次递归调用都会往调用栈里增加一个栈帧,久而久之,就越界了。
在运行时,程序会动态创建一个堆栈段,里面存放着调用栈,因此保存着函数的调用关系和局部变量
局部变量也是存放在堆栈段内的。
栈溢出不一定是递归调用太多,也可能是局部变量太大
因此,我们一般把较大的数组存放在main函数外
例题子
例题4-1 古老的密码 UVa1339
//qsort函数的声明
void qsort(void* base, size_t num, size_t size, int (*comparator)(const void*, const void*))
//qsort函数实现的是快速排序算法
//参数说明:
//待排序的数组起始地址
//元素个数
//元素的大小
//一个指向函数的指针,该函数必须具有以下行书
int cmp(const void *,const void *) {...}
//这个函数中,const void *的意思是:
//指向常数的万能的指针,它可以通过强制类型转化变成任意类型的指针
//例如,如果排序的对象是个整型数组,那么:
int cmp(const void* a, const void* b)
{
return *(int*)a - *(int*)b;
}
//一般的,需要先把参数a和参数b转化为真实的类型,然后让cmp函数当ab时分别返回负数,0,和正数即可。
qsort在算法竞赛中不经常使用
经常使用sort函数
这里是为了告诉“将一个函数作为参数传递给另外一个函数”是很有用的
例题4-2 刽子手游戏 UVa489
我们先来考虑,程序设计的方式
一般有两种:
自顶向下和自底向上
算法竞赛中一般是自顶向下
即:
先写伪代码,然后转化为实际的代码
先写主程序,包括对函数的调用,在实现函数本身。
这个题没有什么难点,只是说注意一点就可以
代码的注释我都不想写了
太简单了
#include
#include
#define maxn 100
int left, chance;
char s[maxn], s2[maxn];
int win, lose;
void guess(char ch)
{
int bad = 1;
for (int i = 0; i < strlen(s); i++)
{
if (s[i] == ch)
{
left--;
s[i] = ' ';//字符串序列中有当前猜的字母,则对这个清为空格
bad = 0;
}
}
if (bad)
--chance;
if (!chance)
lose = 1;
if (!left)
win = 1;
}
int main()
{
int rnd;
while (scanf("%d%s%s", &rnd, s, s2) == 3 && rnd != -1)
{
printf("Round %d\n", rnd);
win = lose = 0;
left = strlen(s);
chance = 7;
for (int i = 0; i < strlen(s2); i++)
{
guess(s2[i]);
if (win || lose)
break;
}
if (win)
printf("You win.\n");
else if (lose)
printf("You lose.\n");
else
printf("You chickened out.\n");
}
return 0;
}
例题4-3 救济金发放 UVa133
这个需要注意的地方就是
循环的处理方式
这个算作是约瑟夫环的进阶版
int go(int p, int d, int t)
{
while (t--)
{
do
{
p = (p + d + n - 1) % n + 1; //向前、后走
}while (a[p] == 0);//跳过为0项
}
return p;
}
例题4-4 信息解码 UVa213
书上代码:
#include
#include
int readchar()
{
for (;;)
{
int ch = getchar();
if (ch != '\n' && ch != '\r')
return ch;//一直读到换行符为止
}
}
//readint主要用于读取01序列
int readint(int c)//用于读取c位二进制字符,并转换为十进制数
{
int v = 0;
while (c--)
{
v = v * 2 + readchar() - '0';
}
return v;
}
int code[8][1 << 8];
int readcodes()//用于读取编码,并形成编码序列
{
memset(code, 0, sizeof(code));//对编码序列清零
code[1][0] = readchar();//读取编码头的第一个字符
for (int len = 2; len < 7; len++)//len表示 编码长度,len=2,即表示下面进行对00,01,10的编码对应
{
for (int i = 0; i < (1 << len) - 1; i++)//例如,当len=2时,那么会有三个字符输入,即(1
int ch = getchar();//读字符
if (ch == EOF)//程序结束,整个程序的结束
return 0;
if (ch == '\n' || ch == '\r')//编码头的读取结束
return 1;
code[len][i] = ch;//将字符存入所对应的位置。例如01,就存储长度为2的,第2个位置;10在存入长度为2的,第3个位置
}
}
return 1;
}
int main()
{
while (readcodes())//读取编码头,形成编码序列
{
for (;;)
{
int len = readint(3);//读取三位二进制数,以形成编码长度
if (len == 0)//标志结束,即000
break;
for (;;)
{
int v = readint(len);
if (v == (1 << len) - 1)//标志读到了全1序列,则直接退出。进行下一个长度的读取
break;
putchar(code[len][v]);
}
}
putchar('\n');
}
return 0;
}
习题
习题4-1 UVa1589
习题4-2 UVa201
习题4-3 UVa220
习题4-4 UVa253
习题4-5 UVa1590
习题4-6 UVa508
习题4-7 UVa509
习题4-8 UVa12108
习题4-9 UVa1591
习题4-10 UVa815
习题4-11 UVa1588
习题4-12 UVa11809
约瑟夫环c语言出现段错误,算法竞赛入门经典 紫书 第四章相关推荐
- 约瑟夫环c语言代码 指针,约瑟夫环C语言实现源代码(1)
前天笔试有个约瑟夫环的问题,怪不得人家没通知我面试,原来我的约瑟夫环做的确实有问题,昨天晚上又重新做了下,下面上源代码: /* file:osephu.cpp author:www.5dkx.com ...
- 约瑟夫环c语言代码顺序存储,顺序表实现约瑟夫环地问题,C语言.doc
顺序表实现约瑟夫环地问题,C语言 计算机科学与工程学院 PAGE PAGE 2 <算法与数据结构>试验报告 计算机科学与工程学院 <算法与数据结构>试验报告[一] 专业班级 1 ...
- 约瑟夫环c语言计蒜客链表,约瑟夫环的故事 - osc_3n35hvex的个人空间 - OSCHINA - 中文开源技术交流社区...
usingSystem;usingSystem.Collections.Generic;usingSystem.Linq;usingSystem.Text;usingSystem.Threading. ...
- 约瑟夫环c语言程序完整版,C语言:约瑟夫环问题(源代码)
本帖最后由 geige 于 2015-7-26 00:48 编辑 #include #include struct stu //构建一个新的数据类型 { int num; struct stu *ne ...
- 用C语言编写约瑟夫环程序,约瑟夫环C语言,请高手检查我的程序
/*TC2编译通过*//*测试了几组数据,没有发现问题*//*如果有问题,再M我*/#include typedef struct Cnode {int data; int password; str ...
- 约瑟夫环c语言单链表的解题思路,太透彻了:约瑟夫环的三种解法
[CSDN 编者按]极大概率出现在面试中的约瑟夫环问题来啦,本文三种方法描述解题思路,这样讲解绝对让面试官眼前一亮. 作者 | bigsai 责编 | 欧阳姝黎 前言 约瑟夫环问题是算法中相当经典的一 ...
- 约瑟夫环c语言循环指针,约瑟夫环(c语言)(双循环、单循环)
/*题目: 耶稣又15个门徒,其中有一个时出卖耶稣的叛徒,请用排除法找出这位门徒:15人围坐一圈,从第一个开始报号:1,2,3,1,2,3...凡是报到"3"的退出圈子,最后留在圈 ...
- c语言算法竞赛入门经典百度云,《算法竞赛入门经典》CH-2(C语言)
中国剩余定理,题目要求: 每组数据包含3个非负整数a,b,c,表示队尾人数(a<3, b<5, c<7),输出总人数的最小值(或报告无解).已知总人数不小于10,不超过100.输入到 ...
- c语言 如果 n 是素数,且 n+2 也是素数,则称为孪生素数.,算法竞赛入门经典: 第四章 函数与递归 4.3孪生素数...
/* 孪生素数: 如果n和n+2都是素数,则称他们是孪生素数.输入m,输出两个数均不超过m的最大孪生素数.5<=m<=10000.例如m=20时答案是17,19,m=1000时答案是881 ...
最新文章
- 用Leangoo看板工具做办公室采购流程管理
- CentOS6 英文系统安装ibus
- 网站建设优质内容页面如何打造?
- 微信小程序(11)--购物车
- flume的概述和运行机制
- EXCEL中与数据库打交道的好工具-JXL
- 用ASP.NET Core 2.0 建立规范的 REST API -- GET 和 POST
- 中对缺失数据的预处理_数据预处理也有套路的
- 样本分成训练集和测试集_吴恩达深度学习笔记(64)-开发集和测试集的大小分配...
- 在github上实现页面托管预览功能
- 2019年春季学期《软件工程》教学总结
- Evo使用过程问题汇总
- SAP 上线 新旧科目映射 辅助核算
- sptd.sys不是病毒?
- 【redis集群:2. 集群伸缩】
- 理论小知识:集合之scard
- 又拍云叶靖:基于Docker的云处理服务平台
- IOS 固定定位失效的分析与解决办法
- SQL查询学生表中每课大于85分的同学名称
- 云呐医疗行业条码固定资产管理系统
热门文章
- vue 项目中神策埋点
- 【LoadRunner】The above not found error(s) may be explained by header and body byte counts being 0 .
- 如何分辨on-policy和off-policy
- 【计算机网络】BitTorrent技术对网络的潜在危害
- 移动数据和软件更新系统及方法
- eureka java_Eureka服务注册入门,服务启动
- linux_端口占用扫描port scan(lsof/ss/netstat/Nmap)使用实例
- 食亨CEO王泰舟对话新华社:餐饮数字化经营时代已经到来
- smartdeblur有手机版吗_SmartDeblur下载-SmartDeblur官方最新版下载[照片处理]-下载之家...
- 从零开始构建矽璓工业物联操作系统:使用risc-v架构的hifive1 emulator