五、指针和字符串--普通仙女为指针怒码万字

前篇:

一二---普通仙女对指针的学习记录(从入门到学废)

三---普通仙女对指针的学习记录(从入门到学废)

四、数组指针与指针数组--普通仙女为指针怒码万字

目录

1.字符串常量/字符串字面量

2.字符数组

3.用指针表示法创建字符串

4.字符串数组

5.指向指针的指针 (禁止套娃)

6.字符串指针做函数参数


1.字符串常量/字符串字面量

用双引号括起来的内容称为字符串字面量,也叫字符串常量,存储时,字符和编译器加的\0都被存在内存里。

字符串常量属于静态存储类别,存储一次,可以使用多次。双引号括起来的内容 就相当于 指向该字符串存储位置的指针。

如果我们尝试解引用一下这个双括号东东,就会得到第一个字符

(这就类似于数组名不仅仅是一个名字,还是一个指向数组位置的指针)。

关门,放图!!!


2.字符数组

  • 标准的数组初始化形式:stupidstupid char c[5]={'L','o','v','e','\0'};

        注意加上\0,字符数组才能变成字符串;如果没有’\0’结束符,字符数组使用%s输出会乱码因为没有\0,它不知道什么时候停止。

  • 用字符串初始化数组: char cc[ ]="Rabbit";

        不用自己加空字符,编译器会自动加上;

        不过它与字符串本身还是有区别的,我们把这一部分放到下一板块和指针一起讲,比较着更能看出不同~。

另外,我们可以让编译器自己计算数组的大小,虽然只能是在初始化时这样做。(但是这足够了,哪有人想要一个一个数字母的个数啊zzz)

既然创建了一个字符串数组,像从前一样,我们来聊聊数组名~

它同样代表了数组首元素的地址:

cc==&cc[0];        *cc=='R';        *(cc+1)=='a';

既然如此,我们隆重推出指针表示法来创建一个字符串;


3.用指针表示法创建字符串

初始化:       char *pt="Rabbit" ;

                      char cc[ ]="Rabbit" ;

赋值:           char *pp ;        pp="Great" ;

                      但是数组不能直接赋值;

这很很简单,pp、pt和cc现在都是指针了,我们不多赘述(我居然还会用成语VAV)

先讲讲上一个板块遗留的问题,关于用字符串初始化数组与字符串本身的区别(不好意思,名字起的有点绕)

  1. 字符串字面量储存在静态储存区中
  2. 数组形式:程序运行时为数组分配内存,将字符串的内容拷贝到数组中。也就是说这个时候其实有两个字符串副本。
  3. 指针形式:初始化指针时,是把字符串的地址拷贝给指针,即pt和“Rabbit”的地址相同。

这里剩下的内容简单,我们还是做一个表格清楚一点,也简洁~

麻烦手机版的uu们滑动看一下这个表格~

初始化类型自增加法使用
数组形式char cc[]="Rabbit"

cc

地址常量

改变cc就是改变地址

cc++

违法

cc+1

指向下一字符

数组表示法cc[2]

指针表示法

*(cc+2)

指针形式char *pt="Rabbit"

pt

指针变量

改变pt就是改变指向

pt++

指向下一字符

pt+1

指向下一字符

数组表示法pt[2]

指针表示法

*(pt+2) 


练习5.1:

用指针形式、数组形式,指针表示法、数组表示法表示字符串;

#include<stdio.h>
int main()
{
	char c[]="YOU ARE SO BRIGHT.";
	char *pt="I love Rabbit.";
	printf("%s\n",c);
	printf("%s\n",pt);
	printf("%c\n",*c);
	printf("%c\n",*pt);
	
	for(int i=0;c[i]!='\0';i++)
		printf("%c",c[i]);
	printf("\n**************************************\n");
		for(int i=0;*(c+i)!='\0';i++)
		printf("%c",*(c+i));
	printf("\n**************************************\n");
	for(int i=0;pt[i]!='\0';i++)
		printf("%c",pt[i]);
	printf("\n**************************************\n");
		for(int i=0;*(pt+i)!='\0';i++)
		printf("%c",*(pt+i));
	printf("\n**************************************\n");
		for(int i=0;*pt!='\0';pt++)
		printf("%c",*pt);
	printf("\n**************************************\n");
}

练习5.2:

复制字符串

#include<stdio.h>
int main()
{
	char a[]="happy birthday to you!";
	char b[30];
	int i;
	for(i=0;*(a+i)!='\0';i++)//指针法
	{
		*(b+i)=*(a+i);
	 } 
	 *(b+i)='\0';
	 //上面的循环没有复制到空字符,所以这句一定要加,这样才是字符串, 
	 printf("the string a is: %s\n",a);
	 printf("the string b is: ");
	 for(i=0;b[i]!='\0';i++)
	 printf("%c",b[i]);//下标法 
	 
	 
	 printf("\nanother method:\n");
	 char *c;
	 c=b;
	 for(;*c!='\0';c++)//指针法 
	 printf("%c",*c);
 } 

4.字符串数组

创建一个字符串数组,我们就可以访问多个不同的的字符串。

char my[3][10]={ "happy" , "birthday" , "to you" };

char *you[3]={ "thank" ,"you" ,"very much" };

第一个是char类型数组的数据,第二个是指向字符串的指针数组。

和往常一样,我们放一张表格。

元素大小类型修改字符串
char c[N][M]

内含N个

数组

相同

为M

char被定义后只能读取不能修改,之后对它的赋值都是错误的
char *p[N]

内含N个

指针

可以不同char*定义后可以读取和修改每个字符

5.指向指针的指针 (禁止套娃)

    char you[3][10]={ "thank" ,"you" ,"very much" };

    char *ap[10];

    for(int i=0;i<3;i++) ap[i]=you[i];

    char **p=ap;

关于**p,我们可以理解为*(*p),括号里面是一个指针。

*p用指针来指向指针数组中的一个字符串,通过p递增指向指针数组中不同的字符串;**p指向字符串里的某个字符;

看完上一篇,这个对你来说应该so easy叭~~

#include<stdio.h>
int main()
{
	char you[3][10]={ "thank" ,"you" ,"very much" };

	char *ap[10];//每个元素的内容,是一个字符串指针

	for(int i=0;i<3;i++)
		ap[i]=you[i];
	printf("*ap=%s\n",*ap);
	printf("**ap=%c\n",**ap);
	
	char **p=ap;
	
	printf("*p=%s\n",*p);
	printf("**p=%c\n",**p);
	
	for(int i=0;i<3;i++,p++)
	printf("%s ",*p);
	
 } 

再看另一段代码:

warning!虽然可以运行,但是在运行时给出了警告:

 deprecated conversion from string constant to 'char*' [-Wwrite-strings]

已弃用从string常量到'char*'的转换[-Wwrite-strings]

所以指针数组不能直接指向字符串常量了,我们在使用的时候还是指向字符串数组吧。

6.字符串指针做函数参数

字符串在函数间传递时,可以用字符数组名或者指向字符串的指针变量作为参数。

但由于数组名和指针实际含义不同,在使用时要十分小心。

1.因为指针指向字符串字面量本身的地址,如果我们不想修改字符串内容,却传递了指针(字符串字面量的地址)给形参,被调函数就是在改变字符串常量本身;

当然,如果你加上了const限定符,当我没说。

2.而如果我们传递的数组名,那没关系,因为数组里存的是字符串字面量的副本。


所以如果不希望改变字符串字面量本身,实参用数组名,形参用指针,高效安全。

我们先编个程序看看1会发生什么;

 [Warning] deprecated conversion from string constant to 'char*' [-Wwrite-strings]

[警告]不推荐将字符串常量转换为“char*”[-Wwrite strings]

程序可以运行,但不是我们的预期,所以传给函数的字面常量是没法被修改的。

 练习5.4:

依然是复制字符串,不过这次我们写一个copy函数;

#include<stdio.h>
void copy_string(char*from,char*to);
int main()
{
	char a[]="happy birthday to you!";
	char b[]="you are so kind!"; 
	int i;
	 printf("the string a is: %s\n",a);
	 printf("the string b is: %s\b",b);
		copy_string(a,b);
	 printf("\nafter the copy:\n");
	printf("the string a is: %s\n",a);
	 printf("the string b is: %s\b",b);
 } 
 void copy_string(char*from,char*to)
 {
 	for(;*from!='\0';from++,to++)
 	*to=*from;
 	
 	*to='\0';//这句话很重要我要再说一遍!!! 
 }

练习5.3:

写一个函数,将两个字符串连接,即编写strcat函数。

如果两个字符串相等,则不连接。

例如:字符串1为 stu,字符串2为dent,粘贴之后,字符串1变为:student。

判断字符串相等,可以使用:strcmp函数(来自老师的实验作业题,我就在这里交作业了hhh)

#include<stdio.h>
#include<string.h>
void add_string(char*before,char*after);
int main()
{
	char a[]="happy birthday ";
	char b[]="to you!"; 
	int i;
	 printf("the string a is: %s\n",a);
	 printf("the string b is: %s\b",b);
	 if(strcmp(a,b)==0)
	 return 0;
		add_string(a,b);
	 printf("\nafter the add:\n");
	printf("the string a is: %s\n",a);
	 printf("the string b is: %s\b",b);
 } 
 void add_string(char*before,char*after)
 {
 	while(*before!='\0')
	 before++;
 	//循环转到第一个字符串结束 
 	for(;*after!='\0';)
 	*(before++)=*(after++);
 	
 	*before='\0';//这句话很重要我要再再再说一遍!!! 
 }

 我更新很勤快吧~~这可是比微积分和线性代数都优先的事情呢~

分享就结束啦,感谢阅读!!!!阿里嘎多!!!

2021.12.2

SThree楠钰子.

  • 3
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

程序和三三总有一个能跑

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值