C语言指针如何实现字符串逆序反转
作者:xiaoyaolangwj
指针实现字符串逆序反转
#include<stdio.h> #include<string.h> void rec(char* arr) { //int len = sizeof(arr); // 判断字符串长度需要用strlen。 int len = strlen(arr); printf("字符串长度len = %d\n", len); char* p1 = arr; char* p2 = &arr[len - 1]; while (p1 < p2) { char temp = *p1; *p1 = *p2; *p2 = temp; p1++; p2--; } } int main() { char arr[] = "hello world"; rec(arr); printf("逆序之后输出为:%s\n", arr); system("pause"); return 0; }
知识点
- 判断字符串长度需要用到string.h下的strlen函数方法。
- 算法层面:
逆序就是头尾逐位交换,所以选定两个指针,一个在首,一个在尾。
指针可以直接比较大小。所以才有了while(p1<p2)来将算法执行的终点找到。
- 因为传入函数方法rec的是地址,所以可以直接修改了原始数据。为了如果为了保护原始数据,需要复制一份另用。
字符串逆序的几种写法
提示:将字符串逆序与将其逆序打印出来是两码事,逆序是将内容倒着改变了,逆序打印虽然打印结果也是倒着的,不过储存字符串的数组内容并没有改变。
非递归写法
1. 将一个给定的字符串abcdef逆序
#include <stdio.h> int main() { char arr[] = "abcdef"; int sz = sizeof(arr) / sizeof(arr[0]); //求的是数组包含的元素个数,'\0'也包括在内 int left = 0; int right = sz - 2; //减2是因为求得的sz包含了'\0'这个元素。 while (left < right) { char tmp = arr[left]; arr[left] = arr[right]; arr[right] = tmp; left++; right--; } printf("%s", arr); return 0; }
打印结果为fedcba。
逆序思路为:将一字符串最左端与最右端的字符交换,交换过后,通过数组下标将左边第二个字符与右边第二个字符交换,依次类推,知道数组下标通过left++与right–,使得left>=right。
2. 自己输入一串字符串,将其逆序
#include <stdio.h> #include <string.h> int main() { char arr[101] = { 0 }; //要给字符数组一定的内存大小,如果写成char arr[] = { 0 };,当在给数组输入的时候就会造成越界访问。 scanf("%s", arr); int sz = strlen(arr); //在给定字符数组的大小为101的情况下,只能用strlen求输入字符串长度。 //用sizeof(arr)/sizeof(arr[0])求出来的是数组大小,为101。 int left = 0; int right = sz - 1; while (left < right) { char tmp = arr[left]; arr[left] = arr[right]; arr[right] = tmp; left++; right--; } printf("%s", arr); return 0; }
随便输入一串字符,例如:12345gf,打印结果为fg54321。
注意:对于自己给数组输入数据,再将其逆序这种情况下,在定义数组时,要给字符数组一定的内存大小。如果写成char arr[] = { 0 };,说明这个数组的容量只有一个字节,只能输入一个字符,当在给数组输入的时候就会造成越界访问。
3. 将逆序封装成函数
#include <stdio.h> #include <string.h> void reverse(char arr[]) { int left = 0; int right = strlen(arr) - 1; //封装成函数只能用库函数求字符串长度,不能用sizeof(arr)/sizeof(arr[0])-1这种方式。 //因为数组形参就是个地址。sizeof(arr)与sizeof(arr[0])的大小都是四个字节或者八个字节。 while (left < right) { char tmp = arr[left]; arr[left] = arr[right]; arr[right] = tmp; left++; right--; } } int main() { char arr[] = "abcdef"; reverse(arr); printf("%s", arr); return 0; }
与sizeof 两者用来求字符串长度时的场合区别。
这里值得注意的是,在自定义函数中求字符串长度时,不要用sizeof(arr)/sizeof(arr[0])-1这种方式。直接使用库函数 strlen。因为数组在传参的时候,传过去的是数组首元素的地址,也就是说形参虽说写的是数组的形式char arr[],但是形参其实是个指针变量char*。
对于指针变量来说,其大小根据编译器环境,都是四个字节或者都是八个字节。sizeof运算符就是获取数据类型和表达式的尺寸的(单位:字节)。sizeof(arr)与sizeof(arr[0])的大小都是四个字节或者八个字节。
所以sizeof(arr)/sizeof(arr[0])-1=4/4-1=0,或者8/8-1=0。
递归写法
1. 方法一
#include <stdio.h> #include <string.h> void reverse(char str[]) //用数组接收实参,也可用指针接收实参,如void reverse(char* str) { char tmp = *str; int len = strlen(str); *str = *(str + len - 1); *(str + len - 1) = '\0'; if (strlen(str + 1) >= 2) //首尾交换后,剩下的元素构成的数组,长度要大于1,才逆序,只剩下一个元素,表明其是最中间的元素,放在原位就好。 { reverse(str + 1); } *(str + len - 1) = tmp; } int main() { char arr[101] = { 0 }; scanf("%s", arr); reverse(arr); printf("%s\n", arr); return 0; }
思路:假设一个数组有 n 个元素。
交换str[0]与 str[n-1],再逆序 str[1] 与 str[n-2]
交换 str[1] 与 str[n-2],再逆序 str[2] 与 str[n-3]。依次类推
······
操作步骤:
- 1.先将第一个字符,即 str[0] 位置上的字符放在一个临时变量中。
- 2.将最后一个元素交换到 str[0] 的位置去。
- 3.将字符串中的’\0’放到arr[n-1] 的位置上去。
- 4.此时从 str[1] 到 str[n-2] 的角度上看,是一个新的字符串,将 str[1] 与 str[n-2] 交换。
- 5.将先前放在临时变量中的第一个字符赋给 arr[n-1] 的位置上去。
注意:在第三步并没有将放在临时变量中的第一个字符直接往 str[n-1]上放,而是经过第四步,将str[1] 与 str[n-2] 交换后,才将之前未交换完的第一个字符放到 str[n-1] 上去。原因:如果直接将 str[0] 与 str[n-1] 上的元素通过一个临时变量交换了。那么对于即将要交换的 str[1] 与 str[n-2] 来说,他们与’\0’之间隔了一个放在str[n-1]上的第一个字符,str[1] 与 str[n-2] 也就无法通过首尾字符直接交换的方式进行交换了 。
逆序a b c d e f 等于交换 a与f ,再逆序b c d e
逆序b c d e 等于交换b与e,再逆序c d。依次类推。
2. 方法二
#include <stdio.h> #include <string.h> void reverse(char str[], int left, int right) { if (left < right) { char tmp = str[left]; str[left] = str[right]; str[right] = tmp; reverse(str, left + 1, right - 1); } } int main() { char arr[101] = { 0 }; scanf("%s", arr); int left = 0; int right = strlen(arr) - 1; reverse(arr, left, right); printf("%s\n", arr); return 0; }
方法二比方法一传的参数要多,直接将首尾字符通过第三个临时变量进行交换就行。
以上为个人经验,希望能给大家一个参考,也希望大家多多支持脚本之家。