从0开始学c语言-31-关于字符串的各种函数+内存函数+字符串旋转判断

本文详细介绍了C语言中常用的字符串函数,包括strlen、strcpy、strcat、strcmp等,并探讨了内存函数memcpy、memmove。此外,还讲解了字符串旋转判断的实现方法和递增二维数组的查找技巧,是C语言学习者的重要参考资料。
摘要由CSDN通过智能技术生成

上一篇:从0开始学c语言-30- 指针不练习?还真觉得自己会了~_阿秋的阿秋不是阿秋的博客-CSDN博客

目录

字符串

1. 函数介绍

strlen

strcpy

 strcat

 strcmp

strncpy

strncat

 strncmp

strstr

strtok

strerror

这个报错不如perror

字符分类函数:

 字符转换:

memcpy

memmove 

memcmp

 2. 库函数的模拟实现

模拟实现strlen

模拟实现strcpy

模拟实现strcat

模拟实现strstr

模拟实现strcmp

模拟实现memcpy

模拟实现memmove

3.其他函数

memcmp

memset

练习1:字符串旋转

左旋

判断

三步翻转法

左旋

判断

练习2:递增二维数组查找数字


字符串

C 语言中对字符和字符串的处理很是频繁,但是 C 语言本身是没有字符串类型的,字符串通常放在
常量字符串 中或者 字符数组 中。
字符串常量 适用于那些对它不做修改的字符串函数 .

1. 函数介绍

strlen

size_t strlen ( const char * str );
        1 - 字符串中 '\0' 作为结束标志, strlen 函数返回的是在字符串中 '\0' 前面出现的字符个数(不包含 '\0' )
        2 - 参数指向的字符串必须要以 '\0' 结束。
        3 - 注意函数的返回值为size_t ,是无符号的( 易错
int my_strlen(const char* start)
{
    assert(start);
	const char* end = start;
	while (*end++);
	return (end - start-1);
}

这是我们之前文章模拟实现strlen函数的代码成果,过程在文章从0开始学c语言-23-如何写出好(易于调试)的代码、模拟实现库函数:strcpy、strlen 、编程常见错误_阿秋的阿秋不是阿秋的博客-CSDN博客

思路都在上面这个文章里。

简单演示一下这个函数的作用

int main()
{
 const char*str1 = "abcdef";
 const char*str2 = "bbb";
 if(strlen(str2)-strlen(str1)>0)
 {
 printf("str2>str1\n");
 } 
 else
 {
 printf("srt1>str2\n");
 }
 return 0; }

strcpy

char* strcpy(char * destination, const char * source );
1 - Copies the C string pointed by source into the array pointed by destination, including the
terminating null character (and stopping at that point).
2 - 源字符串(source)必须以 '\0' 结束。
3 - 会将源字符串中的 '\0' 拷贝到目标空间。
4 - 目标空间必须足够大,以确保能存放源字符串。
5 - 目标空间(destination)必须可变

这是我们之前模拟函数strcpy的代码成果

char * strcpy(char * dst, const char * src) {
        char * cp = dst;
        assert(dst && src);
        while( *cp++ = *src++ )
               ;     /* Copy src over dst */
        return( dst );
}

思路在如下文章里从0开始学c语言-23-如何写出好(易于调试)的代码、模拟实现库函数:strcpy、strlen 、编程常见错误_阿秋的阿秋不是阿秋的博客-CSDN博客

这个函数的作用就是把source字符串拷贝到destination字符串中,且连\0都会拷贝过去。

 strcat

char * strcat ( char * destination, const char * source );
1 - Appends a copy of the source string to the destination string. The terminating null character in destination is overwritten by the first character of source, and a null-character is included at the end of the new string formed by the concatenation of both in destination.
2 - 源字符串必须以 '\0' 结束。
3 - 目标空间必须有足够的大,能容纳下源字符串的内容。
4 - 目标空间必须可修改。

这东西不能自己向后追加自己,因为\0的位置被代替了,所以没办法结束追加过程了。

 strcmp

int strcmp ( const char * str1, const char * str2 );
This function starts comparing the first character of each string. If they are equal to each
other, it continues with the following pairs until the characters differ or until a terminating
null-character is reached.
标准规定:
第一个字符串大于第二个字符串,则返回大于 0 的数字
第一个字符串等于第二个字符串,则返回 0
第一个字符串小于第二个字符串,则返回小于 0 的数字
注意:这函数比较的不是字符串长度,而是 比较对应位置字符的ASC码值。
例如:“ asd ”比“ f ”长,却小于f字符串,返回了一个小于0的数。

strncpy

char * strncpy ( char * destination, const char * source, size_t num );
Copies the first num characters of source to destination. If the end of the source C string
(which is signaled by a null-character) is found before num characters have been copied,
destination is padded with zeros until a total of num characters have been written to it.
拷贝 num 个字符从源字符串到目标空间。
如果源字符串的长度小于 num ,则拷贝完源字符串之后,在目标的后边追加 0 ,直到 num 个。

相比strncpy就是能指定拷贝多少字符串的区别了。

给你演示一下错误使用:

 destination字符串的空间不够大,要这么用。可以看到num大于source字符串长度的话并不会拷贝什么奇怪的东西,而是在目标的后边追加0,直到num个。

 函数实现过程

strncat

char * strncat ( char * destination, const char * source, size_t num );
Appends the first num characters of source to destination, plus a terminating null-character.
If the length of the C string in source is less than num, only the content up to the terminating null-character is copied.

加粗的地方是说,如果source的长度小于num,只追加到\0。

演示正常使用效果

 现在演示  source的长度小于num,只追加到\0。的效果

函数实现过程

 strncmp

int strncmp ( const char * str1, const char * str2, size_t num );
比较到 出现  和另一个字符不一样 或者 一个字符串结束 或者 num个字符全部比较完

 意思如图。

strstr

char * strstr ( const char *str1, const char * str2);
Returns a pointer to the first occurrence of str2 in str1, or a null pointer if str2 is not part of  str1.

也就是说,如果在str1中找到了str2就 返回 str1当中出现str2第一个字符的地址,没找到就返回空指针。

演示一下

可以看到即使str1和str2有部分相同也不行,必须是在 str1 中找到 str2的全部字符 才可以。

strtok

char * strtok ( char * str, const char * sep );
参数意思:
        sep参数是个字符串,定义了用作分隔符的字符集合 。第一个参数指定一个字符串,它包含了0 个或者多个由 sep 字符串中一个或者多个分隔符分割的标记。
返回值:
        strtok函数找到str中的下一个标记,并将其用 \0 结尾,保存这个标记的位置并返回一个开始查找标记位置的指针。(注: strtok函数会改变被操作的字符串,所以 在使用strtok函数切分的字符串一般都是临时拷贝的内容并且可修改 。)
参数NULL:
        strtok函数的第一个参数不为 NULL ,函数将找到 str 中第一个标记, strtok 函数将保存它在字符串中的位置。
        strtok函数的第一个参数为 NULL ,函数将在同一个字符串中被保存的位置开始,查找下一个标记。
如果字符串中不存在更多的标记(也就是找不到标记了),则返回 NULL 指针。

 所以strtok函数确实会改变被操作的字符串。

想打印全部分割内容就加个循环,传上NULL,让函数在同一个字符串中被保存的位置开始,查找下一个标记。

 代码如下。

int main()
{
	char* p = "zhangpengwei@bitedu.tech";
	const char* sep = ".@";
	char arr[30];
	char* str = NULL;
	strcpy(arr, p);//将数据拷贝一份,处理arr数组的内容
	for (str = strtok(arr, sep); str != NULL; str = strtok(NULL, sep))
	{
		printf("%s\n", str);
	}
}

strerror

char * strerror ( int errnum );
返回错误码,所对应的错误信息。
Get a system error message ( strerror) or prints a user-supplied error message ( _strerror).
#include <errno.h>//必须包含的头文件
int main()
{
	FILE* pFile;
	pFile = fopen("unexist.ent", "r");
	if (pFile == NULL)
		printf("Error opening file unexist.ent: %s\n", strerror(errno)); //必须有errno.h
	//errno: Last error number
	return 0;
}

上面这段代码就可以告诉我们出错误的原因是什么。但是参数是errno的话,必须要有头文件errno.h。

下面这段代码则不需要这个头文件就可以报错,只不过需要你自己输入数字。(且可以看到负数是不知道的错误)

这个报错不如perror

字符分类函数:

 试了几个,好像他们的返回值都是int。

 字符转换:

int tolower ( int c ); //转换为小写
int toupper ( int c ); //转换为大写

 注意代码包含的头文件。

#include <stdio.h>
#include <ctype.h>
int main()
{
	int i = 0;
	char str[] = "TEEESAJDI.\n";
	char str2[] = "Tjsajdisa.\n";
	char b,c;
	while (str[i])
	{
		c = str[i];
		if (isupper(c))
			c = tolower(c);
		putchar(c);
		i++;
	}
	i = 0;
	while (str2[i])
	{
		b = str2[i];
		if (islower(b))
			b = toupper(b);
		putchar(b);
		i++;
	}
	return 0;
}

memcpy

void * memcpy ( void * destination, const void * source, size_t num );

mem开头的这几个函数都是内存函数。

1 - 函数 memcpy source 的位置开始向后复制 num个字节的数据 destination 内存位置
2 - 这个函数在 遇到 '\0' 的时候并不会停下来
3 - 如果 source destination 有任何的重叠,复制的结果都是未定义的。(也就是说source和destination不能在内存中有重叠的地方,这种结果未定义。)
#include <stdio.h>
#include <string.h>
struct {
	char name[40];
	int age;
} person, person_copy;
int main()
{
	char myname[] = "Pierre de Fermat";
	//拷贝字符串到结构体person中
	memcpy(person.name, myname, strlen(myname) + 1);//+1是为了拷贝\0
	person.age = 46;
	//拷贝结构体person到person_copy中
	memcpy(&person_copy, &person, sizeof(person));//拷贝一个结构体的大小
	printf("person_copy: %s, %d \n", person_copy.name, person_copy.age);
	return 0;
}

拷贝成功了。

memmove 

void * memmove ( void * destination, const void * source, size_t num );
memcpy 的差别就是 memmove 函数处理的源内存块和目标内存块是可以重叠的
如果源空间和目标空间出现重叠,就得使用 memmove 函数处理。
注意:num的单位是字节。

 如果你用这个代码,把memmove改为memcpy发现也可以重叠拷贝,难道我在骗你?

不,memcpy只要实现不重叠拷贝就可以了,只不过vs中的这个memcpy既可以重叠拷贝,又可以不重叠拷贝,是个发育超常的函数。

memcmp

int memcmp ( const void * ptr1, 
             const void * ptr2, 
             size_t num );

比较从ptr1ptr2指针开始的num个字节

返回>0,则ptr1>ptr2

返回<0,则ptr1<ptr2

返回<0,则ptr1=ptr2

和strcmp一样是比较对应字符的ASC码值的,只不过这个是以字节为单位进行比较,且不止可以比较字符串,因为参数是空指针,便可以接收任何类型的指针。

 

 2. 库函数的模拟实现

模拟实现strlen

具体已经在之前的文章说过思路,这里不再细说。

只介绍三种方式。

1·指针指向元素,如果指向的元素不是\0,就count++,返回count。

//计数器方式
int my_strlen(const char * str) {
 int count = 0;
 while(*str)
 {
 count++;
 str++;
 }
 return count; }

2·使用函数递归方式,指向元素为\0就返回0,不为\0就返回1(一个长度)+ my_strlen(str+1)(指针向后+1作为参数传回去strlen函数)

//不能创建临时变量计数器
int my_strlen(const char * str) {
 if(*str == '\0')
 return 0;
 else
 return 1+my_strlen(str+1);
}

3·指针-指针=指针之间的元素个数。指针不等于\0就继续向后挪动,直到指针向后挪动到\0的位置便停下来,指向\0的指针减去一开始的指针便是字符串长度。

//指针-指针的方式
int my_strlen(char *s) {
       char *p = s;
       while(*p != ‘\0’ )
              p++;
       return p-s; }

模拟实现strcpy

这个函数之前也写过思路了,这里不再介绍。

注意while判断条件中的意思,如果*src指向\0,那么这个表达式的结果就是0,判断条件为假,跳出循环,且执行后置++的操作,完成拷贝。

1.参数顺序
//2.函数的功能,停止条件
//3.assert
//4.const修饰指针
//5.函数返回值
//6.题目出自《高质量C/C++编程》书籍最后的试题部分
char *my_strcpy(char *dest, const char*src)
{ 
 char *ret = dest;
 assert(dest != NULL);
assert(src != NULL);
 
 while((*dest++ = *src++))
 {
 ;
 }
 return ret; }

模拟实现strcat

这个函数是用来追加字符串的,那么想要让str指向的字符串追加到dest中,就要先找到dest当中\0字符的位置,所以我写了while(*dest++);语句,等跳出循环的时候,dest指针指向\0字符后面的位置,所以需要把指针-1挪到\0的位置。

这时候我们找到了dest当中\0的位置,可以开始进行追加字符串的操作了,其实就相当于拷贝,所以我写了while (*dest++ = *str++);语句来实现追加字符串的操作,最后返回dest最开始的位置。

char* my_strcat(char* dest, const char* str)
{
	assert(dest && str);
	char* ret = dest;
	while (*dest++);
	dest -= 1;
	while (*dest++ = *str++);
	return ret;
}
int  main()
{
	char arr1[88] =  "i love " ; //[ ] 中必须有常量,否则strcat会报错
	//因为不加足够大的常量的话,后续追加字符串会没有访问权限
	char arr2[] = "you." ;
	printf("%s\n",my_strcat(arr1, arr2));
	/*my_strcat(arr1, arr1);*/ //这样是不行的,\0被覆盖了
	return 0;
}

模拟实现strstr

这玩意有个东西需要学,KMP算法,不过我还没学,后续有时间再学吧。

char *  strstr (const char * str1, const char * str2)

首先我们要清楚strstr函数的功能,是从str1当中找到str2完整的字符串,然后返回str1当中第一次出现str2完整字符串的开头地址。

比如我们从下面这个图中找fhg。当找到str1中第一次出现str2字符的位置时,我们就需要留一个指针标记这个位置,作为我们未来函数strstr的返回值。紧接着str1和str2的指针都向后移动,我们发现并不相等了,也就是str1中的g不等于str2中的h。

既然str1和str2现在指向的元素不相等了,那么我们需要str2当中的指针返回到开头的位置。因为我们要从str1中找到完整的str2字符串,既然已经有一个不一样了,那么就需要重新返回去开头位置进行对比,寻找下一个str1中相等的位置。

str1从字符g继续向后挪动,发现 f 又和str2中的字符 f 相等,那么我们需要更新上次标记的位置,把那个指针更新到现在的 f 位置。然后str1和str2当中的指针继续向后挪动,此时我们对比了fgh都相等,那么怎么结束对比字符的循环呢?我们以str2中\0为判断条件,如果str2中的指针指向\0说明,已经在str1中找到了完整的str2字符串,此时我们返回str1中第一次出现str2完整字符串的开头位置,也就是str1中第二个f的位置。

到此,我们的strstr函数完成了寻找的工作。这是找到了的情况,如果没找到,那便返回一个空指针。

然后就写出来了。

char* my_strstr(const char* str1, const char* str2)
{
	//验证是否为空指针
	assert(str1 && str2);
	if ((*str1 == '\0')&& (*str2 == '\0'))
	{
		return  (char*)str1;
	}
	const char* s1,*s2;
	while (*str1)
	{
		s1 = str1;
		s2 = str2;
		//当s1和s2不是\0空字符且s1和s2相等的时候
		//s1和s2向后挪进行对比
		while (*s1 && *s2 && (*s1 == *s2))
		{
			s1++;
			s2++;
		}
		//跳出循环
		//1·在s1中找到了,此时s2=‘\0'
		if (*s2 == '\0')
		{
			return (char*)str1;
			//因为你自己规定了函数的返回类型是char*
		}
        //2·没找到,让返回的指针向后挪继续对比
		str1++;
	}
	//跳出循环意味着str1是指向\0的
	//没找到
	return NULL;
}
int main()
{
	char arr1[] = "sfgfhgfh";
	char arr2[] = "fhg";
	printf("%s\n",my_strstr(arr1, arr2));
	return 0;
}

库函数中的实现过程样子

模拟实现strcmp

(字符串没办法用大小号比较的原因是,字符串直接用这个比较的话,比较的是地址)

我们知道strcmp是比较字符串对应位置的ASCII码值,那首先就要找到两个字符串的对应位置,让这两个位置的ASCII码值进行比较,如果相等就把指针向后挪一步,继续比较,直到有一方大或者小,然后返回一个>0或者<0的值。

这里先放上图,以防你看不懂后面代码的意思。

 上面这段话的意思是让你知道两个字符相减的结果是什么(就是ASC码值相减)。(这里别和指针-指针=指针之间的元素个数弄混, 这个等于元素个数的前提是指向同一块区域的地址。)

//strcmp比较的就是字符串每个对应字符的ASCII 码值
//比较的不是长度,是字符串大小

int my_strcmp(char* s1, char* s2)
{
	while (*s1 == *s2)
	{
		if (*s1 == '\0')
		{
			return 0;
		}
		s1++;
		s2++;
	}
	/*if (*s1 > *s2)
		return 1;
	else
		return -1;
	*/
	return *s1 - *s2;
}
int main()
{
	printf("%d\n",my_strcmp("s", "asd"));
	return 0;
}

下面这段代码更为精简。不过思路是一样的。

要搞清楚跳出循环来到return的过程,想要跳出循环

1·两个比较的字符不相等

2·dst字符为空字符也就是\0的时候会跳出来(意味着之前的字符都相等)

int my_strcmp (const char * src, const char * dst) {
        int ret = 0 ;
 assert(src != NULL);
   assert(dst != NULL);
        while( ! (ret = *(unsigned char *)src - *(unsigned char *)dst) && *dst)
                ++src, ++dst;
        if ( ret < 0 )
                ret = -1 ;
        else if ( ret > 0 )
                ret = 1 ;
        return( ret );
}

还可以把 if 和 else if 和 return 当中的句子写成这段

return ((-ret)<0)-(ret<0);

 所以说,这个()里的其实就是判断真假的表达式,为真是1,为假是0,然后相减就能得到我们想要的值。

模拟实现memcpy

这函数是copy内存中的内容。实际上和strcpy差不多。只不过函数结束是用字节来限制的。

void * memcpy ( void * dst, const void * src, size_t count) {
        void * ret = dst;
        assert(dst);
        assert(src);
        /*
         * copy from lower addresses to higher addresses
         */
        while (count--) {
                *(char *)dst = *(char *)src;
                dst = (char *)dst + 1;
                src = (char *)src + 1;
       }
        return(ret);
}

这是库函数里的样子,下面是第一个是我自己写的,第二个是改进了库函数的。

void* my_memcpy1(void* dest, const void* str, size_t num)
{
	assert(dest && str);
	char* p1 = (char*)dest;
	const char* p2 = (const char*)str;
	while (num--)
		*p1++ = *p2++;
	return dest;
}

void* my_memcpy2(void* dest, const void* str, size_t num)
{
	assert(dest && str);
	void* ret = dest;
	while (num--)
	{
		/**(char*)dest = *(const char*)str;
		dest = (char*)dest + 1;
		str = (const char*)str + 1;*/
		// *(char*)dest++ = *(char*)str++;
		//后置++优先级高于char*的强制类型转换
		//所以先后置++,而空指针不能进行++
//这样写没问题
		*((char*)dest)++ = *((char*)str)++;
	}
	return ret;
}

模拟实现memmove

因为memmove在拷贝重叠区域的数据,便需要判断如何进行拷贝才不会覆盖原有的数据,还完全拷贝过去。

就像下面这样,如果从前向后进行拷贝,因为有重叠区,那么后面重叠区域的数据会被覆盖,没办法完全拷贝过去,所以我们从后向前拷贝,重叠区域的数据就不会被覆盖。

src是红色框起来的区域,那么便需要考虑src和dest不同位置的情况需要怎么拷贝的问题

绿色的代表dest,

如果dest在src前,从前向后拷贝,

如果src在dest前,从后向前拷贝。

至于为什么这么分类,是为了避免重叠区域拷贝被覆盖的情况,不理解的话自己画图就能看出来

#include <assert.h>
void* my_memmove(void* dest, const void* src, size_t num)
{
	assert(dest && src);
	void* ret = dest;
	if (dest < src)
	{
		//前向后
		while (num--)	
			*((char*)dest)++ = *((char*)src)++;
	}
	else 
	{
		//后向前
		while (num--)//如果num=20,判断是20为真
			//第一次进入循环后是19
			//因为和最后一个差19字节
			*((char*)dest + num) = *((const char*)src + num);
	}
	return ret;
}

3.其他函数

memcmp

memset

int main()
{
	//以字节为单位来设置内存
	int arr[] = { 1.0,2.0,2.0 };
	memset(arr, 1, 20);
	//把arr中前20个字节设置为01
	return 0;
}

练习1:字符串旋转

写一个函数,判断一个字符串是否为另外一个字符串旋转之后的字符串。

例如:

给定 s1 =AABCD 和 s2 = BCDAA,返回1

给定 s1=abcd 和 s2=ACBD,返回0.

AABCD 左旋一个字符得到 ABCDA

AABCD 左旋两个字符得到 BCDAA

左旋

首先写了一个让字符串自己左旋的函数

其实你会发现,如果字符串有5个,你左旋4个就相当于右旋1个,所以实际上左旋就包含了所有旋转情况。

void str_lfmove(char* arr, int num)
{
	int n = strlen(arr);
	while (num)
	{
		//1·拿出来一个字符
		char tmp = *arr;
		//2·剩下n-1个字符向前挪(被拿掉的第一个字符就是下面判断条件里被剪掉的1
		int i = 0;
		for (i = 0; i< n - 1; i++)
		{
			*(arr + i) = *(arr + i + 1);
		}
		//3·把拿出来的字符放到最后一个
		*(arr + n - 1) = tmp;
		num--;
	}
}
int main()
{
	char arr[10] = "ASDFGHJKL";
	int num;
	scanf("%d", &num);
	str_lfmove(arr, num);
	printf("%s\n", arr);
	return 0;
}

判断

现在加入一个字符数组对比,判断是否旋转了

int judge_move(char* str1, char* str2)
{
	assert(str1 && str2);
	int len1 = strlen(str1);
	int len2 = strlen(str2);
	if (len1 == len2)
	{
		int num = len1;
		while (num)
		{
			//1·拿出来一个字符
			char tmp = *str1;
			//2·剩下n-1个字符向前挪(被拿掉的第一个字符就是被剪掉的1
			int i = 0;
			for (i = 0; i < len1 - 1; i++)
			{
				*(str1 + i) = *(str1 + i + 1);
			}
			//3·把拿出来的字符放到最后一个
			*(str1 + len1 - 1) = tmp;
            //4·进行判断
			if (strcmp(str1, str2))
			{
				return 1;
			}
			num--;
		}
	}
	return 0;
}
int main()
{
	char arr1[10] = "ASDFGHJKL";
	char arr2[10] = "DFGHJKLAS";
	if (judge_move(arr1, arr2))
	{
		printf("是");
	}
	else
		printf("不是");
	return 0;
}

三步翻转法

然后改善了方法,分为这三步:

左边逆序,右边逆序,整体逆序

 AB是需要左旋的字符个数。

左旋

这是一个字符数组左旋的代码

以要左旋的n个字符为界限
//左边逆序,右边逆序,整体逆序
//如果输入超出字符串长度,这个三步翻转的方法有bug。

//翻转left到right指针内的元素
void reverse(char* left, char* right)
{
	assert(left && right);
	while (left < right)
	{
		char tmp = *left;
		*left = *right;
		*right = tmp;
		left++;
		right--;
	}
}
//确定上面那个函数的范围,并传参过去
void str_lfmove(char* arr, int num)
{
	assert(arr);
	int n = strlen(arr);
	reverse(arr,arr+num-1); //左边逆序
	reverse(arr+num,arr+n-1); //右边逆序
	reverse(arr,arr+n-1);  //整体逆序
}
int main()
{
	char arr[10] = "ASDFGHJKL";
	int num;
	scanf("%d", &num);
	str_lfmove(arr, num);
	printf("%s\n", arr);
	return 0;
}

判断

现在以上面代码为基础我们把字符串后面再加上原本自己的字符串,然后从前向后比较就能找到是否是字符串旋转后的样子。

如图。 

//使用在原有字符串后面加一个自己的copy版本字符串来判断
//是否为左旋后的字符串(因为加一个之后就包含了所有旋转的可能
int judge_move(char* str1, char* str2)
{
	if (strlen(str1) != strlen(str2))
		return 0;

	//1·在str1后加自己的copy字符串
	int len = strlen(str1);
	strncat(str1, str1, len);
	
	//2·判断能否在接续后的字符串里找到str2
	char* ret = strstr(str1, str2);
	return ret != NULL;
	//如果ret!=Null为真,返回1,为假则返回0
	//不等于空指针说明找到了
}

int main()
{
	char arr1[20] = "ASDFG"; //注意预留空间
	char arr2[] = "DFGAS";
	if (judge_move(arr1, arr2))
	{
		printf("SHI\n");
	}
	else
		printf("BUSHI\n");
	printf("%s\n", arr1);
	//arr1的字符串内容被改变了。
	return 0;
}

练习2:递增二维数组查找数字

// 画图排除一行或者一列的数组
// 因为右上角和最后列的数据是最大的
int search(int arr[][3], int r, int c, int k)
{
	int x = 0;
	int y = c - 1;
	while (x < r && y >= 0)
	{
		if (arr[x][y] < k)
		{
			x++;
		}
		else if (arr[x][y] > k)
		{
			y--;
		}
		else
			return 1;
	}
	return 0;
}
int main() 
{
	int arr[3][3] = { 1,2,3,4,5,6,7,8,9};
	int key = 4;
	printf("%d\n",search(arr, 3, 3, key));
	return 0;
}

但是上面这个没有带回来下标,下面这段代码更完善

int search(int arr[][3], int*px, int*py, int k)
{
	int x = 0;
	int y = *py - 1;
	while (x < *px && y >= 0)
	{
		if (arr[x][y] < k)
		{
			x++;
		}
		else if (arr[x][y] > k)
		{
			y--;
		}
		else
		{
			*px = x;
			*py = y;
			return 1;
		}
	}
	return 0;
}
int main()
{
	int arr[3][3] = { 1,2,3,4,5,6,7,8,9 };
	int key = 9;
	int x = 3;
	int y = 3;
	//通过&x和&y来传递给函数需要的值
	// 再带回来需要的值
	//0是没找到,1是找到了
	if (search(arr, &x, &y, key))
		printf("下标是%d %d\n", x, y);
	else
		printf("没有找到");
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值