A. 成绩查询(指针运算)
题目描述:已知一组学生成绩,然后根据输入的序号查询成绩
要求:
1. 使用一个整数数组存储学生成绩,假设元素数是n。
2. 使用一个指针指向数组中间元素,即n/2的位置。
3. 使用++和--运算符,求出数组中间元素的前一个成绩和后一个成绩
4. 输入一个序号,然后计算这个序号的元素和中间元素的距离,然后使用指针去访问
例如有11个学生,指针指向中间的学生也就是第6个学生,若输入序号3,即查询第3个学生的成绩,第3和第6之间距离为3,那么指针应该怎么运算呢???
如果有两个中间学生,则将后面那个看为中间学生。
5. 整个程序除了输入时可以使用数组下标,其他部分尽量使用使用指针进行访问。
输入:
第一行输入t表示有t个测试实例
第二行先输入n,表示有n个学生,然后再输入n个成绩(正整数)
第三行输入1个序号,表示要查询成绩的学生的序号。
依次输入t个实例
按自然意义,序号是从1开始计算
提示:在数组中是从........
输出:
对于每个测试实例:
第一行输出数组中间元素的前一个成绩和后一个成绩
第二行根据序号输出1个成绩
输入样例:
2
7 66 99 88 44 77 33 11
2
11 60 80 50 20 90 35 70 40 10 95 30
9
输出样例:
88 77
99
90 70
10
代码参考:
#include <iostream>
using namespace std;
int main(){
int t;
cin >> t;
while(t--){
int n;
cin >> n;
int socre[n] ;
for(int i=0;i<n;i++){
cin >> socre[i];// 读入
}
// 定义一个指针p,初始化为指向数组socre中间位置的元素
int *p = &socre[n/2];
cout << *(--p) <<" " ;// 先对指针p进行递减操作,然后输出p指向的元素(即中间元素的前一个)
p++; // 记得复原
cout << *(++p) << endl;// 先对指针p进行递增操作,然后输出p指向的元素(即中间元素的后一个)
p--; // 同理复原
int index;
cin >> index;
cout << *(p + (index -1 - n / 2)) << endl;
}
return 0;
}
tips:① int *p = &socre[n/2]; 这里如果n是奇数,p指向中间的元素。如果是偶数,p指向中间右侧的元素,因为n/2会自动向下取整(例如7/2为3,第三个也就是中间元素,8/2为4,第四个是中间偏右那个元素)
② 对指针加减后记得复原
③ 按自然意义,序号是从1开始计算,而在数组中是从0开始标号,输入样例给的是数组号,所以按数学规律计算它跟指针p的关系就行
B. 月份查询(指针数组)
题目描述
已知每个月份的英文单词如下,要求创建一个指针数组,数组中的每个指针指向一个月份的英文字符串,要求根据输入的月份数字输出相应的英文单词
1月 January
2月 February
3月 March
4月 April
5月 May
6月 June
7月 July
8月 August
9月 September
10月 October
11月 November
12月 December
输入:
第一行输入t表示t个测试实例
接着每行输入一个月份的数字
依次输入t行
输出:
每行输出相应的月份的字符串,若没有这个月份的单词,输出error
输入样例:
3
5
11
15
输出样例:
May
November
error
代码参考:
#include <iostream>
using namespace std;
int main(){
int t;
cin >> t;
char *p[12];// 创建一个有12个指针的数组,即一个数组里,每个元素都是一个指针(char类型的地址)
// 用char类型的二维数组保存十二个月份
char months[12][50] = {"January","February","March","April",
"May","June","July","August",
"September","October","November","December"};
for(int i=0;i<12;i++){
p[i] = months[i];// 让每个指针都指向对应月份,不用&month[i],因为它本身就是地址了
}
while(t--){
int m;
cin >> m;
if(m>=1 && m<=12){
cout << p[m-1] << endl; // 数组名为实际月份-1
}
else{
cout << "error" << endl;
}
}
return 0;
}
tips:①基本的指针数组创建,把char*看成每个数组元素类型就好,char* p[12]跟char c[12]只是保存的元素不同
② 二维数组概念,也叫嵌套数组,即外层是一个数组,而每个数组元素又是一个内层数组,所以months[i]能表示第i个外层数组元素,也即其内层数组的开始地址
C. 字符串比较(指针参数)
题目描述:
编写一个函数比较两个字符串,参数是两个字符指针(要求显式定义,例如char *S, char *T),比较字符串S和T的大小。如果S大于T,则返回1,如果S小于T则返回-1,如果S与T相等则返回0。
比较规则:
1.把两个字符串的相同位置上的字符进行比较,字符的大小比较以ASCII值为准
2.在比较中,如果字符串S的字符大于字符串T的字符的数量超过小于的数量,则认为S大于T,如果等于则S等于T,如果小于则S小于T
例如S为aaccdd,T为eebbbb,每个位置比较得到S前两个字母都小于T,但后4个字母都大于T,最终认为S大于T
3.如果两个字符串长度不同,则更长的字符串为大
在主函数中输入两个字符串,并调用该函数进行判断,在判断函数中必须使用函数参数的指针进行字符比较
输入:
输入t表示有t个测试实例
接着每两行输入两个字符串
依次输入t个实例
输出:
每行输出一个实例的比较结果
输入样例:
3
aaccdd
eebbbb
AAbb++
aaEE*-
zznnkk
aaaaaaa
输出样例:
1
0
-1
参考代码:
#include <iostream>
#include <string>
using namespace std;
int cmp(char* s, char* t){
int result = 0;
int len1, len2;
len1 = strlen(s);
len2 = strlen(t);
if(len1 == len2){
// 若长度相等,依次比较
int cnt_s = 0;
int cnt_t = 0;
for(int i = 0;i < len1;i++){
// 统计大小比较结果
if(*s > *t){
cnt_s++;
}
else if(*s < *t){
cnt_t++;
}
// 指针加加
s++;
t++;
}
// 根据结果按要求返回
if(cnt_t == cnt_s){
result = 0;
}
else if(cnt_s > cnt_t){
result = 1;
}
else{
result = -1;
}
}
// 谁长返回相应值
else if(len1 < len2){
result = -1;
}
else{
result = 1;
}
return result;
}
int main(){
int t;
cin >> t;
while(t--){
char str1[50] , str2[50];
cin >> str1 >> str2;// 输入并保存字符串
// 分别让两个字符指针指向它们
char *s = str1;
char *t = str2;
cout << cmp(s,t) << endl;
}
return 0;
}
tips:比较简单,cmp函数按规矩写就好。
D. 密钥加密法(指针应用)
题目描述:
有一种方式是使用密钥进行加密的方法,就是对明文的每个字符使用密钥上对应的密码进行加密,最终得到密文
例如明文是abcde,密钥是234,那么加密方法就是a对应密钥的2,也就是a偏移2位转化为c;明文b对应密钥的3,就是b偏移3位转化为e,同理c偏移4位转化为g。这时候密钥已经使用完,那么又重头开始使用。因此明文的d对应密钥的2,转化为f,明文的e对应密钥的3转化为h。所以明文abcde,密钥234,经过加密后得到密文是cegfh。
如果字母偏移的位数超过26个字母范围,则循环偏移,例如字母z偏移2位,就是转化为b,同理字母x偏移5位就是转化为c
要求:使用三个指针p、q、s分别指向明文、密钥和密文,然后使用指针p和q来访问每个位置的字符,进行加密得到密文存储在指针s指向的位置。
除了变量定义和输入数据,其他过程都不能使用数组下标法,必须使用三个指针来访问明文、密钥和密文。
提示:当指针q已经移动到密钥的末尾,但明文仍然没有结束,那么q就跳回密钥头
输入:
第一行输入t表示有t个测试实例
第二行输入一个字符串,表示第一个实例的明文
第三行输入一个数字串,表示第一个实例的密钥
依次输入t个实例
输出:
每行输出加密后的密文
输入样例:
2
abcde
234
XenOS
56
输出样例:
cegfh
CksUX
代码参考:
#include <iostream>
#include <string>
using namespace std;
int main(){
int t;
cin >> t;
while(t--){
char str1[50] , str2[50], ans[50];
cin >> str1 >> str2;
char *p = str1;// 明文
char *q = str2;// 密钥
char *s = ans; // 密文
int len = strlen(str1);
for(int i = 0;i < len;i++){
if(*q == '\0'){
q = str2; // 密钥用完就重头开始用
}
char ch = *p + (*q - '0');// 加密
if(ch < 65 ){
// 加密后发现<a 即不是字母了,+26使其回到对应位置
ch += 26;
}
else if((ch > 90 && ch < 97) || (ch > 122) ){
// 同理,在小写与大写之间,或者大于大写,减去26即可
ch -= 26;
}
*s = ch; // 将ch存入密文字符串中
// 指针加加
p++;
q++;
s++;
}
cout << ans << endl;
}
return 0;
}
tips:①首先注意到密钥是数字,但是我们要用的时候是一位一位用,所以不能用Int类型存,只能用字符串存,但在加密时要转换为数字,所以要减去0的ascall码得到对应数字。
② 小复杂的是,加密后密文不在字母范围内,需要分成三种情况处理。
E. 蛇形矩阵(指针与动态内存分配)
题目描述:
蛇形矩阵,是由1开始的自然数一次排列成的N*N的正方形矩阵,数字依次由外而内的递增。如 N=3时蛇形矩阵为:
1 2 3
8 9 4
7 6 5
N=6时蛇形矩阵为:
1 2 3 4 5 6
20 21 22 23 24 7
19 32 33 34 25 8
18 31 36 35 26 9
17 30 29 28 27 10
16 15 14 13 12 11
输入蛇形矩阵宽度,动态分配二维数组,设置蛇形矩阵并输出结果。
输入:
测试次数t
每组测试数据一行:数组大小N(>0)
输出:
对每组测试数据,输出计算得到的蛇形矩阵。每行元素间以空格分隔,最后一个元素后无空格。
每组测试数据之间以空行分隔。
输入样例:
3
3
6
2
输出样例:
1 2 3
8 9 4
7 6 51 2 3 4 5 6
20 21 22 23 24 7
19 32 33 34 25 8
18 31 36 35 26 9
17 30 29 28 27 10
16 15 14 13 12 111 2
4 3
代码参考:
#include <iostream>
#include <string>
using namespace std;
int main(){
int t;
cin >> t;
while(t--){
int n;
cin >> n;
// 动态分配
int ** matrix =new int*[n];
for(int i=0;i<n;i++){
matrix[i] = new int[n];
}
// 为每个元素赋值
int value = 1;
int min_row = 0, max_row = n-1;
int min_col = 0, max_col = n-1;
while(value <= n*n){
// 从左到右
for(int i=min_col;i<=max_col;i++){
matrix[min_row][i] = value;
value++;
}
min_row++;
// 从上到下
for(int i=min_row;i<=max_row;i++){
matrix[i][max_col] = value;
value++;
}
max_col--;
// 从右往左
for(int i=max_col;i>=min_col;i--){
matrix[max_row][i] = value;
value++;
}
max_row--;
// 从下到上
for(int i=max_row;i>=min_row;i--){
matrix[i][min_col] = value;
value++;
}
min_col++;
}
for(int i=0;i<n;i++){
for(int j=0;j<n-1;j++){
cout << matrix[i][j] << " ";
}
cout << matrix[i][n-1] << endl;
}
cout << endl;
for(int i = 0; i < n; ++i) {
delete[] matrix[i]; // 删除每行的列元素
}
delete[] matrix; // 删除行指针
}
return 0;
}
tips: ①动态分配二维数组,就那几行代码,记下来会用就行。
②蛇形一开始找不到规律,本来想着找下一行跟前一行关系,再逐行赋值,发现很难描述...参考网上代码才知道要按规律像走迷宫一样按123456...来赋值。一次循环分为四步,先从左到右,再从上到下,再从右往左,最后从下到上,开始下次循环。怎么样让“画”出的圈越来越小呢,通过控制行、列就行,走完一步,增大/减小相应行列。
F. 三角函数求和(函数指针)(程序填空题)
题目描述:
以下代码计算[a,b)范围内,0.1为步长的三角函数(sin或cos或tan)之和。请补齐sigma函数。
输入:
多组测试数据,每行数据格式为:
三角函数类型(sin或cos或tan) 起始范围a 终止范围b
输出:
对每组测试数据输出[a,b)内,步长0.1的三角函数和。
输入样例:
sin 0.1 1.0
tan 0.1 1.0
cos 1 1.5
输出样例:
5.01388
6.95511
1.79372
参考代码:
#include <iostream>
#include <cmath>
#include <cstring>
using namespace std;
/********** Write your code here! **********/
// 一个接受函数指针作为参数的函数
double sigma(double (*f)(double), double a, double b) {
double sum =0.0;
for(double i=a;i<b;i+=0.1){
sum += f(i);
}
return sum;
}
/*******************************************/
int main()
{
char s[20];
double a, b;
while (cin >> s >> a >> b)
{
if (!strcmp(s,"sin"))
cout << sigma(sin, a, b) << endl;
else if (!strcmp(s,"cos"))
cout << sigma(cos, a, b) << endl;
else
cout << sigma(tan, a, b) << endl;
}
return 0;
}
tips:①记住接受函数指针作为参数的函数怎么写就行