题目栏
sizof代码分析
下面代码的结果是:
#include <stdio.h>
int i;
int main()
{
i--;
if (i > sizeof(i))
{
printf(">\n");
}
else
{
printf("<\n");
}
return 0;
}
A.>
B.<
C.不输出
D.程序有问题C语言中,0为假,非0即为真。
全局变量,没有给初始值时,编译其会默认将其初始化为0。
i的初始值为0,i–结果-1,i为整形,sizeof(i)求i类型大小是4,按照此分析来看,结果应该选择B,但是sizeof的返回值类型实际为无符号整形,因此编译器会自动将左侧i自动转换为无符号整形的数据,-1对应的无符号整形是一个非常大的数字,超过4或者8,故实际应该选择A
有序数合并
#include <stdlib.h>
int change(const void* p1, const void* p2)
{
return *(int*)p1 - *(int*)p2;
}
int main()
{
int arr1[1000] = { 0 };
int arr2[1000] = { 0 };
int n, m;
scanf("%d %d", &n, &m);
int i = 0,j=0;
for (i = 0; i < n; i++)
{
scanf("%d", &arr1[i]);
}
for (i = n; i < (m+n); i++)
{
scanf("%d", &arr1[i]);
}
//冒泡排序
//for (i = 0; i < m + n-1; i++)
//{
// for (j = 0; j < m + n - i-1; j++)
// {
// if (arr1[j] > arr1[j+1])
// {
// int tmp = arr1[j];
// arr1[j] = arr1[j+1];
// arr1[j+1] = tmp;
// }
// }
//}
//qsort排序
qsort(arr1, m + n, sizeof(arr1[0]), change);
for(i = 0; i < m + n; i++)
{
printf("%d ", arr1[i]);
}
return 0;
}
BC105-矩阵相等判断
int main() {
int arr1[30][30] = { 0 };
int arr2[30][30] = { 0 };
printf("请输入两个整数n和m:");
int n, m;
scanf("%d %d", &n, &m);
int i = 0, j = 0;
for (i = 0; i < n; i++)
{
for (j = 0; j < m; j++)
{
scanf("%d", &arr1[i][j]);
}
}
for (i = 0; i < n; i++)
{
for (j = 0; j < m; j++)
{
scanf("%d", &arr2[i][j]);
}
}
//接下来判断两个矩阵的对应元素是否相等
int flag = 1;
for (i = 0; i < n; i++)
{
for (j = 0; j < m; j++)
{
if (arr1[i][j] != arr2[i][j])
{
flag = 0;
goto end;
}
}
}
end:
if (flag == 1)
printf("Yes\n");
else
printf("No\n");
return 0;
}
BC98-序列中删除指定数字
#include <stdio.h>
int main() {
int n=0,m=0;
int arr[50]={0};
scanf("%d",&n);
if(!(n>=1&&n<=50))
{
return 0;
}
int i=0;
for(i=0;i<n;i++)
{
scanf("%d",&arr[i]);
}
scanf("%d",&m);
for(i=0;i<n;i++)
{
if(arr[i]!=m)
{
printf("%d ",arr[i]);
}
}
return 0;
}
BC54-获得月份天数
int get_days(int n,int m)
{
if(m==4||m==6||m==9||m==11)
return 30;
else if(m==2)
{
if ((n % 100 == 0 && n % 400 == 0) || (n % 4 == 0 && n % 100 != 0))
return 29;//闰年返回29
else
return 28;
}
else
return 31;
}
int main() {
int year,month;
while(scanf("%d %d",&year,&month)==2)
{
int days=get_days(year,month);
printf("%d\n",days);
}
return 0;
}
BC37-网购
int main() {
float price=0;
int n,m,k;//日期,优惠卷
float total=0;
scanf("%f %d %d %d",&price,&n,&m,&k);
if(!(1<=price&&price<=100000)||(k!=1&&k!=0))
{
return 0;
}
if(n==11||n==12)
{
if(n!=m)
return 0;
}
if(n==11&&m==11)
{
total=price*0.7;
}
else {
total=price*0.8;
}
if(k==1)
{
if(total-50>0)
printf("%.2f\n",total-50);
else
printf("0.00\n");
}
else
printf("%.2f\n",total);
return 0;
}
字符串左旋
法一:三步法
#include <stdio.h>
#include <string.h>
void Spin(char arr[], int n)
{
//三步法
int i = 0;
int len = strlen(arr);//字符串长度
n %= len;//防止冗余
for (i = 0; i < n; i++)//左旋n个字符
{
//接下来是左旋一个字符的动作代码
//首先要将左旋的字符存到某个变量当中,然后将整个字符串向左位移
int j = 0;//将左旋的字符存到某个变量当中
int tmp = arr[0];
for (j = 0; j < len-1; j++)
{
arr[j] = arr[j + 1];
}
arr[len-1] = tmp;
}
}
int main()
{
char arr[20]="abcdef";
int n = 0;
scanf("%d", &n);
Spin(arr, n);
printf("%s\n", arr);
return 0;
}
法二:逆序法
void reverse(char* arr, int n)
{
char* left = arr;
char* right = arr + n - 1;
while (left < right)
{
char tmp = *left;
*left = *right;
*right = tmp;
left++;
right--;
}
}
void Spin(char arr[], int n)
{
int len = strlen(arr);
n %= len;//防止冗余
reverse(arr,n);//逆序要左旋的字符
reverse(arr+n,len-n);//逆序剩下的字符串
reverse(arr,len);//再逆序整个字符串
}
int main()
{
char arr[20]="abcdef";
int n = 0;
scanf("%d", &n);
Spin(arr, n);
printf("%s\n", arr);
return 0;
}
逆序法也可以很容易推得右旋
杨氏矩阵
有一个数字矩阵,矩阵的每行从左到右是递增的,矩阵从上到下是递增的,请编写程序在这样的矩阵中查找某个数字是否存在。
要求:时间复杂度小于O(N);
int find_num(int arr[][3], int r, int l, int n)
{
//设右上角的数为k,从右上角开始判断,若n>k,则该行抹去无需再查找,往下一行
//直到遇到k>n,此时行不再减少了,开始判断列,若n<k,此时列也无需再查找了,删去该列,直到遇见n>k
//当n=k时,循环停止
int x = 0;
int y = l-1;//假设没有
while (x<=r-1&&y>=0)
{
if (arr[x][y] < n)
{
x++;
}
else if (arr[x][y] > n)
{
y--;
}
else
return 1;
}
return 0;
}
int main()
{
int arr[3][3] = { 1,2,3,4,5,6,7,8,9 };
int sz_1 = sizeof(arr) / sizeof(arr[0]);
int sz_2 = sizeof(arr[0]) / sizeof(arr[0][0]);
int n = 0;
scanf("%d", &n);
if (find_num(arr, sz_1, sz_2, n))
printf("找到了\n");
else
printf("没找到\n");
return 0;
}
find_num中将参数arr[][3]设置为列大于3,会出现什么情况
例如我设置为4
arr[3][3]中一共有36字节数据存储,现在放到48字节二维数组中存储,原本1,2,3在第一行,现在第一行变为了1,2,3,4.
我们之前讲二维数组有讲过,二维数组在内存空间中所有行都在同一行上,所以,列其实不会有越界情况,只是访问到了"下一行"的元素。
malloc和struct(分配空间)
#define MAX_SIZE A+B
struct _Record_Struct
{
unsigned char Env_Alarm_ID : 4;
unsigned char Para1 : 2;
unsigned char state;
unsigned char avail : 1;
}*Env_Alarm_Record;
struct _Record_Struct *pointer = (struct _Record_Struct*)malloc(sizeof(struct _Record_Struct) * MAX_SIZE);
当A=2, B=3时,pointer分配( )个字节的空间。
代码分析:
我们知道位段申请空间是一字节或4字节申请(不够再申请),首先申请1字节的空间,Env_Alarm_ID : 4和Para1 : 2共占6bit,state所需要8bit空间,一开始申请的1字节空间显然不够用了,再申请1字节空间此时正好存放state,此时还差avail : 1,于是再申请1字节空间,avail : 1独占1字节空间。
至此,整个结构体一共申请了3字节的空间,结构体的大小为3字节
注意:在宏定义中是不会进行计算的
sizeof(struct _Record_Struct) * MAX_SIZE应变为
3x2+3,最终结果为9
所以此时malloc所申请的空间大小为9,pointer所分配的空间大小为9。
判断输出结果
下面代码的结果是( )
int main()
{
unsigned char puc[4];
struct tagPIM
{
unsigned char ucPim1;
unsigned char ucData0 : 1;
unsigned char ucData1 : 2;
unsigned char ucData2 : 3;
}*pstPimData;
pstPimData = (struct tagPIM*)puc;
memset(puc,0,4);
pstPimData->ucPim1 = 2;
pstPimData->ucData0 = 3;
pstPimData->ucData1 = 4;
pstPimData->ucData2 = 5;
printf("%02x %02x %02x %02x\n",puc[0], puc[1], puc[2], puc[3]);
return 0;
}
代码分析:
根据上道题的思路,我们可以易知在该代码中结构体所申请的空间大小为2字节。
pstPimData = (struct tagPIM*)puc;
因此pstPimData指针所能访问的最大地址长度为2字节
注意:
1.%x:打印16进制数
2.%02x:打印16进制数,打印两位,若不足两位,0补位
3.%2x:打印16进制数,打印两位,若不足两位,空格补位
模拟实现函数atoi
#include <stdio.h>
#include <assert.h>
#include <ctype.h>
#include <limits.h>
enum state
{
VALID,
INVALID
};
enum state s = INVALID;//一开始先设置非法状态,等转换成功后在设置为合法状态
int my_atoi(const char* str)
{
//1.空指针情况
assert(str);
//2.空字符串情况
if (*str == '\0')//但其实这里不严谨,到底是遇到\0还是遇到字符0,不能确定,所以我们需要创建一个枚举变量
{
return 0;
}
//3.遇到 -号问题
int flag = 1;
if (*str == '-')
{
flag = -1;
str++;
}
//接下来开始正式转换
long long ret = 0;//为了防止数据太大溢出,用更大类型的long long来接收
while (*str)
{
if (isdigit(*str))
{
ret = ret * 10 + flag * (*str - '0');
if (ret > INT_MAX || ret < INT_MIN)
{
return (int)ret;
}
}
else
{
return (int)ret;//遇到非数字字母的直接返回
}
str++;
}
//到了这一步说明转换成功,将状态改为合法
s = VALID;
return (int)ret;
}
int main()
{
char arr[20];
gets(arr);
int ret = my_atoi(arr);
if (s == INVALID)
printf("转换非法:%d\n", ret);
else
printf("转换合法:%d\n", ret);
return 0;
}
定义两个指针
int* a,b;
//大部分人看到这种定义,一定认为a,b的类型被定义为int*,实际上a类型被定义为int*,b为int
//它的实际代码效果应该这么看
int* a;
int b;
小知识:在头文件最好不要定义全局变量,因为可能会造成重定义
offsetof宏
offsetof
offsetof (type,member)
返回成员偏移量
参数:
1.类型
type应为结构或联合类型
2.成员:
类型的成员
返回值
类型为 size_t 的值,其偏移值为类型中的成员。
头文件:<stddef.h>
模拟实现宏offsetof:
#define OFFSETOF(type,name) (size_t)&(((type*)0)->name)//地址从0开始
struct S
{
char a;
int b;
int c;
};
int main()
{
printf("%d\n", OFFSETOF(struct S, a));
printf("%d\n", OFFSETOF(struct S, b));
printf("%d\n", OFFSETOF(struct S, c));
return 0;
}
交换奇偶位(宏)
#define Swap_Bit(x) ((x&0x55555555)<<1)+((x&0xaaaaaaaa)>>1)
int main()
{
int a = 5;
printf("%d\n", Swap_Bit(a));
}
轮转数组
超出时间限制版本
void rotate(int* nums, int numsSize, int k){
int i=0,j=0;
k%=numsSize;//k可能大于numsSize,所以要取余
for( i=0;i<k;i++)
{
int tmp1=nums[numsSize-1];
for(j=numsSize-2;j>=0;j--)
{
int tmp2=nums[j];
nums[j+1]=nums[j];
if(j-1>=0)
{
nums[j]=nums[j-1];
}
}
nums[0]=tmp1;
}
}
reverse版本
void reverse(int *p1,int *p2){
while(p1<p2)
{
int tmp=*p1;
*p1=*p2;
*p2=tmp;
p1++;
p2--;
}
}
void rotate(int* nums, int numsSize, int k){
k%=numsSize;//k可能大于numsSize,所以要取余
reverse(nums,nums+numsSize-1);
reverse(nums+k,nums+numsSize-1);
reverse(nums,nums+k-1);
}
memcpy版本
void rotate(int* nums, int numsSize, int k)
{
k%=numsSize;
int* tmp=(int*)malloc(sizeof(int)*numsSize);
memcpy(tmp+k,nums,sizeof(int)*(numsSize-k));
memcpy(tmp,nums+numsSize-k,sizeof(int)*k);
memcpy(nums,tmp,sizeof(int)*numsSize);//再memcpy回去
}
消失的数字
异或版本
int missingNumber(int* nums, int numsSize){
int i=0;
int n=0;
//如输入[3,0,1]
for(i=0;i<=numsSize;i++)
{
n^=i;
}
// n=0^0^1^2^3
for(i=0;i<numsSize;i++)
{
n^=nums[i];
}
//n^3^0^1=0^0^1^2^3^3^0^1
//因为异或的0^0=0,0^x=x,x^x=0
//最后异或的结果就是缺少的那个数字
return n;
}
求和法
int missingNumber(int* nums, int numsSize){
int sum=0;
int i=0;
for(i=0;i<=numsSize;i++)
{
sum+=i;
}
for(i=0;i<numsSize;i++)
{
sum-=nums[i];
}
return sum;
}
移除元素
法一:Erase
#include <assert.h>
int Find(int* p, int val, int* sz)
{
for (int i = 0; i < *sz; i++)
{
if (p[i] == val)
return i;
}
return -1;
}
void Erase(int* p, int val, int* sz)
{
assert(*sz > 0);
int i = 0;
int pos = Find(p, val, sz);
if (pos == -1)
return;
int num = pos;
for (i = 0; i < *sz - pos - 1; i++)
{
p[num] = p[num + 1];
num++;
}
(*sz)--;
}
int removeElement(int* nums, int numsSize, int val) {
int i = 0;
int* p = nums;
int sz = numsSize;
int count = 0;
for (i = 0; i < sz; )
{
i++;
if (nums[i-1] == val)
{
Erase(p, val, &sz);
i = 0;
count++;
}
}
nums = p;
/* for ( i=0; i < numsSize - count; i++)
{
printf("%d ", nums[i]);
}*/
return numsSize - count;
}
法二:
int removeElement(int* nums, int numsSize, int val) {
int dest = 0;
int src = 0;
while (src < numsSize)
{
if (nums[src] != val)
{
nums[dest++] =nums[src++];
}
else
src++;
}
return dest;
}
合并两个有序数组
示例一
输入:nums1 = [1,2,3,0,0,0], m = 3, nums2 = [2,5,6], n = 3
输出:[1,2,2,3,5,6]
解释:需要合并 [1,2,3] 和 [2,5,6] 。
合并结果是 [1,2,2,3,5,6] ,其中斜体加粗标注的为 nums1 中的元素。
#include <stdlib.h>
int fun(const void* p1,const void* p2)
{
return *(int*)p1-*(int*)p2;
}
void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n){
int i=0,j=0;
for(i=m;i<m+n;i++,j++)
{
nums1[i]=nums2[j];
}
qsort(nums1,m+n,sizeof(nums1[0]),fun);
}
法二:归并尾插
void merge(int* nums1, int nums1Size, int m, int* nums2, int nums2Size, int n){
int end1=m-1;
int end2=n-1;
int i=m+n-1;
while(end1>=0&&end2>=0)
{
if(nums1[end1]>nums2[end2])
{
nums1[i]=nums1[end1];
i--;
end1--;
}
else
{
nums1[i]=nums2[end2];
i--;
end2--;
}
}
while(end2>=0)
{
nums1[i]=nums2[end2];
i--;
end2--;
}
}
删除有序数组中的重复项
版本一:
void Erase(int* nums, int* sz, int val, int count)
{
int dest = 0;
int src = 0;
int num = count;
while (src < *sz)
{
if (nums[src] != val || count == 0)
{
nums[dest++] = nums[src++];
}
else
{
src++;
if (count > 0)
count--;
}
}
*sz = *sz - num;
}
int removeDuplicates(int* nums, int numsSize)
{
for (int i = 0; i < numsSize; i++)
{
int flag = 0, count = 0;
for (int j = i + 1; j < numsSize; j++)
{
if (nums[j] == nums[i])
{
flag = 1;
count++;
}
}
if (flag)
{
Erase(nums, &numsSize, nums[i], count);
}
}
return numsSize;
}
版本二:优化后
int removeDuplicates(int* nums, int numsSize)
{
int count=1, k=0;
for(int i=1; i<numsSize; i++)
{
if(nums[i]!=nums[k])
{
nums[++k] = nums[i];
count++;
}
}
return count;
}
罗马数字转整数
int GetNum2(char* str)
{
int ret=0;
if(*str=='I')
ret=1;
else if(*str=='V')
ret=5;
else if(*str=='X')
ret=10;
else if(*str=='L')
ret=50;
else if(*str=='C')
ret=100;
else if(*str=='D')
ret=500;
else if(*str=='M')
ret=1000;
return ret;
}
int Compare(char* str1,char* str2)
{
int a=GetNum2(str1),b=GetNum2(str2);
return a-b;
}
// int GetNum1(char c1,char c2)
// {
// if(c1=='V')
// return 4;
// else
// return 9;
// }
int romanToInt(char * s){
int sum=0;
while(*s)
{
if(Compare(s+1,s)>0)
{
sum+=Compare(s+1,s);
s+=2;
}
else
{
sum+=GetNum2(s);
s++;
}
}
return sum;
}
自守数
牛客链接:自守数
#include <stdio.h>
#include <math.h>
int Judge(int x)
{
int num = pow(x,2);
while(x)
{
int cmp1 = num%10;
int cmp2 = x%10;
if(cmp1!= cmp2)
return 0;
num/=10;
x/=10;
}
return 1;
}
int main() {
int n = 0;
int i = 0;
int count = 0;
scanf("%d", &n);
for (i = 0; i <= n; i++)
{
if(Judge(i))
count++;
}
printf("%d", count);
return 0;
}