问题描述:
在这个题目中
输入一个字符串和一个整数 n,一行使用空格隔开,将 1 至 n 个字符,平移到字符串的最后,输出移动后的字符串。
输入格式
一个字符串和一个整数。
输出格式
一个字符串。
在我写的代码中出现了长的字符串移动错误的情况,短的却可以。
相关代码
#include<stdio.h>
void movechars(char *s,int n)
{
for(char *p=s,*q=s+n;*q;p++,q++)
{
char temp=*p;
*p=*q;
*q=temp;
}
}
int main(void)
{
int n;
char str[100];
scanf("%s",str);
scanf("%d",&n);
movechars(str,n);
printf("%s",str);
return 0;
}
运行结果
实际输入:
qwe子qwe字qwe自retertgfgdhfdjxhdfhdfhfxhb 8
实际输出:
eretertgfgdhfdjxhdfhdfhfxhbqweqwqwe
预期输出:
eretertgfgdhfdjxhdfhdfhfxhbqwe紫qwe资qw
(实际字符串之间没有汉字,提问要求不能有重复字符)
实际输出与预期输出不同。
我的初步解决思路:
我用的双指针法实现的,并没有逻辑错误,也没有语法错误,不知道为什么错了。
#操作环境、软件版本等相关信息
头歌上的题目,操作环境,版本现版本。
遇到bug要会测试,你输入的全是重复的字符,排列到底对不对全靠猜
我输入:1234 3
输出:4231
因为你算法本身就不对
你是p和q一直在交换,但是q到结尾交换就结束了
你要把前n个字符先存起来,后n个字符往前挪,再把前n个字符追加到后面
void movechars(char *s, int n){
int len = strlen(s);
n = n % len; // 获得有效的移动次数
for (char *p = s, *q = s + n; *q; p++, q++){
char temp = *p;
*p = *q;
*q = temp;
}
}
为什么平移相对位置还会变
可采纳
void move(char *s,int m)
{
int i,j;
char temp;
for(i=1;i<=m;i++)//m是平移字符的个数
{
temp=*s;//temp临时变量每次记录字符串的第一个字符
for(j=1;*(s+j)!='\0';j++)//内层循环 每次除了第一个字符的其他位置字符向左平移一位,m个字符向左平移m次
*(s+j-1)=*(s+j);
*(s+j-1)=temp;
*(s+j)='\0';
}
}
更新问题描述: 我正在做一个C语言程序,需要实现将输入的一个字符串中的前N个字符移动到字符串末尾的功能。我的代码实现了双指针交换的方法。但测试时,长字符串无法移动,而短字符串却能正常移动。以下是输入输出与我的预期不符的情况:
实际输入:qwe子qwe字qwe自retertgfgdhfdjxhdfhdfhfxhb 8 实际输出:eretertgfgdhfdjxhdfhdfhfxhbqweqwqwe 预期输出:eretertgfgdhfdjxhdfhdfhfxhbqwe紫qwe资qw
问题分析: 根据给出的参考资料没有与这个问题直接相关的内容。在分析这个问题时,可以先看一下代码实现,分析是否漏掉了某些细节问题。而一般情况下,字符串操作出现问题,可能是由于指针未初始化或移动过程中指针越界导致的。
解决方案: 进一步分析给出的测试数据,我们可以看到出现问题的字符串的长度长达30多个字符。此时,如果采用双指针交换字符来实现移动的话,效率可能较低,同时,如果采用指针越界的方式来移动字符串,可能会出现意想不到的结果。因此,我们可以考虑采用较为简单的方式来实现字符串移动,比如先把前N个字符存到另一个字符串,然后再把剩下的字符放在新字符串的末尾,最后将之前存储的前N个字符追加在新字符串末尾即可。具体实现如下:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void move(char* str, int n){
char temp[n+1];
strncpy(temp, str, n); // 把前N个字符存到临时字符串
temp[n] = '\0';
memmove(str, str+n, strlen(str)-n); // 向前移动剩下的字符串
strcat(str, temp); // 在最后追加之前存储的前N个字符
}
int main(){
char str[1000];
int n;
printf("请输入字符串和需要前移的字符数(用空格分隔):");
scanf("%[^\n]%d", str, &n); // 同时输入字符串和数字
move(str, n);
printf("移动后字符串为:%s", str);
return 0;
}
这里我们采用了C标准库函数 strncpy()
来将源字符串中的前n个字符复制到temp临时字符串中,并在temp字符串末尾补字符 '\0'。之后我们使用 memmove()
将源字符串中的剩余字符向前移动n个位置,并使用 strcat()
在移动后的字符串末尾添加temp临时字符串,实现整个字符串的前移。值得注意的是strcat()
前需要保证把'\0'添加在目标字符串的末尾,否则它会在不确定的位置添加。
代码中,使用了字符串的头文件 string.h
中的三个函数。但快速阅读后,没有发现指针的越界问题。此时问题可能来自编译环境。如果是早期编译环境,字符串的内存分配是在栈区,如果字符串长度过长,就可能出现了栈空间不足的问题。这导致了程序的崩溃或其他非预期情况。可以采取的解决方案之一就是尽量不要用字符串的栈空间,而改用堆空间。
更新后的代码,尽量使用了动态分配内存,可以在编译较早的版本上使用:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void move(char* str, int n){
char* temp = (char*)malloc((n+1)*sizeof(char)); // 使用动态分配内存
strncpy(temp, str, n);
temp[n] = '\0';
memmove(str, str+n, strlen(str)-n);
strcat(str, temp);
free(temp); // 释放动态分配的内存
}
int main(){
char* str = (char*)malloc(1000*sizeof(char)); // 同样使用动态分配内存
int n;
printf("请输入字符串和需要前移的字符数(用空格分隔):");
scanf("%[^\n]%d", str, &n);
move(str, n);
printf("移动后字符串为:%s", str);
free(str); // 释放动态分配的内存
return 0;
}
在实现完代码后,我们可以多测试几个字符串长度,判断是否还会出现类似的问题。
参考资料: 1. C语言中字符串的用法,见https://www.runoob.com/cprogramming/c-strings.html
2. 何时需要使用指向堆的指针,见https://blog.csdn.net/lele12/article/details/76181443
3. 栈空间和堆空间的区别,见https://www.guru99.com/cpp-stack-vs-heap.html