C语言编程常见技巧(问题???)
Posted banloong
tags:
篇首语:本文由小常识网(cha138.com)小编为大家整理,主要介绍了C语言编程常见技巧(问题???)相关的知识,希望对你有一定的参考价值。
本文章根据《算法竞赛入门经典(第二版)》一书整理。。。
第一章 程序设计入门
- printf 语句控制输出小数位数或总长度
printf("%.3f ",8.0/5.0) //小数位数为3。
printf("%.*f ",3,8.0/5.0) //用3来代替* ,用来动态指定小数位数
printf("%3d",xxx) //指定输出宽度为3
printf("%-3d",xxx) //左对齐,邮编填补空格
printf("%03d",xxx) //指定宽度,并用0填补左边空缺
- 求多位数各个位上的数
while(x > 0){
y = x % 10; //y分别为个位、十位、百位等
x /= 10;
}
- 交换变量a,b的值
方法一:借用第三方变量
int a,b,temp;
temp = a;
a = b;
b = temp;
方法二:不借用第三方变量
1)使用加减法(和不变)//限制:只有定义了加减法的数据类型才可以使用。
int a,b;
a = a +b;
b = a - b;
a = a - b;
2)使用异或运算(^)
a = a ^ b;
b = a ^ b;
a = a ^ b;
原理: x^x == 0; x^0 == x;
首先用a保存了a^b的值,再用b = a ^ b = (a^b)^b=a^b^b=a^(b^b)=a^0=a,这样实现了b = a;
接着又用a = a^b = (a^b)^b(第一个b还是原来的b,而第二个b已经是a的值)= (a^b)^a = a^a^b = 0^b = b,这样实现交换。
- C语言中,0为假,其余皆为真。
第二章 循环结构程序设计
- 四舍五入
floor(x + 0.5)
- continue和break
continue进行下一次循环。break则是跳出当前循环体。
- 整数溢出
int型一般为32位整数,取值范围为-2^31~2^31-1,即-2147483648~2147483647
- while (先判断后计算)
- do while (先计算一次,后判断)
- scanf判断输入结束:
windows:输入完毕后,先按Enter键,再按Ctrl+Z键,最后在按Enter键。之所以这么复杂是因为scanf语句的输入格式中空格,TAB,回车符都不意味着输入结束。
Linux:输入完毕后按下Ctrl+D即可。
while(scanf("%s",&a) == 1 ) //保证输入不为空(有没有==1,意义不大吧。。。。)
while(scanf("%d",&a) == 1 && n) //保证输入不为空且不是0。
- 文件读取
输入输出重定向:详见https://blog.csdn.net/xavierdarkness/article/details/80638641;
freopen("input.txt","r",stdin);
freopen("output.txt","w",stdout);
文件读取(不使用重定向)(较灵活)
FILE *fin,*fout;
fin = fopen("data.in","rb");
fout = fopen("data.out","wb");
不同:freopen不是指针类型的,写起来简单,自然,但不可同时读写文件和输入输出。
fopen则需使用文件指针,且在使用fopen时,应使用配套的fsacnf和fprintf进行输入输出,普通的scanf和printf依然能在命令行界面操作。
如果在fopen下想使用标准输入输出,只需赋值“fin = stdin;fout = stdout”即可,此时不在调用fopen和fclose。
- 浮点数溢出
在除法中(1/n^2)此时,需注意溢出,此时要使用连除(1/n/n)而不是直接除以其平方和(1/(n*n))。
第三章 数组和字符串
- 数组声明:
数组在程序中的声明位置很重要:参考:https://zhidao.baidu.com/question/397529275.html。
全局变量(在main函数外声明)在静态存储区分配内存,局部变量(main函数内声明)是在栈上分配内存空间的,
VC堆栈默认是1M,int a[1000000]的大小是4*1000000,将近4M,远远大于1M,编译连接的时候不会有问题,但运行是堆栈溢出,程序异常终止。
- 内存复制:#include <string.h>
void *memcpy(void *dest, const void *src, size_t n);
常用方法:把数组a全部复制到数组b中:memcpy(b,asixeof(a));
- 数组置零:#include <string.h>
void *memset(void *s, int ch, size_t n);
函数说明:将s中当前位置后面的n个字节 (typedef unsigned int size_t )用 ch 替换并返回 s。
常用方法:将数组a清零:memset(a,0,sizeof(a));
- 开关问题
一般使用j % i 来判断几倍关系,用 !来取反模拟实现开启、关闭。
- 蛇形填数
eg:10 11 12 1
9 16 13 2
8 15 14 3
7 6 5 4
类似上述问题使用数组,模拟笔撞墙(是否越界、是否填过)的问题。
检验是否填过以及碰壁:(碰壁条件 && !a[x][y])而不是判断(a[x][y] == 0)。
- scanf注意事项与gets (#include <stdio.h>)区别: 参考:https://zhidao.baidu.com/question/290403568.html.
1、 gets功能为读入一行,并将换行符(
)转换为字符串结束符( )。
2、 scanf("%s",s);读入时,遇到空白字符,包括空格,制表符,换行符时均会停止输入。
对于字符串数组scanf("%s",s)和scanf("%s",&s)是没有区别的,s代表数组首地址,&s也是一样。
对于字符(int型或其他)来说参考以下:
scanf
函数要求第二个参数是一个指针类型的变量
scanf
(
"%d"
,a)----->表示a的定义为:
int
* a;
scanf
(
"%d"
,&a)---->表示a的定义为:
int
a;
3、终止条件不同。
gets只有遇到
时才会结束输入,而scanf遇到空格或制表符时,也会结束输入。
比如输入"test string
"。
用gets得到的字符串为"test string", 二用scanf得到的是"test"。
4、终止后,对终止字符处理不同。
比如输入为"test
abcd"。
执行gets后,
不会留在缓冲区中,即这时调用getchar得到的字符是‘a‘。
执行scanf后,
会留在缓冲区,这时调用getchar得到的字符是‘
‘。
- sprintf (#include <stdio.h>)参考:https://baike.baidu.com/item/sprintf/9703430?fr=aladdin。应保证写入的字符串有足够的空间。
int sprintf( char *buffer, const char *format, [ argument] … );
返回值:返回写入buffer 的字符数( 计算在内,