本人0基础开始学编程,我能学会的,你也一定可以,学会多少写多少。
下载安装请从官网入手,社区版本即可,这里主要使用的软件是VS2019,图标如下。
?上一篇:从0开始学c语言-25-浮点型在内存中的存储+数据储存练习_阿秋的阿秋不是阿秋的博客-CSDN博客
目录
操作符练习
前置后置++练习
求两个数二进制中不同位的个数
方法1 —— 使用异或^后的p & (1 << a)求不同位
方法2 —— 使用异或^后的a = a&(a-1)求不同位
打印整数二进制的奇数位和偶数位
写成函数
统计二进制中1的个数
方法1——用该数据模2,检测其是否能够被2整除
方法2 ——?n & (1 << i)
方法3——采用相邻的两个数据进行按位与运算
交换两个变量(不创建临时变量)
杀仁诛心题
求Sn=a+aa+aaa+aaaa+aaaaa的前5项之和,其中a是一个数字
打印水仙花数
代码1
代码2
指针练习
数组和指针
喝汽水问题
代码1
代码2
代码3
利用指针写一个函数实现字符串逆序
调试作业
找问题、解释问题
?调整奇数偶数顺序
模拟字符串实现
实现strcpy
实现strlen
操作符练习
对应文章
从0开始学c语言-18-操作符详解_阿秋的阿秋不是阿秋的博客-CSDN博客
前置后置++练习
int main()
{
int a, b, c;
a = 5;
c = ++a;
b = ++c, c++, ++a, a++;
b += a++ + c;
printf("a = %d b = %d c = %d\n:", a, b, c);
return 0;
}
直接写过程,不引导。
a = 5;
c = ++a;
//c=6,a=6
b = ++c, c++, ++a, a++;
//从左向右执行,b的结果为最后一个表达式
//b=7,7,7,7
//后置++会先使用后++,所以c++和a++在等于b的时候并没有进行+1
//上面这个语句执行后的结果:b=7,c=8,a=8
b += a++ + c;
//b = b + a++ + c = 7+8+8 = 23
//a = 9
printf("a = %d b = %d c = %d\n:", a, b, c);
//a=9,b=23,c=8
return 0;
求两个数二进制中不同位的个数
编程实现:两个int(32位)整数m和n的二进制表达中,有多少个位(bit)不同?? 输入例子:1999 2299 输出例子 : 7
本质是求异或后的1有多少
方法1 —— 使用异或^后的p & (1 << a)求不同位
int main()
{
int i = 0;
int j = 0;
scanf("%d %d", &i, &j); //scanf需要指针类型的参数
int p = i ^ j;
//异或,不同为1
//算有几个1,就是两个数二进制中不同位的个数
int a = 0;
int count = 0;
for (a = 0; a < 32; a++)
{
if (p & (1 << a))
{
count++;
}
}
printf("%d\n", count);
return 0;
}
方法2 —— 使用异或^后的a = a&(a-1)求不同位
这种方法原理:
? ??举例子试试(tmp也就是a) ?? ??? ? tmp = 5 为真进入循环 ? ? ? ? ? ? ? ? ? ? ?tmp - 0101 - 5 ? ? ? ? ? ? ? ?? ?tmp-1 - 0100 - 4
? ?tmp & (tmp - 1) - 0100 - 5&4 - count++ ?? ??? ? ?? ??? ? 下一次循环 ? ? ? ? ? ? ? ? ? ? ? ? ? ?tmp - 0100 - 上一次tmp & (tmp - 1)的结果? ? ? ? ? ? ? ? ? ? ? ? ? tmp-1 - 0011 - 3 ?? ??? ? tmp & (tmp - 1) - 0000 -?count++ ?? ??? ?tmp=0为假,跳出循环
此时count为2,而 5当中 确实是有2个1。
int calc_diff_bit(int m, int n)
{
int tmp = m ^ n;
int count = 0;
while (tmp)
{
tmp = tmp & (tmp - 1);
count++;
}
return count;
}
int main()
{
int m, n;
while (scanf("%d %d", &m, &n) == 2)
{
printf("%d\n", calc_diff_bit(m, n));
}
return 0;
}
打印整数二进制的奇数位和偶数位
获取一个整数二进制序列中所有的偶数位和奇数位,分别打印出二进制序列
思路:二进制中只有0和1 ,那就是识别是0还是1。至于奇数和偶数位,不过是加一个循环(奇数位,偶数位)来识别是0还是1罢了。
int main()
{
int a = 0;
scanf("%d", &a);
int i = 0;
int count1 = 0; //验证一下是否走了16位,其实没必要
int count2 = 0;
//从低位置开始打印,高位置打印的话就改一下初始值和调整部分就行
//打印奇数位
for (i = 0; i < 32; i += 2)
{
if (a & (1 << i))
{
printf("%d ", 1);
}
else
{
printf("%d ", 0);
}
count1++;
}
printf("\n");
printf("%d\n",count1);
//打印偶数位
for (i = 1; i < 32; i += 2)
{
if (a & (1 << i))
{
printf("%d ", 1);
}
else
{
printf("%d ", 0);
}
count2++;
}
printf("\n");
printf("%d\n", count2);
return 0;
}
写成函数
void Printbit(int num)
{
for (int i = 31; i >= 1; i -= 2)
{
printf("%d ", (num >> i) & 1);
}
printf("\n");
for (int i = 30; i >= 0; i -= 2)
{
printf("%d ", (num >> i) & 1);
}
printf("\n");
}
统计二进制中1的个数
方法1——用该数据模2,检测其是否能够被2整除
2.可以整除:则该数据对应二进制比特位的最低位一定是0,否则是1,如果是1给计数加1 3. 如果n不等于0时,继续1
int count_one_bit(int n)
{
int count = 0;
while (n)
{
if (n % 2 == 1)
count++;
n = n / 2;
}
return count;
}
上述方法缺陷:进行了大量的取模以及除法运算,取模和除法运算的效率本来就比较低。
方法2 ——?n & (1 << i)
int count_one_bit(unsigned int n)
{
int count = 0;
int i = 0;
for (i = 0; i < 32; i++)
{
if ((n >> i) & 1)
count++;
//或者
//if( n & (1 << i))
//count++;
}
return count;
}
用位操作代替取模和除法运算,效率稍微比较高 缺陷:不论是什么数据,循环都要执行32次
方法3——采用相邻的两个数据进行按位与运算
此种方式,数据的二进制比特位中有几个1,循环就循环几次,而且中间采用了位运算,处理起来比较高效
int count_one_bit(int n)
{
int count = 0;
while (n)
{
n = n & (n - 1);
count++;
}
return count;
}
交换两个变量(不创建临时变量)
本质是对 异或^操作符 的运用。
异或的结论:
1· 任何两个相同的数 异或 为0 2· 0和任何数字 异或 是它本身
int main()
{
int a = 10;
int b = 20;
printf("交换前:a = %d b = %d\n", a, b);
a = a ^ b;
b = a ^ b;
a = a ^ b;
printf("交换后:a = %d b = %d\n", a, b);
return 0;
}
杀仁诛心题
int i;
int main()
{
i--;
if (i > sizeof(i))
{
printf(">\n");
}
else
{
printf("<\n");
}
return 0;
}
C语言中,0为假,非0即为真。 全局变量,没有给初始值时,编译其会默认将其初始化为0。 i的初始值为0,i--结果 - 1,i为整形,sizeof(i)求i类型大小是4, 按照此分析来看,结果应该是小于<,但是sizeof的返回值类型实际为无符号整形,因此编译器会自动将左侧 i 自动转换为无符号整形的数据,- 1对应的无符号整形是一个非常大的数字,超过4或者8,故实际应该为大于。
求Sn=a+aa+aaa+aaaa+aaaaa的前5项之和,其中a是一个数字
观察aa=a*10+a,aaa=aa*10+a,以此类推
原理就这,可写了
int main()
{
int a = 0;
int n = 0;
int i = 0;
int sum = 0;
int tmp = 0;
scanf("%d %d", &a, &n);
for (i = 0; i < n; i++)
{
tmp = tmp * 10 + a;
sum += tmp;
}
printf("%d\n", sum);
return 0;
}
打印水仙花数
求出0~100000之间的所有“水仙花数”并输出。 “水仙花数”是指一个n位数,其各位数字的n次方之和确好等于该数本身, 如 : 153=1 ^ 3+5 ^ 3+3 ^ 3,则153是一个“水仙花数”
思路:
1 5 3分别是153、15、3 除10 的余数,所以可以考虑函数递归。3次方就是3位数,需要判断出是几位数,然后专门用一个函数或者变量用来求一个数的n次方,最后相加验证即可。
代码1
//输出i的j次方
int output(int i,int j)
{
int put = 1;
int time = 0;
for (time = 0; time < j; time++)
{
put *= i;
}
return put;
}
//算 几次方 几位数
int count(int i)
{
int count = 0;
while (i > 9)
{
i /= 10;
count++;
}
return count+1;
}
//进行水仙花数字的运算
int test(int i,int sum,int a)
{
if (i > 9)
{
sum += output(i % 10,a);
return test(i / 10, sum,a);
//函数递归
}
else
{
sum += output(i % 10, a);
return sum;
//求和
}
}
int main()
{
int i = 0;
for (i = 0; i < 1000000; i++)
{
int a = count(i); //几位数,几次方
int sum = 0; //次方和
//这两个值必须放在循环里
//因为每个数的位数不同
//且每次调用test函数前
//sum必须=0,否则会受到上次循环的sum影响
//等于本身则输出
if (i == test(i, sum,a))
{
printf("%d\n", i);
}
}
return 0;
}
代码2
int main()
{
int i = 0;
for (i = 0; i <= 999999; i++)
{
int count = 1;
int tmp = i;
int sum = 0;
//判断i是否为水仙花数
//1. 求判断数字的位数
while (tmp / 10)
{
count++;
tmp = tmp / 10;
}
//2. 计算每一位的次方和
tmp = i;
while (tmp)
{
//double pow( double x, double y );
//pow计算次方和,返回类型double
//所以强制类型转换
sum += (int)pow(tmp % 10, count);
tmp = tmp / 10;
}
//3. 判断
if (sum == i)
printf("%d\n", i);
}
return 0;
}
指针练习
从0开始学c语言-21-指针和数组、二级指针、指针数组_阿秋的阿秋不是阿秋的博客-CSDN博客
从0开始学c语言-20-指针与地址、指针类型、野指针、指针运算_阿秋的阿秋不是阿秋的博客-CSDN博客
数组和指针
int main()
{
unsigned long pulArray[] = { 6,7,8,9,10 };
unsigned long* pulPtr;
pulPtr = pulArray;
*(pulPtr + 3) += 3;
printf("%d %d\n", *pulPtr, *(pulPtr + 3));
return 0;
}
输出:6,12
牢记数组名是首元素地址就能做出来,搞清楚指针指在了哪里。
喝汽水问题
喝汽水,1瓶汽水1元,2个空瓶可以换一瓶汽水,给20元,可以多少汽水(编程实现)。
思路:?
1.20元首先可以喝20瓶,此时手中有20个空瓶子 2. 两个空瓶子可以喝一瓶,喝完之后,空瓶子剩余:empty/2(两个空瓶子换的喝完后产生的瓶子) + empty%2(手里剩下的空瓶) 3. 如果瓶子个数超过1个,可以继续换(这就是循环条件)
代码1
int num(int money)
{
//花钱买到的汽水瓶数
int num_bot = money;
//空瓶数
int emp_bot = num_bot;
//总共瓶
int sum_bot = emp_bot;
while (emp_bot>1)
{
//加上 新换瓶数
sum_bot += emp_bot/2;
//看手里剩多少
emp_bot = emp_bot / 2 + emp_bot % 2;
}
return sum_bot;
}
int main()
{
int money = 0;
printf("你有多少钱?请输入:>");
scanf("%d", &money);
printf("%d\n",num(money));
return 0;
}
代码2
int main()
{
int money = 0;
int total = 0;
int empty = 0;
scanf("%d", &money);
total = money;
empty = money;
while (empty > 1)
{
total += empty / 2;
empty = empty / 2 + empty % 2;
}
printf("%d\n", total);
return 0;
}
按照上述喝水和用瓶子换的规则的话,多次运行,其实就是个等差数列:money*2-1
代码3
记得考虑钱<=0的情况
int main()
{
int money = 0;
int total = 0;
int empty = 0;
scanf("%d", &money);
if (money <= 0)
{
total = 0;
}
else
{
total = money * 2 - 1;
}
printf("total = %d\n", total);
return 0;
}
利用指针写一个函数实现字符串逆序
void Reverse(char* str)
{
char* left = str;
char* right = str + strlen(str) - 1;
while (left < right)
{
char temp = *left;
*left = *right;
*right = temp;
++left;
--right;
}
}
调试作业
从0开始学c语言-23-如何写出好(易于调试)的代码、模拟实现库函数:strcpy、strlen 、编程常见错误_阿秋的阿秋不是阿秋的博客-CSDN博客
找问题、解释问题
int main()
{
int i = 0;
int arr[] = {1,2,3,4,5,6,7,8,9,10};
for(i=0; i<=12; i++)
{
arr[i] = 0;
printf("hello bit\n");
}
return 0;
}
以上代码有两个问题:1.数组访问越界 ? 2. 死循环
访问越界不再解释,下标超出了。
每次访问arr数组i号位置时,都会将该位置内容设置为0,当访问到arr[12]时,也会将该位置内容设置为0,而位置恰好为i的位置,即a[12]恰巧将i设置为0,因此造成死循环。
?调整奇数偶数顺序
调整数组使奇数全部都位于偶数前面。
输入一个整数数组,实现一个函数,来调整该数组中数字的顺序使得数组中所有的奇数位于数组的前半部分,所有偶数位于数组的后半部分。
思路:对半劈开,各自找到奇数或者偶数就交换。
void swap_arr(int arr[], int sz)
{
int left = 0;
int right = sz - 1;
int tmp = 0;
while (left < right)
{
// 从前往后,找到一个偶数,找到后停止
while ((left < right) && (arr[left] % 2 == 1))
{
left++;
}
// 从后往前找,找一个奇数,找到后停止
while ((left < right) && (arr[right] % 2 == 0))
{
right--;
}
// 如果偶数和奇数都找到,交换这两个数据的位置
// 然后继续找,直到两个指针相遇
if (left < right)
{
tmp = arr[left];
arr[left] = arr[right];
arr[right] = tmp;
}
}
}
模拟字符串实现
从0开始学c语言-23-如何写出好(易于调试)的代码、模拟实现库函数:strcpy、strlen 、编程常见错误_阿秋的阿秋不是阿秋的博客-CSDN博客
实现strcpy
char* my_strcpy(char* dst, const char* src)
{
char* cp = dst;
while (*cp++ = *src++);
return(dst);
}
实现strlen
int my_strlen(const char* str)
{
const char* eos = str;
while (*eos++);
return(eos - str - 1);
}
下一篇:从0开始学c语言-27-字符指针,指针数组和数组指针_阿秋的阿秋不是阿秋的博客-CSDN博客
|