1:有以下函数,该函数的功能是( )
int fun(char *s)
{
char *t = s;
while(*t++);
return(t-s);
}
A: 比较两个字符的大小 B: 计算s所指字符串占用内存字节的个数
C: 计算s所指字符串的长度 D: 将s所指字符串复制到字符串t中
解析 B
*t++ 最后会在’\0’后一个位置停止 '\0’后一个位置为此时指针指向 尾部减去头部包括\0就是字节数
而c答案字符串长度不包括最后的\0
2:若有“ 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指向的地址的值;(pa++)*=3;将该值变为原来的3倍,也就是数组a的第一个值为4.5; 则a[0]此时变为4.5. 由于pa++之后,所以pa指向a[1],所以值为2.5。
此题最重要的地方是pa++是先使用再++,如果没有注意到便会出错选成4.5.
3:以下程序运行后的输出结果是( )
#include <stdio.h>
int main()
{
int a[] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10, 11, 12}, *p = a + 5, *q = NULL;
*q = *(p+5);
printf("%d %d\n", *p, *q);
return 0;
}
A: 运行后报错 B: 6 6 C: 6 11 D: 5 10
解析 A
*p为6,即数组向后移动五位
*q = *(p+5);这是一个错误语句。
我们将p指针向后移动5个位置,使其指向a数组的第11个元素(即11)。然后我们将p指针指向的值(即11)赋给q指针指向的位置。但是,由于q初始值为NULL,它并没有指向任何有效的内存位置,所以这个赋值操作是非法的。
在接下来的printf函数中,我们尝试输出p和q的值。但由于之前的非法赋值操作导致程序崩溃,因此无法继续执行printf函数,程序异常终止。
4:设有定义 char *p[]={“Shanghai”,“Beijing”,“Honkong”}; 则结果为 j 字符的表达式是( )
A: *p[1] +3 B: *(p[1] +3) C: *(p[3] +1) D: p[3][1]
解析
题中j所在位置即p[1][3],这时有多种办法表示p[1][3],(p[1] +3)或是(*(p+1)+3)
B:先通过p[1]获取指针数组中第2个元素的值,即"Beijing"的地址。然后在这个地址上偏移3个字节,即指向字符串中的第4个字符,即’j’字符。
A: p[1] +3表示对指针数组p中的第2个元素进行解引用操作,即获取字符串常量"Beijing"。然后将字符串的首字母’B’的ASCII码值与3相加。
C:(p[3] +1) 表示对指针数组p中的第4个元素进行解引用操作,但是p数组中只有3个元素,所以超出了数组的有效索引范围。这是非法的表达式。
D:p[3][1] 表示对指针数组p中的第4个元素进行解引用操作,但是p数组中只有3个元素,所以超出了数组的有效索引范围。这是非法的表达式。
5:以下叙述中正确的是( )
A: 即使不进行强制类型转换,在进行指针赋值运算时,指针变量的基类型也可以不同
B: 如果企图通过一个空指针来访问一个存储单元,将会得到一个出错信息
C: 设变量p是一个指针变量,则语句p=0;是非法的,应该使用p=NULL;
D: 指针变量之间不能用关系运算符进行比较
解析 B
A:指针变量的赋值只能赋予地址, 决不能赋予任何其它数据,否则将引起错误;
C: p=NULL ;和 p=0 ;是等价的;
D:指向同一数组的两指针变量进行关系运算可表示它们所值数组元素之间的关系。
D:例如,可以使用等号运算符(==)来比较两个指针变量所指向的元素是否相等。如果相等,则表示它们指向同一个元素。
① 可以使用大于号(>)或小于号(<)来比较两个指针变量所指向的元素的大小关系。如果一个指针变量的值大于另一个指针变量的值,则表示第一个元素在数组中的位置靠后。相反,如果一个指针变量的值小于另一个指针变量的值,则表示第一个元素在数组中的位置靠前。
② 还可以使用大于等于号(>=)或小于等于号(<=)来比较两个指针变量所指向的元素的大小关系。如果一个指针变量的值大于或等于另一个指针变量的值,则表示第一个元素在数组中的位置靠后或相同。相反,如果一个指针变量的值小于或等于另一个指针变量的值,则表示第一个元素在数组中的位置靠前或相同。
③需要注意的是,对指针变量进行关系运算时,必须确保两个指针变量指向同一类型的数组元素,否则结果可能不准确。此外,还要注意避免指针越界访问数组元素,否则会导致未定义的行为。
6:珠玑妙算游戏(the game of master mind)的玩法如下。
计算机有4个槽,每个槽放一个球,颜色可能是红色(R)、黄色(Y)、绿色(G)或蓝色(B)。例如,计算机可能有RGGB 4种(槽1为红色,槽2、3为绿色,槽4为蓝色)。作为用户,你试图猜出颜色组合。打个比方,你可能会猜YRGB。要是猜对某个槽的颜色,则算一次“猜中”;要是只猜对颜色但槽位猜错了,则算一次“伪猜中”。注意,“猜中”不能算入“伪猜中”。
给定一种颜色组合solution和一个猜测guess,编写一个方法,返回猜中和伪猜中的次数answer,其中answer[0]为猜中的次数,answer[1]为伪猜中的次数。
示例:
输入: solution=“RGBY”,guess=“GGRR”
输出: [1,1]
解释: 猜中1次,伪猜中1次。
核心代码模式:
int* masterMind(char* solution, char* guess, int* returnSize)
{
*returnSize = 2;
int *res = (int *)calloc(2, sizeof(int));
int count=0;
for (int i=0;i<4;i++)
{
if (solution[i]==guess[i])
{
solution[i] = 0;
guess[i] = 0;
count++;
}
}
res[0]=count;
int fake_count=0;
for (int i=0;i<4;i++)
{
for (int j=0;j<4;j++)
{
if (solution[i] == guess[j] && guess[j] != 0)
{
guess[j] = 0;
fake_count++;
break;
}
}
}
res[1]=fake_count;
return res;
}
完整代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
int* masterMind(char* solution, char* guess, int* returnSize)
{
*returnSize = 2;
int* res = (int*)calloc(2, sizeof(int));
int count = 0;
for (int i = 0; i < 4; i++)
{
if (solution[i] == guess[i])
{
solution[i] = 0;
guess[i] = 0;
count++;
}
}
res[0] = count;
int fake_count = 0;
for (int i = 0; i < 4; i++)
{
for (int j = 0; j < 4; j++)
{
if (solution[i] == guess[j] && guess[j] != 0)
{
guess[j] = 0;
fake_count++;
break;
}
}
}
res[1] = fake_count;
return res;
}
int main()
{
char solution[4] = {0};
char guess[4] = {0};
for (int i = 0; i < 4; i++)
{
scanf("%c", &solution[i]);
}
for (int i = 0; i < 4; i++)
{
scanf("%c", &guess[i]);
}
int returnSize;
int* result = masterMind(solution, guess, &returnSize);
printf("count: %d\n", result[0]);
printf("fake_count: %d\n", result[1]);
free(result);
return 0;
}
解析
代码中的变量说明:
solution:表示正确的序列,由4个数字组成。
guess:表示玩家猜测的序列,也由4个数字组成。
returnSize:表示返回结果的数组的大小,这里设置为2。
res:表示返回的结果数组,其中res[0]表示正确位置数,res[1]表示错误位置数。
代码的执行过程如下:
①首先将返回结果数组的大小设置为2,并分配2个int类型的空间。 定义一个count变量,用来记录猜中数字和位置正确的数量,初始化为0。
② 遍历solution和guess数组的每个元素,如果当前位置的数字相等,则表示猜中了,将solution和guess数组中对应位置的数字都设为0,同时count自增1。
数字设置为0是为了防止下一次循环出现重复。
③ 将正确位置数保存到结果数组的第一个位置res[0]中。 定义一个fake_count变量,用来记录仅猜中数字但位置不正确的数量,初始化为0。
④使用两个嵌套的循环分别遍历solution和guess数组的每个元素,如果当前位置的数字在guess数组中可以找到且没有被匹配过(不为0),则表示猜中了数字但位置不正确,将guess数组中对应位置的数字设为0,同时fake_count自增1,并跳出内层循环。
同样的,数字设置为0是为了防止下一次循环出现重复。
⑤将错误位置数保存到结果数组的第二个位置res[1]中。 返回结果数组res。
7:给出一个整型数组 numbers 和一个目标值 target,请在数组中找出两个加起来等于目标值的数的下标,返回的下标按升序排列。
(注:返回的数组下标从1开始算起,保证target一定可以由数组里面2个数字相加得到)
数据范围:2≤len(numbers)≤10 ^5,−10≤numbers i ≤10 ^9 ,
0≤target≤10 ^9
示例1
输入:[3,2,4],6
返回值:[2,3]
说明:因为 2+4=6 ,而 2的下标为2 , 4的下标为3 ,又因为 下标2 < 下标3 ,所以返回[2,3]
示例2
输入:[20,70,110,150],90
返回值:[1,2]
说明:20+70=90
int* twoSum(int* numbers, int numbersLen, int target, int* returnSize )
{
*returnSize = 2;
int* res = (int*)calloc(2, sizeof(int));
for (int i=0;i<numbersLen;i++)
{
for (int j=i+1;j<numbersLen;j++)
{
if (numbers[i]+numbers[j]==target)
{
res[0]=i+1;
res[1]=j+1;
break;
}
}
}
return res;
}
提示:运行是可以通过的,但是运行超时了,呜呜呜呜呜呜呜,再写一个吧。
不超时版核心代码:
int* twoSum(int* numbers, int numbersLen, int target, int* returnSize )
{
int size=2;
int* target_arr=(int*)malloc(sizeof(int)*size);
for(int i=0;i<numbersLen;i++)
{
if(numbers[i]>target+10)
{
continue;
}
for(int j=i+1;j<numbersLen;j++)
{
if(numbers[i]+numbers[j]==target)
{
target_arr[0]=i+1;
target_arr[1]=j+1;
}
}
}
*returnSize=size;
return target_arr;
}
不超时版完整代码:
#define _CRT_SECURE_NO_WARNINGS 1
#include <stdio.h>
#include <stdlib.h>
int* twoSum(int* numbers, int numbersLen, int target, int* returnSize)
{
int size = 2;
int* target_arr = (int*)malloc(sizeof(int) * size);
for (int i = 0; i < numbersLen; i++)
{
if (numbers[i] > target + 10)
{
continue;
}
for (int j = i + 1; j < numbersLen; j++)
{
if (numbers[i] + numbers[j] == target)
{
target_arr[0] = i + 1;
target_arr[1] = j + 1;
}
}
}
*returnSize = size;
return target_arr;
}
int main()
{
int numbers[] = {0};
int numbersLen = 0;
scanf("%d",&numbersLen);
for (int k = 0; k < numbersLen; k++)
{
scanf("%d", &numbers[k]);
}
int target = 0;
scanf("%d", &target);
int returnSize = 0;
int* result = twoSum(numbers, numbersLen, target, &returnSize);
printf("%d, %d\n", result[0], result[1]);
free(result);
return 0;
}
解析
①首先,外层的for循环用于遍历数组中的每一个元素。循环变量i的初始值为0,每次迭代增加1,直到达到数组的长度。
②在内层的for循环中,用变量j从i+1开始遍历数组中剩下的元素。这是因为我们要找的是两个不同的数,因此不需要重复计算已经计算过的组合。
③在每一次内层循环中,首先判断numbers[i]和numbers[j]的和是否等于目标值target。如果是,则将i和j的索引分别加1赋值给数组a的第一个和第二个元素。这样就找到了满足条件的两个数的索引。
④如果内层循环中的条件不满足,则执行continue语句,跳过本次循环继续执行下一次。这是因为根据给定的条件,如果numbers[i]大于target+10,那么numbers[j]肯定也会大于target+10,因此不需要继续进行计算,直接进入下一次外层循环。
为什么numbers[i]的值超过了目标值target加上10,就不存在满足条件的组合?
这是因为组合的每个元素都是正整数,所以每次选择一个元素加到组合中,组合的值就会增加。当组合的值超过了目标值加上10,说明即使后续选择的元素都是最小的元素1,也无法使组合的值减小到小于等于目标值,因此就不存在满足条件的组合。因为mumbers的取值是可以为-10的!!
举例 [20,-10,5,5] target=10这种情况10+10=20,是可以满足的,但是如果是[21,-10,5] target=10,10+10=20,这种情况就不可以了。已经比它大了。
总结起来,这个条件判断的目的是对数组中的元素进行过滤,排除掉那些已经超过目标值加上10的元素,以提高代码执行的效率。
⑤最后,代码执行完毕后,数组a中存储着满足条件的两个数的索引值。