C语言(二)字符数组、字符串、字符指针及字符串常用操作

版权声明:本文为博主原创文章,未经博主允许不得转载。 https://blog.csdn.net/qq_40818798/article/details/86572546

目录

一、字符数组初始化 

二、数组名不允许自加自减

三、字符串操作内存示意图

四、字符串拷贝函数

五、求字符串中某一子串出现的次数

六、删除给定字符串中的空格

方式1:当字符不为结束符时,从头到尾扫描,遇非空格则拷贝(可删除字符串中所有空格)

方式2:当字符不为结束符时,i从头扫描,遇空格则i++;j从尾扫描,遇空格则j--。最终确定字符串长度,一次性拷贝(只能删除非空格字符串前和后的空格,不能删除出现在字符串中间的空格) 

 七、分离给定字符串(奇偶位分开)

八、字符串反转

方式1:利用递归和栈模型实现(全局变量:不用传参,多线程时可用性差;递归局部变量:传参,通用性强)

方式2:双向扫描交换首尾,直到begin与end相等

九、键值对——分离有用字符串+去空格串


一、字符数组初始化 

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
#define MAXSIZE 1000
int main()
{
	char a[MAXSIZE] = { '1','a','2','b' };//1数组指定长度,2用字符初始化,3会自动补'\0'以结束
	char b[] = { '1','a','2','b' };	//1数组不指定长度,2用字符初始化,3不以'\0'结束
	char c[] = "1233456546";//1数组不指定长度,2用字符串初始化,3自动补'\0'结束
	char d[MAXSIZE] = "1233456546";//1数组指定长度,2用字符初始化,3自动补'\0'结束
	//char e[2] = "fsdf"; //直接报错,长度非法
	char f[2] = "fs"; //不会报错,但不自动添加'\0',因为没有空间
	printf("strlen(a):%d\tsizeof(a):%d\ta:%s\n", strlen(a), sizeof(a), a);
	printf("strlen(b):%d\tsizeof(b):%d\tb:%s\n", strlen(b), sizeof(b), b);
	printf("strlen(c):%d\tsizeof(c):%d\tc:%s\n", strlen(c), sizeof(c), c);
	printf("strlen(d):%d\tsizeof(d):%d\td:%s\n", strlen(d), sizeof(d), d);
	printf("strlen(f):%d\tsizeof(f):%d\td:%s\n", strlen(f), sizeof(f), f);
	return 0;
}
  • strlen()——C语言string.h中的函数,遇'\0'截止,但统计长度并不包括'\0',只统计非'\0'的字符个数

  • sizeof()——C语言运算符,计算()内的变量所属数据类型所占内存的字节数

  1.  sizeof(a):1000
     sizeof(b):4
     sizeof(c):11
     sizeof(d):1000   
     
  2. a d为指定长度数组,故统计结果为数组长度1000;
  3. b以省略长度方式书写,编译器将初始化的字符个数指定为其长度,故sizeof(b)=4;
  4. c以省略长度方式书写,字符串方式初始化,末尾自动追加'\0',统计时包含该'\0',故sizeof(c)=11

二、数组名不允许自加自减

#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
	char b[] = { '1','a','2','b' };	
	b++;//非法操作
        b--;//非法操作
	return 0;
}
  • error C2105: '++' needs l-value
  • 原因:数组名代表数组的首地址(而非整个数组的地址),一旦定义,则不允许修改其值(常指针):在main函数执行完成,操作系统将释放内存。如果更改值,使他指向其他地方,则释放内存必然出错。故为保证释放的内存安全,数组首地址不允许改变
  • 如何更改?定义一指针变量p,p指向数组首地址b,通过p来访问数组b。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int main()
{
	char b[] = { '1','a','2','b' };	
	char *p = NULL;
	p = b;
	p++;
	return 0;
}

三、字符串操作内存示意图

四、字符串拷贝函数

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/*
src 源字符串
dst 目标地址
*/
int str_copy1(char *dst, char *src)
{
	for (; *src != '\0'; src++, dst++)
	{
		*dst = *src;
	}
	*dst = '\0';
	return 0;
}
int str_copy2(char *dst, char *src)
{
	for (; *src != '\0';)
	{
		*dst++ = *src++; // *dst = *src, dst++, src++
	}
	*dst = '\0';
	return 0;
}
int str_copy3(char *dst, char *src)
{
	// src: "1234567\0"
	// dst:  1234567\0
	for (; (*dst = *src) != '\0'; )
	{
		src++;
		dst++;
	}
	return 0;
}
int str_copy4(char *dst, char *src)
{
	//	for (; (*dst++ = *src++););
	while ((*dst++ = *src++));
	return 0;
}
int str_copy5(char* const dst, char* const src)
{
	//传址调用时,不要轻易改变形参指向,可引入一辅助指针变量,将形参值接过来
	char* tmpdst = dst;//1
	char* tmpsrc = src;//2
	if (tmpdst == NULL || tmpsrc == NULL)	//增加判断,防止向(从)空地址拷贝字符
		return -1;
	while ( *tmpdst++ = *tmpsrc++ );
	printf("%s\n", dst);//如果没有1 2 直接修改指针所指内容,会出错。
	printf("%s\n", src);//如果没有1 2 直接修改指针所指内容,会出错。
	return 0;
}
//    0x00000000 ---> NULL  --->  0 
//    '\0' --->  0      
//    '0' ---> 48
int main(void)
{
	char *str = "123456789";
	char dst[128] = { 0 };
	//char *dst = NULL;

	if( str_copy5(dst, str) )
		printf("str_copy5(dst, str) error!\n");

	printf("dst:%s\n", dst);
	return 0;
}
  • NULL  --->  0 
  • '\0' --->  0      
  • '0' ---> 48

五、求字符串中某一子串出现的次数

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

//strstr(母串, 子串)
//统计 子串在母串的个数
int get_sub_str_count(char *src, char *sub_str)
{
	char *p = src;
	int cnt = 0;
	if (src == NULL || sub_str == NULL) 
	{
		fprintf(stderr, "(src == NULL || sub_str == NULL\n");
		return -1;
	}
	while ((p = strstr(p, sub_str)) != NULL)
	{
		//找到了子串
		cnt++;
		p += strlen(sub_str);
		if (*p == '\0')
			break;
	}
	return cnt;
}
int get_sub_str_count2(char *src, char *sub_str, int *cnt_p)
{
	char *p = src;
	int cnt = 0;
	if (src == NULL || sub_str == NULL) 
	{
		fprintf(stderr, "(src == NULL || sub_str == NULL\n");
		return -1;
	}
	while ((p = strstr(p, sub_str)) != NULL)
	{
		//找到了子串
		cnt++;
		p += strlen(sub_str);
		if (*p == '\0')
			break;
	}
	*cnt_p = cnt;
	return 0;
}

int main(void)
{
	char *str = "21321321312312itcaste21jdisaodjaitcastu34jsioadjitcastdjsaiodjaitcast123itcast";
	char *sub_str = "itcast";
	int cnt = 0;

	cnt = get_sub_str_count(str, sub_str);
	if (cnt < 0) 
	{
		fprintf(stderr, "get_sub_str_count err\n");
		return -1;
	}

	printf("cnt  = %d\n", cnt);

	cnt = 0;

	if (get_sub_str_count2(str, sub_str, &cnt) < 0) 
	{
		fprintf(stderr, "get_sub_str_count2 err\n");
		return -1;
	}
	printf("cnt  = %d\n", cnt);
	return 0;
}

#if 0
int main(void)
{
	char *str = "21321321312312itcaste21jdisaodjaitcastu34jsioadjitcastdjsaiodjaitcast123itcast";
	char *sub_str = "itcast";

	char *p = str;
	int cnt = 0;

	while ((p = strstr(p, sub_str)) != NULL)
	{
		//找到了子串
		cnt++;
		p += strlen(sub_str);
		if (*p == '\0') {
			break;
		}
	}

	printf("cnt = %d\n", cnt);

	return 0;
}
#endif

#if 0
//查找子串 do-while
int main(void)
{
	char *str = "21321321312312itcaste21jdisaodjaitcastu34jsioadjitcastdjsaiodjaitcast123";
	//                                                 ↑
	char *sub_str = "itcast";
	char *p = NULL;

	int cnt = 0; //统计的个数
	p = str;
	//do -while
	do {
		p = strstr(p, sub_str);
		if (p != NULL) {
			//找到了一个
			cnt++;
			p++;
		}
	} while (p != NULL);

	printf("cnt = %d\n", cnt);

	return 0;
}
#endif

六、删除给定字符串中的空格

  • 有一个字符串开头或结尾含有n个空格(”   abcdefgdddd    ”),欲去掉前后空格,返回一个新字符串。
  • 要求1:请自己定义一个接口(函数),并实现功能;
  • 要求2:编写测试用例。
  • 提示:int trimSpace(char *inbuf, char *outbuf);

方式1:当字符不为结束符时,从头到尾扫描,遇非空格则拷贝(可删除字符串中所有空格)

#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int trimSpace(char* const inbuf, char* const outbuf)
{
	char *tmpsrc = inbuf;	//源串
	char *tmpdec = outbuf;	//目的串
	if (tmpsrc == NULL || tmpdec == NULL)
	{
		printf("函数trimSpace()中(tmpsrc == NULL || tmpdec == NULL)运行出错!\n");
		return -1;
	}	
	while ( (*tmpsrc) != '\0' )
	{
		if( (*tmpsrc) != ' ' )
			*tmpdec++ = *tmpsrc;
		tmpsrc++;
	}
	*tmpdec = '\0';
	return 0;
}
int main()
{
	char *src = "   abcdefgdddd    ";
	char *dec = (char*)malloc(sizeof("   abcdefgdddd    "));
	if (dec == NULL)
	{
		printf("申请内存失败!\n");
		return 0;
	}
	printf("源串:%s!\n", src);	//为明显在末尾加一!
	if (trimSpace(src, dec))
	{
		printf("trimSpace(src, dec) execute error!\n");
	}
	printf("结果:%s!\n", dec);	//为明显在末尾加一!
	if (dec != NULL)	//释放堆内存
	{
		free(dec);
		dec = NULL;
	}
	return 0;
}

方式2:当字符不为结束符时,i从头扫描,遇空格则i++;j从尾扫描,遇空格则j--。最终确定字符串长度,一次性拷贝(只能删除非空格字符串前和后的空格,不能删除出现在字符串中间的空格) 

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>

int trimSpace(char *inbuf, char *outbuf)
{
	int i = 0;
	int j = 0;
	int len = 0;

	if (inbuf == NULL || outbuf == NULL) {
		fprintf(stderr, " (inbuf == NULL || outbuf == NULL)\n  ");
		return -1;
	}

	j = strlen(inbuf) - 1;

	//左边开始遍历
	while (isspace(inbuf[i]) && inbuf[i] != '\0') 
		i++;
	//右边
	while (isspace(inbuf[j]) && j > i) 
		j--;
	len = j - i + 1;

	strncpy(outbuf, inbuf + i,len);
	outbuf[len] = '\0';

	return 0;
}

int main(void)
{
	char *str = "   abcdefgdddd   ";
	char buf[128] = { 0 };

	if (trimSpace(str, buf) < 0) 
		return -1;

	printf("buf: [%s]\n", buf);

	return 0;
}

 七、分离给定字符串(奇偶位分开)

  • 有一个字符串”1a2b3d4z”,
  • 要求写一个函数实现如下功能:
  • 功能1:把偶数位字符挑选出来,组成一个字符串1.
  • 功能2:把奇数位字符挑选出来,组成一个字符串2.
  • 功能3:把字符串1和字符串2,通过函数参数,传送给main,并打印。
  • 功能4:主函数能测试通过。
  • int getStr1Str2(char *souce, char *buf1, char *buf2);
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int getStr1Str2(char* const souce, char* const buf1, char* const buf2)
{
	char *tmpsrc = souce;	//源串
	char *tmpdec1 = buf1;	//目的串1
	char *tmpdec2 = buf2;	//目的串2
	int flag = 0;//判断奇偶 0为偶 1为奇
	if (souce == NULL || buf1 == NULL || buf2 == NULL)
	{
		printf("函数getStr1Str2()中(souce == NULL || buf1 == NULL || buf2 == NULL)运行出错!\n");
		return -1;
	}	
	while ( (*tmpsrc) != '\0' )
	{
		if (flag == 0)
		{
			*tmpdec1++ = *tmpsrc++;
			flag = 1;
		}
		if (flag == 1)
		{
			*tmpdec2++ = *tmpsrc++;
			flag = 0;
		}	
	}
	*tmpdec1 = '\0';
	*tmpdec2 = '\0';
	return 0;
}
int main()
{
	char *src = "a1b2c3d4e5f6g7h8i9";
	char *dec1 = (char*)malloc(sizeof("   abcdefgdddd    "));
	char *dec2 = (char*)malloc(sizeof("   abcdefgdddd    "));
	if (dec1 == NULL || dec2 == NULL)
	{
		printf("申请内存失败!\n");
		return 0;
	}
	printf("源串:%s\n", src);
	if (getStr1Str2(src, dec1, dec2))
	{
		printf("getStr1Str2(src, dec1, dec2) execute error!\n");
	}
	printf("奇数串:%s\n", dec1);	
	printf("偶数串:%s\n", dec2);	
	if (dec1 != NULL)	//释放堆内存
	{
		free(dec1);
		dec1 = NULL;
	}
	if (dec2 != NULL)	//释放堆内存
	{
		free(dec2);
		dec2 = NULL;
	}
	return 0;
}

八、字符串反转

方式1:利用递归和栈模型实现(全局变量:不用传参,多线程时可用性差;递归局部变量:传参,通用性强)

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
/*不使用全局变量*/
int inverse2(char *src, char *outbuf)  //outbuf = outbuf
{
	if (src == NULL || outbuf == NULL) 
		return -1;
	if (*src == '\0') 
		return 0;
	inverse2(src + 1, outbuf);
	strncat(outbuf, src, 1);
	return 0;
}
/*使用全局变量*/
char g_buf[128] = { 0 };
//倒叙打印str字符串
int inverse(char *str)
{
	if (str == NULL) 
		return -1;
	if (*str == '\0') 
		return 0;
	inverse(str + 1);//bcdefg

	//printf("%c", *str);
	strncat(g_buf, str, 1);
	
	return 0;
}
int main(void)
{
	char str[] = "abcdefghi";
	char out_buf[128] = { 0 };

	inverse(str); //abcdefg
	printf("g_buf : %s\n", g_buf);
	//printf("str : %s\n", str);
	inverse2(str, out_buf);
	printf("out_buf : %s\n", out_buf);

	return 0;
}

方式2:双向扫描交换首尾,直到begin与end相等

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int inverse(char *str)
{
	char *begin = str;
	char *end = str + strlen(str) - 1;
	char tmp = 0;
	if (str == NULL) 
        {
		fprintf(stderr, " str == NULL\n");
		return -1;
	}
	while (end > begin) 
        {
		tmp = *end;
		*end = *begin;
		*begin = tmp;
		begin++;
		end--;
	}
	return 0;
}

int main(void)
{
	char str[] = "abcdefghi";
	char out_buf[128] = { 0 };

	inverse(str); //abcdefg
	printf("g_buf : %s\n", g_buf);
	//printf("str : %s\n", str);
	inverse2(str, out_buf);
	printf("out_buf : %s\n", out_buf);

	return 0;
}

九、键值对——分离有用字符串+去空格串

  • 键值对("key = valude")字符串,在开发中经常使用;
  • 要求1:请自己定义一个接口,实现根据key获取valude;
  • 要求2:编写测试用例。
  • 要求3:键值对中间可能有n多空格,请去除空格
  • 注意:键值对字符串格式可能如下:
  1. "key1 = valude1"
  2. "key2 = valude2        "
  3. "key3 =       valude3      "
  4. "key4 = v a l u d e4  "
  • 提示
int getKeyByValude(char* keyvaluebuf, char* keybuf, char* valuebuf, int* valuebuflen);
int main()
{
    getKeyByValude("key1 = valude1", "key1", buf, &len);
}
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
int trimSpace(char* const inbuf, char* const outbuf)
{
	char *tmpsrc = inbuf;	//源串
	char *tmpdec = outbuf;	//目的串
	if (tmpsrc == NULL || tmpdec == NULL)
	{
		printf("函数trimSpace()中(tmpsrc == NULL || tmpdec == NULL)运行出错!\n");
		return -1;
	}	
	while ( (*tmpsrc) != '\0' )
	{
		if( (*tmpsrc) != ' ' )
			*tmpdec++ = *tmpsrc;
		tmpsrc++;
	}
	*tmpdec = '\0';
	return 0;
}
int getKeyByValude(char *keyvaluebuf, char *keybuf, char *valuebuf, int* valuebuflen)
{
	char *p;
	if(NULL	== keyvaluebuf || NULL == keybuf || NULL == valuebuf || NULL == valuebuflen)
	{
		return -1;
	}
	//查看源串中是否有键
	p = strstr(keyvaluebuf, keybuf);
	if (p == NULL)
		return -1;
	//检查等号
	p = strstr(keyvaluebuf, "=");
	p++;
	//删除值中左右空格
	trimSpace(p, valuebuf);
	*valuebuflen = strlen(valuebuf);

	return 0;
}
int main()
{
	char keyvaluebuf[] = "key3 =       valude3      ";
	char keybuf[] = "key3";
	char valuebuf[128];
	int valuebuflen = 0;;
	getKeyByValude(keyvaluebuf, keybuf, valuebuf, &valuebuflen);
	printf("源串:%s\n", keyvaluebuf);
	printf("键:%s\n", keybuf);
	printf("值:%s\n", valuebuf);
	printf("值长:%d\n", valuebuflen);
	return 0;
}

猜你喜欢

转载自blog.csdn.net/qq_40818798/article/details/86572546