刷题日记

157 阅读8分钟

本文已参与「新人创作礼」活动,一起开启掘金创作之路

一.选择题 1.

二维数组X按行顺序存储,其中每个元素占1个存储单元。若 X[4][4] 的存储地址为 Oxf8b82140 , X[9][9] 的存储地址为 Oxf8b8221c ,则 X[7][7] 的存储地址为( ) A: Oxf8b821c4 B: Oxf8b821a6 C: Oxf8b82198 D: Oxf8b821c0

答案选A

假设每行有n个元素:那x[9][9]元素的地址 - x[4][4]元素的地址 = 0x21c-0x140=5n+5(21c和140是地址末三位的十六进制数),这里n是43,假设x[7][7]的地址是z,x[7][7]元素的地址 - x[4][4]元素的地址 = z-0x140 = 3n+3,z= 3n+3+0x140 = 3*43+3+0x140 = 0x84+0x140 = 0x1c4,看地址的尾数,选择A

在上下文及头文件均正常的情况下,下列代码的输出是( )(注: print 已经声明过)

int main() { char str[] = "Geneius"; print(str); return 0; } print(char *s) { if(*s) { print(++s); printf("%c", *s); } } 代码实现了递归倒序打印字符串的功能,但是++s使得s的值发生了变化,回不到'G'的位置上,故而没有打印'G'

A: suiene B: neius C: run-time error D: suieneG

答案选A

对于代码段,下面描述正确的是

t=0; while(printf("")) { t++; if (t<3) break; } A.其中循环控制表达式与0等价 B.其中循环控制表达式与'0'等价 C.其中循环控制表达式是不合法的 D.以上说法都不对 因print(“”)函数调用的返回值是字符串中字符的个数,即为1。所以while后面的条件恒为真,所以循环控制表达式与'0'是等价的(字符'0'不是0)。正确答案是B

求函数返回值,传入 -1 ,则在64位机器上函数返回( ) A: 死循环 B: 64 C: 32 D: 16

int func(int x) { int count = 0; while (x) { count++; x = x&(x - 1);//与运算 } return count; } 正确答案:C x=x&(x-1)这个表达式执行一次就会将x的2进制中最右边的1去掉,在x变成0之前,表达式能执行几次,就去掉几个1,所以这个代码实现了求一个有符号整数二进制补码中1的个数的功能,我们知道-1的补码是全1,而int类型4个字节32位,选C

读代码选结果( )

A: 1 B: 2 C: 32 D: 死循环,没结果 int count = 0; int x = -1; while(x) { count++; x = x >> 1; } printf("%d",count); 此题一个关键,有符号数右移运算高位是补符号位的,负数的符号位是1,所以x永远不会变为0,是个死循环

下述赋值语句错误的是( )

A: a = (b = (c = 2 , d = 3))
B: i++ C: a/b = 2 D: a = a < a + 1 正确答案:C C选项中a/b是表达式,表达式计算的结果是一个值不能做左值

下面函数的输出结果是( )

void func() { int k = 1^(1 << 31 >> 31); printf("%d\n", k); } A: 0 B: -1 C: -2 D: 1 答案解析: 正确答案:C (1 << 31 );左移31位,并在右侧填充0,得到0x80000000,即符号位为1,其他为0,即-2147483648 int k = 1^(1 << 31 >> 31);注意,这里在右移的时候,符号位保持为1,右移后填充1,结果为0xFFFFFFFF,即-1,0x00000001^0xFFFFFFFF,即0xFFFFFFFE(-2)

假设编译器规定 int 和 short 类型长度分别为32位和16位,若有下列C语言语句,则 y 的机器数为( )

unsigned short x = 65530; unsigned int y = x; A: 0000 7FFA B: 0000 FFFA C: FFFF 7FFA D: FFFF FFFA 答案解析: 正确答案:B unsigned short类型的x变量2个字节保存了65530,十六进制形式为0xFFFA,x给y赋值时会整型提升,而无符号数在提升时高位补0,其实就相当于把x的值放在了y的低2个字节的空间中,故选B

下列程序的输出结果是什么()

#include<stdio.h> int main() { int n = 1001; int ans = 0; for(int i = 1; i <= n; ++i) { ans ^= i % 3; } printf("%d",ans); return 0; } A: -2 B: 0 C: 1 D: 2 答案选B

i % 3 的值按1、2、0循环,可推算出ans按1、3、3、2、0、0循环,循环进行1001次,而1001%6=5,也就是ans按规律得到的第5个数为最终结果,故ans=0

以下选项中,对基本类型相同的两个指针变量不能进行运算的运算符是( )

A: + B: - C: = D:==

正确答案:A A错误,因为两个地址相加无意义也可能越界,所以规定不允许指针相加。B选项,可以求出两个数据元素储存位置之间的相隔同数据类型的元素个数,C选项,赋值,没问题,D选项,判断两指针是否相同

如果 x=2014 ,下面函数的返回值是( )

int fun(unsigned int x) { int n = 0; while(x + 1) { n++; x = x | (x + 1); } return n; } 答案解析: 正确答案:C 这个作用是对整型中0的个数进行统计,x=x|(x+1);的作用是每次循环把x的二进制中从右往左数的最后一位0变成1,直到变成全1的时候x+1就溢出为全0,循环结束。2014的二进制是0000 0000 000 0000 0000 0111 1101 1110,所以结果是 23

有以下函数,该函数的功能是( )

int fun(char *s) { char *t = s; while(t++); return(t-s); } 答案解析: 正确答案:B 循环在t为0时停止,同时t++,t最后会停在字符串结束的'\0'之后的一个位置,t作为尾部指针减去头部指针就是整个字符串占用内存的字节数,包含\0在内;而c答案字符串长度不包括最后的\0

若有float a[3]={1.5,2.5,3.5},pa=a;(pa++)*=3; ”,则 *pa 的值是( )

A.1.5 B.2.5 C.3.5 D.4.5

答案解析: 正确答案:B 在*pa=a中指针pa指向a[0];pa++返回值仍是操作之前的值;

*(pa++)取pa指向的地址的值;

(pa++)=3将该值变为原来的3倍,也就是数组a的第一个值为4.5;

由于pa++之后pa指针移动了sizeof(float)个字节,所以pa指向a[1],所以值为2.5

以下叙述中正确的是( )

A: 即使不进行强制类型转换,在进行指针赋值运算时,指针变量的基类型也可以不同 B: 如果企图通过一个空指针来访问一个存储单元,将会得到一个出错信息 C: 设变量p是一个指针变量,则语句p=0;是非法的,应该使用p=NULL; D: 指针变量之间不能用关系运算符进行比较

答案解析: 正确答案:B A 选项描述不正确,不同类型指针一般不可以直接赋值;C选项中,p=NULL;和p=0;是等价的;D选项中,指向同一数组的两指针变量进行关系运算可表示它们所指数组元素之间的位置关系。B选项正确

关于指针下列说法正确的是【多选】( )

A: 任何指针都可以转化为void * B: void *可以转化为任何指针 C: 指针的大小为8个字节 D: 指针虽然高效、灵活但可能不安全 答案解析: 正确答案:ABD C选项,指针占几个字节要看平台,64位环境下8个字节,32位环境下4个字节

指出下列代码的缺陷【多选】( )

float f[10]; // 假设这里有对f进行初始化的代码 for(int i = 0; i < 10;) { if(f[++i] == 0) break; } A: for(int i = 0; i < 10;)这一行写错了 B: f是float型数据直接做相等判断有风险 C: f[++i]应该是f[i++] D: 没有缺陷 答案解析: 正确答案:BC 一般float型只能精确到小数后六位(即1e-6),将float型数据的绝对值与1e-6比较,来判断是否相等(为零)。float的精度误差在1e-6;double精度误差在1e-15;所以要判断一个float型数:if(fabs(f)<1e-6);要判断一个double型数:if(fabs(f)<1e-15);若满足,则为零。考虑B选项是对的。若要判断float a,b是否相等,要看if(fabs(a-b)<1e-6)是否为真。C选项,考虑的是数组越界问题

请指出以下程序的错误【多选】( )

void GetMemory(char **p, int num) { if(NULL == p && num <= 0)//1 return; p = (char)malloc(num); return; } int main() { char *str = NULL; GetMemory(&str, 80); //2 if(NULL != str) { strcpy(&str, "hello"); //3 printf(str); //4 } return 0; }

A: 1 B: 2 C: 3 D: 4 答案解析: 正确答案:AC 第1处两种情况之一成立都是要返回的,应该用或,此处用与错误。在GetMemory(&str,100);中传入str的地址,在语句char*str=NULL;中str初始化为空指针,但是str指针变量也有地址,所以参数char**p里面的p保存的是指针变量str的地址,所以调用GetMemory函数之后,动态开辟的空间的地址存放在了str中,在函数返回之后没有释放内存,但是这不会导 致程序错误,只会导致内存泄漏。第3处用&str是错的,应该直接用str,是刚申请下来的空间首地址,可以用来接收字符串的copy。

请问下列代码的输出结果有可能是哪些【多选】( )

#include <stdio.h> typedef union { int a; struct { short b; short c; }; }X; int main() { X x; x.a = 0x20150810; printf("%x,%x\n", x.b, x.c); return 0; }

A: 2015,810 B: 50810,201 C: 810,2015 D:20150,810 答案解析: 正确答案:AC 对于0x20150810 如果按照大端模式存储:从低地址到高地址:20 15 08 10 输出从低地址到高地址:20 15 08 10

如果按照小端模式存储:从低地址到高地址:10 08 15 20 输出从高地址到低地址:08 10 20 15 此数以int类型赋值给联合体x.a,而以结构成员b和c分开访问,分别拿到低地址的2个字节和高地址的2个字节,大端下是2015和810,小端下是810和2015

下面这个程序执行后会有什么错误或者效果【多选】( )

#define MAX 255 int main() { unsigned char A[MAX], i; for(i = 0; i <= MAX; i++) A[i] = i; return 0; } A: 数组越界 B: 死循环 C: 栈溢出 D: 内存泄露

答案解析: 正确答案:AB 数组下标越界:数组大小255,但是当a[255]就是256个元素,导致越界了。死循环:这个是因为无符号字符型的变量大小在0-255之间,所以说i永远不可能大于255的,是个死循环。内存泄漏:创建的临时变量,在栈中,应该会由系统自动释放,所以应该是不存在内存泄漏的问题。栈溢出:属于缓冲区溢出的一种。栈溢出是由于C语言系列没有内置检查机制来确保复制到缓冲区的数据不得大于缓冲区的大小,因此当这个数据足够大的时候,将会溢出缓冲区的范围

请问下列程序的输出是多少( )

#include<stdio.h> int main() { unsigned char i = 7; int j = 0; for(;i > 0;i -= 3) { ++j; } printf("%d\n", j); return 0; } A: 2 B: 死循环 C: 173 D: 172 答案解析: 正确答案:C 本题就是找规律,计算什么时候能遇到0 unsigned char 8位数据位,范围在0-255,所以-2的补码(11111110)时,变成254;同理-1(11111111)时,变成255;最后减到0时,不满足循环条件,for停止,刚好173次

7 4 1 ==> 共(7-1)/3+1=3次 1-3=-2,即254,继续循环 254 251 ... 5 2 ==> 共(254-2)/3+1=85次(2-3=-1,即255,继续循环) 255 252 ... 6 3 ==> 共(255-3)/3+1=85次(3-3=0,退出循环) 所以总共173次

二.筛选法求素数 筛选法求素数_牛客题霸_牛客网 (nowcoder.com)

思路:把2~n之间的正整数放在数组内存储,将数组中2之后的所有能被2整除的数变为0,再将3之后的所有能被3整除的数变为0,以此类推直到n为止,数组中不为0的数即是素数

第一次的代码

#include<stdio.h> int main() { int n = 0; int count = 0; while (scanf("%d", &n)) { int arr[100] = { 0 }; int i = 0; int j = 0; for (i = 0;i < n - 1;i++) { arr[i] = i + 2;//将2n之间的正整数放在数组内存储 } for (i = 0;i < n - 1;i++) {

		for (j = i + 1;j < n - 1;j++)
		{
			if (arr[j] % arr[i] == 0)
			{
				arr[j] = 0;
				
			}

		}
	}

	for (i = 0;i < n - 1;i++)
	{
		if (arr[i] != 0)
		{
			printf("%d ", arr[i]);
		}
		else
			count++;
	}
	printf("\n");
	printf("%d", count);

}
return 0;

}

出现的问题

出现了这样的错误,接着回头看了一下发现

这样写就导致会遇到除以0的情况

改进:

#include<stdio.h> int main() { int n = 0; int count = 0; while (scanf("%d", &n)) { int arr[100] = { 0 }; int i = 0; int j = 0; for (i = 0;i < n - 1;i++) { arr[i] = i + 2;//将2n之间的正整数放在数组内存储 } for (i = 0;i < n - 1;i++) { if (arr[i] == 0) { continue; } for (j = i + 1;j < n - 1;j++) { if (arr[j] % arr[i] == 0) { arr[j] = 0;

			}

		}
	}

	for (i = 0;i < n - 1;i++)
	{
		if (arr[i] != 0)
		{
			printf("%d ", arr[i]);
		}
		else
			count++;
	}
	printf("\n");
	printf("%d", count);

}
return 0;

}

加一个判断即可

二.包含数字9的数 今年是2019年,KiKi想知道1~2019中有多少个包含数字9的数。包含数字的数是指有某一位是“9”的数,例如“2019”、“199”等。

包含数字9的数_牛客题霸_牛客网 (nowcoder.com)

#include<stdio.h> int main() { int i=0; int count=0; for(i=1;i<2020;i++) { int tmp=i; while(tmp) { if(tmp%10==9) { count++; break; } tmp/=10; } } printf("%d",count); return 0; }

三.计算日期到天数的转换 计算日期到天数转换_牛客题霸_牛客网

#include<stdio.h> int is_leapYear(int y) { if((y%4==0&&y%100!=0)||(y%400==0)) { return 1; } else return 0; } int main() { int y=0; int m=0; int d=0; int i=0; scanf("%d %d %d",&y,&m,&d); int arr[12]={31,28,31,30,31,30,31,31,30,31,30,31}; int days=0; int flag=is_leapYear(y); for(i=0;i<m-1;i++) { days+=arr[i]; } if(m>2) { if(flag==1) { days+=1; } } days+=d; printf("%d",days); return 0; }

四.验证尼科彻斯定理 尼科彻斯定理_牛客题霸_牛客网

要验证尼科彻斯定理

我们仔细分析,可以把它简化为一个等差数列求和的问题,等差数列的公差是2,求和公式为Sn=n*a1+n*(n-1)我们需要遍历一遍,找到数列的首项,之后的问题也就迎刃而解。

#include<stdio.h> #include<math.h> int main() { int m=0; while(scanf("%d",&m)!=EOF) { int s=0; s=pow(m,3); int i=0; int j=0; //等差数列求和 Sn=na1+n(n-1) //找到等差数列的首项a1 for(i=0;i<10000;i++) { if(s==mi+m(m-1)) { for(j=0;j<m-1;j++) { printf("%d+",i+2j); } printf("%d\n",i+2j); break; } } } return 0; }

五.小乐乐与序列(数列去重并排序) 小乐乐与序列_牛客题霸_牛客网

思路一:

如:5 4 3 2 1 3 2 2 2 1

先排序,得到:

5 4 3 3 2 2 2 1 1

再去重,只要后面一个与前面一个不一样就放入数组

思路二: (较好)

如:5 4 3 2 1 3 2 2 2 1

由于题目给了正整数的条件

我们直接把某个数m放到数组下标也为m处

这样我们即实现了去重又实现了排序

打印时只要不是0我们就打印

#include<stdio.h> int main() { int arr[100001]={0}; int n=0; int k=0; scanf("%d",&n); int i=0; for(i=0;i<n;i++) { scanf("%d",&k);
arr[k]=k;
} for(i=0;i<100001;i++) { if(arr[i]!=0) { printf("%d ",arr[i]); } } return 0; }

六.字符串左旋 实现一个函数,可以左旋字符串中的k个字符

例如:

ABCD左旋一个字符得到BCDA

ABCD左旋两个字符得到CDAB

方法一:

void left_move(char*str,int k) { int len = strlen(str); int i = 0; int j = 0; k %= len; for (i = 0;i < k;i++) { char tmp = *str;

	for (j = 0;j < len-1;j++)
	{
		*(str + j) = *(str + j + 1);
	}
	*(str + len - 1) = tmp;
}

} int main() { char arr[] = "abcdef"; int k = 0; scanf("%d", &k); left_move(arr,k); printf("%s\n", arr); return 0; }

方法二:拼接

void reverse(char* left,char* right) {

while (left < right)
{
	char tmp = *left;
	*left = *right;
	*right = tmp;
	left++;
	right--;
}

} void left_move(char*str,int k) { int len = strlen(str); k %= len; reverse(str, str + k - 1); reverse(str + k,str + len - 1); reverse(str, str + len - 1);

} int main() { char arr[] = "abcdef"; int k = 0; scanf("%d", &k); left_move(arr,k); printf("%s\n", arr); return 0; }

七.杨氏矩阵 有一个数字矩阵,矩阵的每行从左到右是递增的,矩阵从上到下是递增的,请编写程序在这样的矩阵中查找某个数字是否存在。

要求:时间复杂度小于O(N);

void findInarr(int arr[3][3],int* px,int* py,int k) { int x = 0; int y = *py - 1; while (x <= *px - 1 && y >= 0) { if (arr[x][y] < k) { x++; } else if (arr[x][y] > k) { y--; } else { *px = x; *py = y; return; } } *px = -1; *py = -1; }

int main() { int arr[3][3] = { 1,2,3,4,5,6,7,8,9 }; int k = 0; scanf("%d", &k); int x = 3; int y = 3; findInarr(arr,&x,&y,k); if (x == -1 && y == -1) { printf("找不到\n"); } else { printf("找到了,下标是%d %d\n", x, y); } return 0; }

八.字符串旋转结果 写一个函数,判断一个字符串是否为另外一个字符串旋转之后的字符串。

例如:给定s1 =AABCD和s2 = BCDAA,返回1

给定s1=abcd和s2=ACBD,返回0.

AABCD左旋一个字符得到ABCDA

AABCD左旋两个字符得到BCDAA

AABCD右旋一个字符得到DAABC

方法1.仿照上面的左旋

方法2. 在AABCD后面追加一个AABCD

       AABCDAABCD

这样就包含了所有可能的情况

int is_move(char* str1, char* str2) { int len1 = strlen(str1); int len2 = strlen(str2); if (len1 != len2) { return 0; } strncat(str1, str1, len1); if (strstr(str1, str2)) { return 1; } else { return 0; } } int main() { char str1[20] = "AABCD"; char str2[] = "BCDAA"; int ret = is_move(str1, str2); printf("%d", ret); return 0; }

注:

字符串自己给自己追加内容尽量用strncat 而不是strcat,否则可能会出现bug

九.有序序列合并 有序序列合并_牛客题霸_牛客网 (nowcoder.com)

#include<stdio.h> int main() { int m = 0; int n = 0; scanf("%d %d", &m, &n); int arr1[m]; int arr2[n];

int i = 0;
for (i = 0;i < m;i++)
{
	scanf("%d", &arr1[i]);
}
for (i = 0;i < n;i++)
{
	scanf("%d", &arr2[i]);
}
 i = 0;
int j = 0;
while (i < m && j < n)
{
	if (arr1[i] < arr2[j])
	{
		printf("%d ", arr1[i]);
		i++;
	}
	else
	{
		printf("%d ", arr2[j]);
		j++;
	}
}
if (i == m)
{
	for (;j < n;j++)
	{
		printf("%d ",arr2[j]);
	}
}
else
{
	for (;i < m;i++)
	{
		printf("%d ", arr1[i]);
	}
}
return 0;

}

十.找单身狗 一个数组中只有两个数字是出现一次,其他所有数字都出现了两次。

编写一个函数找出这两个只出现一次的数字。

这道题我们要用到 位操作符,所以我们先来复习一下 位操作符 的有关知识

异或运算的特殊公式

我们之前做过一道类似的题目,那道题是数组中只有一个出现了一次的元素,其他元素都出现两次,那道题我们直接把每个元素都异或(^),最终得到的结果就是这个要找的“单身狗”

但是这道题目是两个数字都只出现了一次,

直接异或的话并不能找到这两个数字分别是多少

所以我们的整体思路是:

把所有的数字分成两组(那两个只出现了一次的数字必须分在不同的组), 每组中除了这个特殊的数字, 其他的数字都是成对的,都是出现了两次的 再分别对每个组里的元素进行异或操作 但是我们遇到了一个难点,就是怎么把这些元素分成满足这样要求的两组

分组的方法:

我们先对整个数组里的所有元素进行 异或 操作 这里举个例子:1 2 3 4 5 1 2 3 4 6 1^2^3^4^5^1^2^3^4^6=5^6 5 ^ 6就是 101 ^ 110 = 011 下面我们需要把得到的这个二进制值011查找 找到某一位,这个二进制位上的数字是1, 1代表这两个数的这个位上的数字一个是0,一个是1 我们再根据这个二进制位上的数字是1还是0 把数组进行分组 数组是1的一组,是0的是另一组 上代码

#include<stdio.h> int main() { int arr[] = { 1,2,3,4,5,1,2,3,4,6 }; int i = 0; int sz = sizeof(arr) / sizeof(arr[0]); int ret = 0; for (int i = 0;i < sz;i++) { ret ^= arr[i]; } int pos = 0; for (int i = 0;i < 32;i++) { if (((ret >> i) & 1) == 1) { pos = i; break; } } int m = 0; int n = 0; for (int i = 0; i < sz; i++) { if (((arr[i] >> pos) & 1 )== 1) { m ^= arr[i]; } else { n ^= arr[i]; } } printf("%d %d", m, n);

return 0;

}

十一.输出一个最小的步数变为Fibonacci数 链接:Fibonacci数列__牛客网

Fibonacci数列是这样定义的: F[0] = 0 F[1] = 1 for each i ≥ 2: F[i] = F[i-1] + F[i-2] 因此,Fibonacci数列就形如:0, 1, 1, 2, 3, 5, 8, 13, ...,在Fibonacci数列中的数我们称为Fibonacci数。给你一个N,你想让其变为一个Fibonacci数,每一步你可以把当前数字X变为X-1或者X+1,现在给你一个数N求最少需要多少步可以变为Fibonacci数。

#include<stdio.h> int main() { int n=0; scanf("%d",&n); int a=0; int b=1; int c=a+b; while(1) { if(n==b) { printf("%d\n",0); break; } else if(n<b) { if(abs(a-n)<abs(b-n)) { printf("%d\n",abs(a-n)); break; } else { printf("%d\n",abs(b-n)); break; } } a=b; b=c; c=a+b; } return 0; }

十二.替换空格 请实现一个函数,将一个字符串中的每个空格替换成“%20”。例如,当字符串为We Are Happy.则经过替换之后的字符串为We%20Are%20Happy。

替换空格__牛客网 (nowcoder.com)

class Solution { public: void replaceSpace(char str,int length) { int spacecnt=0; char cur=str; while(*cur) { if(cur==' ') { spacecnt++; } cur++; } int newlen=length+2spacecnt; int end1=length-1; int end2=newlen-1; while(end1!=end2) { if(str[end1]!=' ') { str[end2--]=str[end1--]; } else { str[end2--]='0'; str[end2--]='2'; str[end2--]='%'; end1--; } }

}

};