C语言字符串翻转的两种方法及对应的内存模型

第一种:指针两头堵模型

#define  _CRT_SECURE_NO_WARNINGS 
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
int inverse(char *str1)
{
	int length = 0;
	char *p1 = NULL;
	char *p2 = NULL;
	if (str1 == NULL)
	{
		return -1;
	}
	length  = strlen(str1);
	p1 = str1;                 //指针指向字符串的开头;
	p2 = str1 + (length - 1);  //指针指向字符串的最后一个;
	while (p1 < p2)
	{
		char c = *p1;
		*p1 = *p2;
		*p2 = c;
		++p1;
		--p2;
	}
	return 0;
}
int  main(void)
{
	char buf[] = "abcdefg";   //buf[] 会在张栈上对全局区的字符串拷贝。
	inverse(buf);
	printf("buf:%s\n", buf);
	system("pause");
	return 0;
}

        这种模型是两个指针做分别指向字符串的开始和结尾,因为我们的buf是在栈上有内存,buf作为形参传入inverse函数的实参,我们可以在inverse函数内部,通过指针去修改buf的内存数据。

        

        如果我们将main函数改变内存模型就会改变.

int  main(void)
{
	char *p = "abcdefg";   //p只有在栈上拥有指针的内存,而没有字符串的内存。
	inverse(p);
	printf("buf:%s\n", p);
	system("pause");
	return 0;
}

        

        由内存模型可知由于是在全局区修改的字符串,因此会报错,程序荡机。

第二种:利用栈进行递归逆序

       栈是一种先进后出的内存模型,而我们的函数调用压栈模型也符合这一特点 函数调用的压栈模型因此我们可以将字符串的每一个字符利用函数压栈模型进行依次压栈

        掌握递归需要掌握两点:函数参数的入栈模型和函数调用的压栈模型。我们对下面代码的参数压栈模型个函数调用模型进行分析。

#define  _CRT_SECURE_NO_WARNINGS 
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

int inverse_stack(char *str1)
{
	if (str1 == NULL)  //递归结束的异常条件
	{
		return;
	}
	if (*str1 == '\0')  //递归结束的正常条件
	{
		return;
	}
	inverse_stack(str1 + 1);
	printf("%c", *str1);
}
int  main(void)
{
	char buf[] = "abcg";   //buf[] 会在栈上对全局区的字符串拷贝。
	inverse_stack(buf);
	system("pause");
	return 0;
}
        

        这个是函数实参str1指向字符g时的参数压栈模型。根据函数压栈模型来讲,当最后str1指向了字符'\0'时,最后一个压栈的函数会在if(str1 == '\0') {return;}语句块中结束函数,释放函数在栈上申请的内存,进入到倒数第二次压栈的函数(即图上的栈顶的函数),此时函数输出printf("%c",*str1)   (str1指向了‘g’),然后依次执行,直到栈上的内存被释放的只有main函数。

        

        函数的调用模型。


扫描二维码关注公众号,回复: 1373575 查看本文章

改进:将逆序的结果存入一个全局变量,并进行打印

#define  _CRT_SECURE_NO_WARNINGS 
#include <stdlib.h>
#include <string.h>
#include <stdio.h>


char g_buf[1024];

int inverse_stack(char *str1)
{
	if (str1 == NULL)  //递归结束的异常条件
	{
		return;
	}
	if (*str1 == '\0')  //递归结束的正常条件
	{
		return;
	}
	inverse_stack(str1 + 1);
	strncat(g_buf, str1, 1);
}
int  main(void)
{
	char buf[] = "abcg";   //buf[] 会在张栈上对全局区的字符串拷贝。
	memset(g_buf, 0, strlen(g_buf));
	inverse_stack(buf);
	printf("%s", g_buf);
	system("pause");
	return 0;
}

       在项目开发里面,如果这函数被多个线程所调用,因为这个函数使用了全局变量,所以会出现加锁与解锁的问题,也有可能会使多个程序相同一块内存空间拷贝数据,出现乱序的问题。

       我们需要避免这个问题。

改进:将逆序的结果存入一个临时变量,并进行打印

        
#define  _CRT_SECURE_NO_WARNINGS 
#include <stdlib.h>
#include <string.h>
#include <stdio.h>

int inverse_stack(char *str1,char *buf)
{
	if (str1 == NULL || buf == NULL)  //递归结束的异常条件
	{
		return;
	}
	if (*str1 == '\0')  //递归结束的正常条件
	{
		return;
	}
	inverse_stack(str1 + 1,buf);
	strncat(buf, str1, 1);
}
int  main(void)
{
	char buf[] = "abcg";   //buf[] 会在张栈上对全局区的字符串拷贝。
	char g_buf[1024] = {0};
	inverse_stack(buf,g_buf);
	printf("%s", g_buf);
	system("pause");
	return 0;
}
        局部变量做函数参数,因为函数的压栈模型的原因,我们的g_buf不会再inverse函数调用结束前被释放。

    

猜你喜欢

转载自blog.csdn.net/m0_37717595/article/details/80539957