考前突击时在头歌遇到个题,我按照我的想法没有整出来,特此记录。
全是废话 大家不必点开阅读
一、原题描述
任务描述
本关任务:实现字符串的部分复制。
编程要求
在右侧编辑器中的Begin-End
之间补充代码,实现字符串的部分复制。
提示
函数 strmncpy 的原型为:
void strmncpy(char *s, int m, int n, char *t);
-
参数 s 指向源字符串,t 指向字符串复制的目标单元,函数功能为将 s 指向字符串从第 m 个(从0开始编号)字符开始的连续 n 个字符复制到 t 指向的存储单元;
-
如果第 m 个字符后面的字符数不足 n 个,则复制到 '\0'为止;
-
如果 s 的长度不到 m,则复制空串。
例如:
char *s = "abcdefghijklmn";
char t[20];
strmncpy(s,4,6,t);
cout << t << endl;
输出结果为:efghij
测试说明
平台会对你编写的代码进行测试,比对你输出的数值与实际正确数值,只有所有数据全部计算正确才能通过测试:
测试输入:
abcdefghjkksdsd
5 7
预期输出:fghjkks
测试输入:
asdftyuioplkm
3 9
预期输出:ftyuioplk
二、疑惑
这是正确的(从网上copy的)代码:
#include <iostream>
using namespace std;
void strmncpy(char *s, int m, int n, char *t);
int main()
{
char s[128],t[128];
int m,n;
cin>>s; // 输入源串
cin>>m>>n; // 输入m和n
strmncpy(s, m, n, t); // 字符串复制
cout << t <<endl; // 输出复制结果
return 0;
}
// 函数strmncpy:字符串的部分复制,将s指向字符串从第m个字符开始的n个字符复制的t中
// 参数:s-指向源字符串,t-指向目标字符串,m-起始位置,n-字符个数
// 返回值:无
void strmncpy(char *s, int m, int n, char *t)
{
// 请在此添加代码,实现函数strmncpy
/********** Begin *********/
//检测m是否超过s
char *check = s;
int position = 0;
while(*check !='\0')
{
check ++;
position ++;
}
int i, j;
if(position>=m)
for(i=m, j=0; i<m+n; i ++, j ++)
{
t[j] = s[i];
if(s[i] == '\0') break;
}
t[j] = '\0';
/********** End **********/
}
(一)、为什么在被调函数中,我的t仿佛什么都没有发生过一样
这是我的问题代码:
#include <iostream>
using namespace std;
void strmncpy(char *s, int m, int n, char *t);
int main()
{
char s[128],t[128];
int m,n;
cin>>s; // 输入源串
cin>>m>>n; // 输入m和n
strmncpy(s, m, n, t); // 字符串复制
cout << t <<endl; // 输出复制结果
return 0;
}
// 函数strmncpy:字符串的部分复制,将s指向字符串从第m个字符开始的n个字符复制的t中
// 参数:s-指向源字符串,t-指向目标字符串,m-起始位置,n-字符个数
// 返回值:无
void strmncpy(char *s, int m, int n, char *t)
{
// 请在此添加代码,实现函数strmncpy
/********** Begin *********/
t = s+m;
*(t+n) = '\0';
//cout<<t<<endl;
/********** End **********/
}
我的想法是:让t指向s+m的那个地址,然后令s+m+n的内容变成‘\0’,这样我就在输出字符串t时有了一个我确定的开头和一个确定的结尾'\0’。
问题表现在:尽管在strmcpy函数内进行cout<<t确实会输出正确结果,但当函数结束调用返回主函数时,t又恢复了调用函数前的样子,仿佛什么都没有发生。
三、问题解决
联想到前几天写的类似的题,我又进行了小小的修改:
我将函数类型由void改为char*,于是乎:
#include <iostream>
using namespace std;
char* strmncpy(char *s, int m, int n, char *t);
int main()
{
char s[128],t[128];
int m,n;
cin>>s; // 输入源串
cin>>m>>n; // 输入m和n
// 字符串复制
cout << strmncpy(s, m, n, t) <<endl; // 输出复制结果
return 0;
}
// 函数strmncpy:字符串的部分复制,将s指向字符串从第m个字符开始的n个字符复制的t中
// 参数:s-指向源字符串,t-指向目标字符串,m-起始位置,n-字符个数
// 返回值:无
char* strmncpy(char *s, int m, int n, char *t)
{
// 请在此添加代码,实现函数strmncpy
/********** Begin *********/
t = s+m;
*(t+n) = '\0';
//cout<<t<<endl;
return t;
/********** End **********/
}
是没有问题的。当然没有问题,你都return回去了嘛
这说明之前写的那个问题代码,它在被调函数中对t的改变并不会影响到main函数的t,即:该函数被调前后,main函数的t仍是空字符串。
这就像下面这个swap函数的单向传递一样:
#include <iostream>
using namespace std;
void swap(int *, int *);
int main()
{
int a = 2, b = 5;
cout<<"swap前:"<<endl;
cout<<"a="<<a<<" b="<<b<<endl<<"&a="<<&a<<" &b="<<&b<<endl;
swap(&a, &b);
cout<<"swap后:"<<endl;
cout<<"a="<<a<<" b="<<b<<endl<<"&a="<<&a<<" &b="<<&b<<endl;
return 0;
}
void swap(int *x, int *y) //实际上是*(&a), *(&b),取a和b所在地址上的内容(即a和b)
{
int t = *x; //现在的x,y 都是地址
*x = *y;
*y = t;
//试图交换地址
int *p = x;
x = y;
y = p;
}
如上,在内容交换的过程中,被调函数swap确实让主函数的a,b发生了改变,但是swap()没有改变指针的值。
在我的教科书上它是这么解释的:
void swap2(int *p1, int *p2)
{
int *p;
p = p1; p1 = p2; p2 = p;
}
如有函数调用swap2(pa, pb), 其中实参pa、pb分别指向a、b的指针变量。swap2()函数调用过程如图4-9所示。实参pa、pb传递给形参p1、p2,函数交换了p1,p2的值,但pa和pb的值不变,*pa、*pb即a、b的值也不会交换。
我豁然开朗,回头看看我的问题代码:
void strmncpy(char *s, int m, int n, char *t);
这条声明把t改成x的话,我将很明显地理解为什么我的有问题:
就像定义函数swap(int a,int b)一样,任你在swap里怎么改变形参a和b,它并不会影响实参(这个实参即使命名是a, b,也绝不是swap的那两个形参);所以调用strmncpy(s, m, n, t),任你形参x怎么变化,它的变化都无法影响到主函数的t中。
我已经完全理解了.jpg
(虽然我可能下次碰到这样的事情又会栽倒……)
此外,在临时抱佛脚的复习时,我还留意到课本讨论指针函数int *f(形参表)的这段话,特此记录以防遗忘:
指针函数返回值不能使本函数中的局部变量的地址,因为本函数执行完毕返回主调函数后,函数的局部变量全部释放,主调函数再去访问它,不能保证结果正确。返回值可以是主调函数中的局部变量的地址、数组元素的地址或全局变量的地址等。
不过很显然,int f(形参表)或者double f(形参表)或者一些其他函数是可以return 本函数的局部变量。二者不要混淆。