C语言.字符串,及string.h初步应用

一、字符
字符是用单引号 ’ ’ 括起来的单个普通字符或转义字符。

例:char c='A'; char c='\n';

二、字符串
在 C 语言中,字符串实际上是使用 null 字符 ‘\0’ 终止的“一维字符数组”(本质!)。

三、字符数组
下面的声明和初始化创建了一个 “Hello” 字符串。

例子: char A[10];
//字符数组的赋值方法,三种
赋值: char A[10] = {'h','e','l','l','o'};  --> 后面没有赋值的成员的值都是0
       char A[10] = {"hello"};-->等价于{'h','e','l','l','o','\0'}    (本质)
       char A[10] = "hello";

注意:
1)整型不需要使用任何符号,字符使用单引号’’,字符串使用""。
2)重点:字符数组初始化后不能整体赋值!

四、字符指针
整型指针 --> 指向内容: int
二级指针 --> 指向内容: 指针
数组指针 --> 指向内容: 数组
函数指针 --> 指向内容: 函数
字符指针 --> 指向内容: char

例子:
char a = ‘h’;
char *p = &a; --> p就是字符指针 --> 指向某个字符

char *p = "hello";  --> 不是把整个字符串拷贝到指针变量,指针变量永远只能存放指针/地址

五、char*p="hello"和char p[]="hello"的区别

首先“hello”在程序开启的时候放在了内存的.rodata段,是一个常量区,是一个only-read只读区域。

char *p=“hello”是将’h’的地址赋给指针p,即p指向了常量区‘h’的地址。
char p[]="hello"是将常量区中的"hello"拷贝到数组p[]中。

其在内存中的情况如下:
C语言.字符串,及string.h初步应用_第1张图片

例:
//例如,我们试图将字符串的'h'改为'k',其结果如上图
char *p="hello";*p=‘k’;//错误,p指向常量区.rodata 'h'的地址,常量区的内容只读,无法修改;
char p[]="hello";*p=‘k’;//正确,p[]在堆栈开辟连续内存并把"hello"从常量区复制过来;

注意:
1) p: 存放"hello"字符串首元素’h’的地址,
2) p是指向一个字符,不是指向一个字符串
3) 字符串在常量区存储时,以’\0’作为结束标志

细节补充1:

char *p="hello";
char *q="hello";
p和q的地址是一样的,编译器在处理的时候会把相同的字符串优化。

细节补充2:
“如果有空间”系统会在字符串后补‘\0’
反言之就是如果空间不够,系统就不能补了;

用strlen()测试下面字符串长度:
char cc[5]="hello";       //结果:19(不确定)		 //空间不足补\0 {'h','e','l','l','o'}
char cc[10]="hello";	  //结果:5              //空间足够补\0 {‘h’,'e','l','l','o','\0','\0','\0','\0','\0'};
char cc[]="hello";        //结果:5              //自适应 {‘h’,'e','l','l','o','\0'}
//strlen()测字符串长度是到'\0'截止,第一张情况由于系统不能补'\0',则测的时候会
一直寻找下去直到找到'\0'(null,0),所以其结果不定。
到后面使用strcpy()同理,一定要注意开辟足够的内存空间
例如存放"hello"应预留‘\0的位置’ char cc[6];

总结:
char A[10] = “hello”; --> 把常量区的字符串"hello"直接拷贝到栈空间A变量中(如果数组是局部变量)
char *p = “hello” --> 把常量区的字符串"hello"的首元素的地址存储在指针变量p中

六、strlen()

原型:
*size_t strlen(const char *s);

功能: 给一个字符串的起始地址s,不断往后计算,直到遇到\0为止就停止计算!
返回值:s指向的字符串对应的字符个数*

问题①:

	//strlen()的用法以及和sizeof()的区别
	char B[] = "helloworld";
	char A[100] = "helloworld";
	char *p = "helloworld";

    printf("sizeof(A) = %d\n",sizeof(B));//11		
	printf("sizeof(A) = %d\n",sizeof(A));//100
	printf("sizeof(p) = %d\n",sizeof(p));//4

	printf("strlen(A) = %d\n",strlen(B));//10
	printf("strlen(A) = %d\n",strlen(A));//10
	printf("strlen(p) = %d\n",strlen(p));//10
	
	//由char B[]可知'\0'也占一个空间,但是测字符串的时候不会算进去。
	//由char A[100]可知,后面全补0,一样会占内存空间,但不会算在字符串长度上。
   //sizeof(p)测的是'h'的地址,相当于sizeof(char *),任何指针都是占4个字节(32     位系统机器位长)

问题②:

int main()
{
	char  a[7]="a0\0a0\0";
	char  b[7]="a0\0asds";
	char  c[7]="a0\aasds";
	char  d[7]="a0\aaa\0";
 
	printf("%d \n",strlen(a));  //2
	printf("%d \n",strlen(b));  //2
	printf("%d \n",strlen(c));  //12
	printf("%d \n",strlen(d));  //5
}

//'\0'结束   结果2
//‘\0’结束   结果2
//'\a'转义字符,算一个字符  总共7个字符 c[7]没空间补'\0' 其结果为12(不确定)
//‘\a’转义字符 ,‘\0’结束,一共5个字符  结果5

补充-关于转义字符:
C语言.字符串,及string.h初步应用_第2张图片
总结:
1)strlen()传首地址进来,返回长度;
2)strlen()直到‘\0’结束,要考虑是否有‘\0’(空间是否够补);
3)转义字符算一个字符;

七、strcmp()

int strcmp(const char *s1, const char *s2);
int strncmp(const char *s1, const char *s2, size_t n);

功能:
比较两个字符串是否一致;

参数:

s1与s2都是需要进行对比的字符串的首元素地址
n: 只匹配前n个字节

返回值:
s1与s2匹配: 0
s1与s2不匹配: 非0 (实际可能负数或正数,但一般用不到,知道非0就行)

//Demo
char A[100] = "helloworld";
	char *p = "hello";
	//if(A == p)//错误
	if(strncmp(A,p,5) == 0) //正确
	{
		printf("ok!\n");
	}

注意:
1 )strcmp也是基于strlen的基础上,所以若果不够空间存’\0’也会导致越界对比,导致字符串不匹配;

八、strcpy()

原型:
char *strcpy(char *dest, const char *src);
char *strncpy(char *dest, const char *src, size_t n);

功能:
拷贝字符串到某段内存中

参数:
dest: 需要把字符串拷贝到的空间的起始地址,空间必须足够大
src: 需要拷贝的字符串起始地址
n: 需要的前n个字节 ,需要src指向的内容总长度

返回值:
指向dest这个区域的指针

char a[]="hello";
char b[]="ab";
strcpy(a,b);
//执行后a里面是:{'a','b','\0','l','o','\0'}
printf("%s",a);
//打印 ab
//printf("%c",a+3)
//打印 l

注意:
1)保证被拷贝的空间足够,否则会导致越界
2)strcpy会把’\0’也拷贝过去
3)n指定可以实现追加字符串功能

经验:
① 常用于字符数组初始化后赋值:
char A[100];
A[100] = “gec123456” ; //错误
strcpy(A,“gec123456”);//正确

②malloc()申请堆空间,要用strcpy把字符串赋值过去。

九、strcat()
功能:追加字符串

十、关于数组清零的几种常用方式
1.定义数组时初始化0
char s[50]={0}; – 初始化时,小于开辟的长度,后面自动补0

2.清空某段内存空间 – bzero() –
#include
void bzero(void *s, size_t n);

s: 需要清零的内存空间首地址
n:需要清零的字节数
没有返回值

char str[50]; bzero(str,50);

3.内存初始化 --memset()–
#include 或#include
void *memset(void *s, int ch, size_t n);
函数解释:将s中当前位置后面的n个字节 (typedef unsigned int size_t )用 ch 替换并返回 s 。

功能:作用是在一段内存块中填充某个给定的值,它是对较大的结构体或数组进行清零操作的一种最快方法 。

char str[50];memset(str,0,sizeof(str));

十一、开发经验

以上几个函数在开发中会使用到的场景:
1)write()/send() – 确定某些数据的总字节数 – strlen()
2)strcmp() – 检索数据的正确与否 /登录密码,检索某个特征值
3)strcpy() – 给某些字符数组赋值(数组初始化后不能整体赋值)
char A[100];
A[100] = “gec123456” ; //错误
strcpy(A,“gec123456”);//正确

4)strcat() – 拼接字符串,仅限于追加功能 – 后期使用sprintf()代替strcat()

更多:https://www.cnblogs.com/intelwisd/p/8299738.html

你可能感兴趣的:(C语言学习,字符串,string,strlen,strcmp,strcpy)