模拟实现strcpy
库函数strcpy的功能
#include <stdio.h>
#include <string.h>
int main()
{
char arr1[20] = { 0 };
char arr2[] = "hello hit";
strcpy(arr1, arr2);
printf("%s", arr1);
return 0;
}
逻辑:两个指针,在遍历的同时,目标字符串用源字符串对应值进行赋值
#include <stdio.h>
void my_strcpy(char* dest, char* src)
{
while (*src != '\0')
{
*dest = *src;
dest++;
src++;
}
*dest = *src;
}
int main()
{
char arr1[20] = { 0 };
char arr2[] = "hello hit";
my_strcpy(arr1, arr2);
printf("%s", arr1);
return 0;
}
优化:简洁版本
void my_strcpy(char* dest, char* src)
{
while (*dest++ = *src++);
}
提高健壮性:1.防止源字符串被修改——const常属性
2.判断传入的是否是空指针——assert断言
完整版:
#include <stdio.h>
#include <assert.h>
char* my_strcpy(char* dest, const char* src)
{
char* ret = dest;
assert(src != NULL);
assert(dest != NULL);
while (*dest++ = *src++);
return ret;
}
int main()
{
char arr1[20] = { 0 };
char arr2[] = "hello hit";
printf("%s\n", my_strcpy(arr1, arr2));
return 0;
}
模拟实现strlen
库函数strlen的功能
#include <stdio.h>
#include <string.h>
int main()
{
char arr[] = "hello hit";
int len = strlen(arr);
printf("%d", len);
return 0;
}
逻辑:从数组指针开始,循环遍历字符串,用临时变量计算长度
提高健壮性:1.防止源字符串被修改——const常属性
2.判断传入的是否是空指针——assert断言
#include <stdio.h>
#include <assert.h>
int my_strlen(const char* str)
{
int count = 0;
assert(str);
while (*str != '\0')
{
count++;
str++;
}
return count;
}
int main()
{
char arr[] = "hello hit";
int len = my_strlen(arr);
printf("%d", len);
return 0;
}
描述
KiKi想知道已经给出的三条边a,b,c能否构成三角形,如果能构成三角形,判断三角形的类型(等边三角形、等腰三角形或普通三角形)。
输入描述:
题目有多组输入数据,每一行输入三个a,b,c(0<a,b,c<1000),作为三角形的三个边,用空格分隔。
输出描述:
针对每组输入数据,输出占一行,如果能构成三角形,等边三角形则输出“Equilateral triangle!”,等腰三角形则输出“Isosceles triangle!”,其余的三角形则输出“Ordinary triangle!”,反之输出“Not a triangle!”。
#include <stdio.h>
int main()
{
int a = 0;
int b = 0;
int c = 0;
while (scanf("%d %d %d", &a, &b, &c) == 3)
{
if ((a + b > c) && (b + c > a) && (a + c > b))
{
if ((a == b) && (b == c) && (a == c))
{
printf("Equilateral triangle!\n");
}
else if ((a == b) || (a == c) || (b == c))
{
printf("Isosceles triangle!\n");
}
else
{
printf("Ordinary triangle!\n");
}
}
else
{
printf("Not a triangle!\n");
}
}
return 0;
}
写一个函数打印数组内容(使用指针而不是数组下标)
#include <stdio.h>
void print(int* p, int sz)
{
int i = 0;
for (i = 0; i < sz; i++)
{
printf("%d ", *(p + i));
}
}
int main()
{
int arr[] = { 1,2,3,4,5,6 };
int sz = sizeof(arr) / sizeof(arr[0]);
print(arr, sz);
return 0;
}
字符串逆序
写一个函数,可以逆序一个字符串的内容。
核心思想:不适用scanf(如果输入的字符串中有空格,无法接收)
改用gets来读取buffer缓冲区中的字符串
逻辑:用两侧left和right两个指针,相向运动交换字符串内容
#include <stdio.h>
#include <string.h>
int main()
{
char arr[10001] = { 0 };
gets(arr);
int left = 0;
int right = strlen(arr) - 1;
while (left < right)
{
char tmp = arr[left];
arr[left] = arr[right];
arr[right] = tmp;
left++;
right--;
}
printf("%s\n", arr);
return 0;
}
计算求和
求Sn=a+aa+aaa+aaaa+aaaaa的前5项之和,其中a是一个数字,
例如:2+22+222+2222+22222
更通用的版本:用来求a的前n项之和
#include <stdio.h>
int main()
{
int a = 0;
int n = 0;
scanf("%d %d", &a, &n);
int i = 0;
int sum = 0;
int k = 0;
for (i = 0; i < n; i++)
{
k = k * 10 + a;
sum += k;
}
printf("%d", sum);
return 0;
}
打印水仙花数
求出0~100000之间的所有“水仙花数”并输出。
“水仙花数”是指一个n位数,其各位数字的n次方之和确好等于该数本身,如:153=1^3+5^3+3^3,则153是一个“水仙花数”。
核心思想:1.判断i是n位数
2.得到每一位数,求n次方之和,并比较
#include <stdio.h>
#include <math.h>
int main()
{
int i = 0;
for (i = 0; i <= 100000; i++)
{
int sum = 0;
int n = 1;//默认任何数至少是一位数
int tmp = i;
while (tmp / 10)
{
n++;
tmp /= 10;
}
tmp = i;
while (tmp)
{
sum += pow((tmp % 10), n);
tmp /= 10;
}
if (sum == i)
printf("%d ", i);
}
return 0;
}
函数版本:
#include <stdio.h>
#include <math.h>
int is_narcissistic_number(int i)
{
int sum = 0;
int n = 1;//默认任何数至少是一位数
int tmp = i;
while (tmp / 10)
{
n++;
tmp /= 10;
}
tmp = i;
while (tmp)
{
sum += pow((tmp % 10), n);
tmp /= 10;
}
if (sum == i)
return 1;
return 0;
}
int main()
{
int i = 0;
for (i = 0; i <= 100000; i++)
{
if (is_narcissistic_number(i))
printf("%d ", i);
}
return 0;
}
打印菱形
用C语言在屏幕上输出以下图案:
核心思想:分为两部分。上半部分和下半部分的逻辑不同,用条件判断打印的是*还是空格
#include <stdio.h>
int main()
{
int line = 0;
scanf("%d", &line);
//上半部分
int i = 0;
for (i = 0; i < line; i++)
{
int j = 0;
for (j = 0; j < line - i - 1; j++)
{
printf(" ");
}
for (j = 0; j < 2 * i + 1; j++)
{
printf("*");
}
printf("\n");
}
//下半部分
for (i = 0; i < line - 1; i++)
{
int j = 0;
for (j = 0; j <= i; j++)
{
printf(" ");
}
for (j = 0; j < 2 * (line - i - 1) - 1; j++)
{
printf("*");
}
printf("\n");
}
return 0;
}
喝汽水问题
喝汽水,1瓶汽水1元,2个空瓶可以换一瓶汽水,给20元,可以多少汽水(编程实现)。
核心思想:用空瓶数进行迭代计算
#include <stdio.h>
int main()
{
int money = 0;
scanf("%d", &money);
int total = money;
int empty = money;
if (money < 0)
total = 0;
else
{
while (empty >= 2)
{
total += empty / 2;
empty = empty / 2 + empty % 2;
}
}
printf("%d ", total);
return 0;
}
改进:找规律 total = 2 * money - 1
#include <stdio.h>
int main()
{
int money = 0;
scanf("%d", &money);
int total = money;
if (money < 0)
total = 0;
else
{
total = 2 * money - 1;
}
printf("%d ", total);
return 0;
}
求最小公倍数
正整数A和正整数B 的最小公倍数是指 能被A和B整除的最小的正整数值,设计一个算法,求输入A和B的最小公倍数。
https://www.nowcoder.com/questionTerminal/22948c2cad484e0291350abad86136c3
逻辑一:取a和b中的较大值,向上一次递增直到能够同时整除a和b
#include <stdio.h>
int main()
{
int a = 0;
int b = 0;
scanf("%d %d", &a, &b);
int m = (a > b ? a : b);
while (1)
{
if (m % a == 0 && m % b == 0)
break;
m++;
}
printf("%d", m);
return 0;
}
效率较低,时间开销大
逻辑二:取a和b中的较大值,乘以一个依次增大的i,直到结果与另一个数乘以j相等
#include <stdio.h>
int main()
{
int a = 0;
int b = 0;
scanf("%d %d", &a, &b);
int i = 1;
while ((a * i) % b)
{
i++;
}
printf("%d", i * a);
return 0;
}
逆置字符串
将一句话的单词进行倒置,标点不倒置。比如 "I like beijing.",经过处理后变为:"beijing. like I"。
字符串长度不超过100。
https://www.nowcoder.com/questionTerminal/8869d99cf1264e60a6d9eff4295e5bab
两步反转法:先将整个字符串倒置,再分别将每个单词倒置
#include <stdio.h>
#include <assert.h>
void reverse(char* left, char* right)
{
assert(left && right);
while (left < right)
{
char tmp = *left;
*left = *right;
*right = tmp;
left++;
right--;
}
}
int main()
{
char arr[101] = { 0 };
gets(arr);
int len = strlen(arr);
//逆序整个字符串
reverse(arr, arr + len - 1);
//逆序每个单词
char* start = arr;
while (*start)
{
char* end = start;
while (*end != ' ' && *end != '\0')
{
end++;
}
reverse(start, end - 1);
if (*end != '\0')
{
end++;
}
start = end;
}
printf("%s", arr);
return 0;
}