tips
1. scanf当是读取整数%d的时候,这时候如果它读取到\n,它就会停止读取。并且碰到空格的时候也会跳过。
2. getchar不需要传入参数,读取失败的时候会返回EOF。那getchar或者scanf到底是怎么从键盘上读取我输入的字符呢?在getchar/scanf与键盘中间有输入缓冲区,从键盘上输入的字符会先到输入缓冲区,然后它们从输入缓冲区中读取字符。按下enter,就是往输入缓冲区里面放入了一个换行符(\n)。
3. scanf与printf针对各种类型,而getchar与putchar只针对字符。
4. 当程序执行时一旦出现getchar,如果此时输入缓冲区里面没有东西,就会弹出一个界面,让你去输入字符(它读取不到就会返回EOF)。如果此时输入缓冲区里面有东西,那么getchar对抓去它干它自己的活。
如上,这样子是因为\n的ACSII码是10
5. 如下面这个代码可以打印数字字符
注意:getchar()读取的是字符,那么既然是字符肯定是一个一个的,又不是字符串。但当我一下子输入一串东西(此时输入缓冲区就已经有这么一串东西了,并且最后一个是\n),那然后当getchar如果在循环里面的话,它是一个一个字符这么读取并返回ACSII码的,并不是一步到位的。
6. 使用 gets() 时,系统会将最后“敲”的换行符从缓冲区中取出来,然后丢弃,所以缓冲区中不会遗留换行符。这就意味着,如果前面使用过 gets(),而后面又要从键盘给字符变量赋值的话就不需要吸收回车清空缓冲区了,因为缓冲区的回车已经被 gets() 取出来扔掉了。
题目1
代码
#include <stdio.h>
int main()
{
int n = 0;
int m = 0;
scanf("%d %d", &n, &m);
int arr[100][100] = { 0 };
//
int i = 0;
int j = 0;
for (i = 0; i < n; i++)
{
for (j = 0; j < m; j++)
{
scanf("%d", &arr[i][j]);
}
}
//
int k = 0;
int num1 = 0;
int num2 = 0;
char ret;
//
scanf("%d",&k);
for (i = 0; i < k; i++)
{
getchar();
scanf("%c %d %d", &ret, &num1, &num2);
if (ret == 'r')
{
for (j = 0; j < m; j++)
{
int tmp = arr[num1 - 1][j];
arr[num1 - 1][j] = arr[num2 - 1][j];
arr[num2 - 1][j] = tmp;
}
}
else if (ret == 'c')
{
for (j = 0; j < n; j++)
{
int tmp = arr[j][num1 - 1];
arr[j][num1 - 1] = arr[j][num2 - 1];
arr[j][num2 - 1] = tmp;
}
}
}
for (i = 0; i < n; i++)
{
for (j = 0; j < m; j++)
{
printf("%d ", arr[i][j]);
}
printf("\n");
}
return 0;
}
经验总结
1. scanf当是读取整数%d的时候,这时候如果它读取到\n,它就会停止读取。并且碰到空格的时候也会跳过。
2. 但是如果scanf读取字符%c的时候,这个时候需要特别注意了,输入缓冲区里面的如果没有被清除掉的话,那么它读取的就是\n,(按下enter键,相当于往输入缓冲区里面放一个\n)
题目2
代码
#include <stdio.h>
int main()
{
long long n = 0;
long long m = 0;
scanf("%lld %lld", &n, &m);
//
int num1 = n > m ? n : m;
int num2 = n < m ? n : m;
//
while (num1 % num2 != 0)
{
int ret = num1 % num2;
num1 = num2;
num2 = ret;
}
int Div = num2;
//
printf("%lld\n", n * m / num2+num2);
return 0;
}
经验总结
1. 求最大公约数用辗转相除法。
2. 两个数的最大公约数与最小公倍数的乘积等于这两个数的乘积。
题目3
代码
#include <stdio.h>
#include <math.h>
int main()
{
int i = 0;
int num = 0;
int sum = 0;
scanf("%d", &num);
//
while (num)
{
int ret = num % 10;
num /= 10;
if (ret % 2 == 0)
{
sum += pow(10, i) * 0;
}
else
{
sum += pow(10, i) * 1;
}
i++;
}
printf("%d\n", sum);
return 0;
}
经验总结
1. 对于一个数值,如果想要得到它n进制形式的每一位数,只需要把这个数值不断%n,然后再/n去更新这个数值,如此循环往复。
2. 如果你要得到一个数值二进制形式下的每一位数,就可以把这个数值不断%2,然后再/2去更新这个数值,如此循环往复。但这样子的话是有缺陷的,比如对于负数而言。这时候对于负数而言的话,为了避免缺陷,需要把负数类型强制转化为unsigned int,这样子的话在数值上其实每个负数变成了很大很大很大的一个正数(我再次强调一下,在内存当中存的是二进制的补码,对正数而言,原码与补码都是一样的),虽然如此,但是那个二进制序列的形式仍然没有发生一丁点变化,这就没有背离我的初衷。
题目4
代码
#include <stdio.h>
#include <string.h>
int main()
{
char arr[8000] = { 0 };
gets(arr);
int sz = strlen(arr);
//
int i = 0;
long long C = 0;
long long CH = 0;
long long CHN = 0;
for (i = 0; i < sz; i++)
{
if (arr[i] == 'C')
{
C++;
}
else if (arr[i] == 'H')
{
CH += C;
}
else if (arr[i] == 'N')
{
CHN += CH;
}
}
printf("%lld\n",CHN);
return 0;
}
经验总结
1. 像我上面代码里的这种方法是比较有效率的,我只要从头到尾遍历一次数组就可以。
2. 以后有关数组的子序列问题其实这道题目也许可以作为参考。给我们提供了一种思路。