【个人记录】字符串部分复制和指针参数单向传递的问题发现

考前突击时在头歌遇到个题,我按照我的想法没有整出来,特此记录。

全是废话 大家不必点开阅读

一、原题描述

任务描述

本关任务:实现字符串的部分复制。

编程要求

在右侧编辑器中的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,则复制空串。

例如:

  1. char *s = "abcdefghijklmn";
  2. char t[20];
  3. strmncpy(s,4,6,t);
  4. cout << t << endl;

输出结果为:efghij

测试说明

平台会对你编写的代码进行测试,比对你输出的数值与实际正确数值,只有所有数据全部计算正确才能通过测试:

测试输入:

  1. abcdefghjkksdsd
  2. 5 7

预期输出:fghjkks

测试输入:

  1. asdftyuioplkm
  2. 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 本函数的局部变量。二者不要混淆。

上一篇:网络爬虫的实现


下一篇:Typora+Markdown