博客
关于我
强烈建议你试试无所不能的chatGPT,快点击我
数组、指针、字符串大礼包!
阅读量:3970 次
发布时间:2019-05-24

本文共 6027 字,大约阅读时间需要 20 分钟。

指针:

int *p,q //表示p是指针,q是int;

int *p,*q //表示p和q都是指针
(*是和变量在一起的,是用来声明指针)

指针有什么用呢?

  • 1.用void swap(int* ,int* ); 交换值 虽然没有返回值,但是利用指针可以实现
    如果是传进两个整型,那就必须要有返回值,不然函数内部的交换只是拷贝,对外界无影响。于是就很麻烦啊;
    使用场景特点:像swap()这样的函数,函数返回有多个值,于是就要用到指针节省力气
  • 2.同样是void maxmin();要找数组中的最大值和最小值,于是有两个输出量,于是就用到指针
  • 3.在用函数做除法的时候,既要用int devide();返回一个ret来判断除数是否为0,如果除数不是0,则还要返回相除的结果,于是要用指针存放结果送出去。
    (这个也是有多个输出)
  • ※4.要对数组中某个元素操作的时候 可以用指针

指针和数组的爱恨情仇:

int sum(int *ar,int n);

int sum(int ar[],int n);
上面两种函数原型等价,就算定义指针,下面也还是可以用[],当作数组来处理

min=2;

int *p=&min;

这时,有*p=2

同时也有p[0]=2,因为这时把min认为是数组,即int min[1];

为什么有数组a[]和数组b[],但是不能将a、b进行赋值?

因为int a[100];相当于int * const a; (数组变量是const的指针,所以不能被赋值)

所以数组在定义之后就不能再进行赋值了
*但是指针定义后却可以改变,所以可以int *q=a;

指针和const:

  • 1.指针是const:指针不能再指向其他变量;
    int * const q=&i;
  • 2.指针所指向的变量是const:可以改变的变量的值,也可以改变指针的指向;
    但是就是不能【通过这个指针】改变变量的值(即可以i=20,但不能做*p=20
    const int *p=&i;(你给我一个变量的指针,我保证不通过这个指针去改变它所指的变量的值!)
    (比如将常数指针传到函数中时,就可以有效避免它所指的变量值被更改,相当于让函数发誓!↑)

※eg.区分以下含义

int i;
const int* p1=&i; 所指变量
int const* p2=&i; 所指变量
int const p3=&i; 指针
判断依据:const在
的前面还是后面
思路:从左到右,碰到就判定为指针的定义,再往右就是指针变量,如果后碰到const那肯定是对指针作用的了

  • 3.const数组:
    const int a[]={1,2,3,4,5,6,7,8,9};
    如果是int a[]={1,2,3,4,5,6,7,8,9}; 那么a数组本来就已经是个const指针了;
    虽然整体不能进行赋值,但是单个单元还是可以进行修改,如a[0]=2;
    这时候再加一个const那么则代表数组的每个单元都是const int
    (比如在函数中使用,传进一个const int a[10]参数,可以有效保护数组不被修改,安全)

关于动态内存分配:

int number;

int a;
printf(“输入数量:”);
scanf("%d",&number);
//int a [number];
a=(int
)malloc(number*sizeof(int));

(eg.若是直接a=malloc(number*sizeof(int));那么得到的【默认】是void*类型,如果是a=(int*)malloc(number*sizeof(int))就得到了int*类型)

最后在程序结束前来一个free(a); 而且只能还申请来的空间的【首地址】!!(意思就是 如果进行过p++,或者是指向了其他变量,那么就要将指针归位,才能释放内存free(p)
(理解:malloc的时候,系统会记住它给了你什么,你还的时候要原封不动地还给它free)

※常见问题:

  • 1.申请了没free→长时间运行内存逐渐下降
    新手:忘了
    老手:找不到合适地free时机
  • 2.free过了再free,系统会奔溃
  • 3.地址变过了,直接去free
    So 好习惯:有malloc 马上跟上free!

字符数组和字符串:

在这里插入图片描述

在这里插入图片描述

区别:字符数组不能用字符串运算方式进行运算

前者只是一个个字符 后者再最后有一个’\0’
这个\0表示字符串结束了,但它不是字符串的一部分
char *str="Hello";虽然只有五个单词,但却占留个位置,因为编译器会自动显示一个’\0’
"Hello"会被编译器变成一个字符数组放在某处,这个数组的长度是6
因为结尾还是表示结束的’\0’,两个相邻的字符串常量会被自动连接起来

字符串特点:

在这里插入图片描述

字符串常量:

char *s="Hello,world!";
char *s2="Hello,world!";
于是会发现两个指针指向同一个位置,而且是个小地址
而且为常量,不能改;
如果你想修改某个值,则必须写成字符数组:
`char s[]=“Hello,world!”;
那么为什么呢?有什么区别呢?

char *s=“Hello,world!”;(我是一个指针,我指向那个重要的地方!只读!)

char s[]=“Hello,world!”;(我是一个数组,东西就在我这里!)

那么是用指针还是数组?

在这里插入图片描述

在这里插入图片描述

char *是字符串吗?

不一定,可能是单个字符,也可能是字符数组

char *a={'H','e','l','l','o'};这个时候表示字符数组;
char *a={'H','e','l','l','o','\0'};这个时候表示字符串**(字符数组后有\0)**;

字符串的输入和输出

char string[8];

scanf("%s",string);
printf("%s",string);

scanf();读入一个单词(到空格、tab或回车为止


小知识:
  • tip1:

/

"123456"等价于{‘1’,‘2’,‘3’,‘4’,‘5’,‘6’,’\0’}
它表示一个字符串常量,虽然表面看上去有六位,但是实际上却又七位
这是因为它独特的字符串血统,最后会自动有一个\0;
/

  • tip2:

/

char a[7]中是由a[0] a[1] a[2] a[3] a[4] a[5] a[6]
其中的**'7’是指一共有7个元素**
然而事实上,由于"1234567"赋值给数组得到的是字符串数组,最后有一个’\0’
所以啊,"1234567"其实是有8位的!!
于是,如果让a[7]="1234567";数组会溢出!!
/

  • tip3:

/

那么如何规避这种情况呢?
可以在scanf()的时候做手脚
scanf("%6s",word);** 在%后面加一个’6’就可以只拿前面6位了!!**
一共有7个元素,于是最后一个元素位置拿来放'\0'
这就完美了~
/

  • tip4:

/

空字符串:
char buffer[100]="";
意思:这是一个空的字符串,buffer[0]=='\0'他是个有效的字符串
但是
char buffer[]="";
意思:这个数组的长度只有1!而且只有一个元素,buffer[0]='\0';

于是可以得出结论:

自己定义数组长度常常有浪费(冗余)
但是若是空着给编译器定义长度,他就很小气地帮你卡死
即你右边有多少,他就给多少空间你
/

  • tip5:

/

字符串中的套娃:二维数组和多重指针
定义有效的二维数组:

a[][]={“Hello”,“World”};(错误)

a[][10]={“Hello”,“World”};(正确)(这个时候,a[0]=char [10]

一定要给定每个元素的长度(第二个框里面要有内容):如"Hello"和"World"的长度

但是啊,我很恶心,给它scanf()了一个很长的字符串,超过了它的定义长度,那怎么办呢??

那我就把char a[][10]写成char *a[],这个时候啊,a[0]就变成了char *,这不就没有长度限制了嘛?
(ps.char *a[]就表示指针数组,数组里面都是指针(可以理解为很多不限长度的字符串~))
/

  • tip6:

/

※字符串的赋值:(理解/重要!)

1.初始化赋值,char a[]="Hello,World!";

2.先定义,然后***循环***给每个元素赋值;
3.动态赋值:同样先定义,然后***循环***给每个元素scanf()
总结:想要一次性修改数组的值?不可能,它在定义的时候才可以直接一次性赋值
其他情况必须使用循环!!一个一个改!!
/

小知识over~

单字符的输入输出:在这里插入图片描述

上面这个Try to understand??

(代码原理没看懂???)
int getchar(int )int putchar(int )都是int类型如果是字符的话就取ASCII码

  • Q1:为什么是int而不是char呢?因为char的范围太小,而EOFstdio中默认为-1,于是就用int才能取到;
  • Q2:getchar明明是得到一个字符,为什么能复读字符串呢?(本质是因为我按一个键,它提取一个键)
    getchar()实时的,碰到它,它就等着用户按键,【并且把所有的操作存放在stdin流中】
    (首先有一个缓冲区shell,它为
    中间商**,我们对键盘的所有操作都被保存在那里)
    getchar()函数就是小弟,给shell【一个一个】地送东西,我们按什么他就送什么
    当我们按下回车的时候,getchar()知道是最后一个货物
    然后让putchar()一个个从shell这个仓库中输出,把自己运过去地
    一件件
    **小物品***(每一个字符)***送到我们看得到地界面上输出;

#include<string.h>里面的函数使用:(只能作用与字符串)

  • 1.strlen:用于输出字符

strlen(“Hello”)==5;

sizeof(“Hello”)==6;
(另外:若char a[100]=“Hello,World!”,那么strlen(a)=12,因为它是根据’\0’判断的
此时sizeof(a)=100,因为它是看空间的)

如何写一个strlen函数

在这里插入图片描述

※思路:传入一个指针(即字符串),从第一个开始遍历,一直到'\0'


  • 2.strcmp:用于比较

int strcmp(const char *s1,const char *s2);

比较两个字符串,返回规则:
0:s1==s2
1:s1>s2
-1:s1<s2

理解:

char s1[]=“abc”;
char s2[]=“abc”;
那么s1==s2吗?NO!因为这个时候比的是地址!地址当然不一样
那么strcmp(s1,s2);得到什么的?得到0,因为字符串一样!
所以判断两个字符串是否相等,不能直接比较,一定要用函数strcmp
strcmp()函数是用ASCII码比
(ps.比较"abc"和"abc “,出现的结果是-1,因为第二个字符串有空格” ")

※区分:

定义数组char s1[]=“abc”; 这时,s1表示数组的【首地址】;
定义指针char *s1=“abc”; 这时,*s1表示数组中第一个元素的值;这时可以通过s1++来遍历噢`


在这里插入图片描述

  • 3.strcpy函数:用于copy(抄作业)

具体使用方法:

注意函数中的两个参数,是先找一个盒子,然后再把东西抄袭进去
最后返回的是到盒子里面找抄到的东西

那么什么叫不能重叠呢?

在这里插入图片描述

因为strcpy的功能抄作业***

所以我们经常用它来复制一个字符串:先malloc一块地址(具体多大要思考噢),然后strcpy抄作业*

在这里插入图片描述

具体形象解释:(右侧)

(小声BB:·strlen·测量的是字符串常量长度,不包括’\0’,所以要+1)
这里的功能是先申请一块动态内存,让dst指针指向这片区域
然后用函数抓住dst这个空盒子,往里面塞src
之后函数完事就把盒子送出去(返回)


  • 4.strcat

具体使用:

在这里插入图片描述

形象表现:

在这里插入图片描述

strcpystrcat的对比:

strcpy抄作业***,它里面的第一个参数是空的(它是白卷!太不努力了啊!)
strcat则是自己写到一半,发现题目不会做,再去抄别人的答案
strcpy是从dst[0]开始抄src;
strcat则是从dst[strlen(dst)]开始抄src;
※共同点:操作者(学渣)都是函数里面的第一个参数(即第一个字符串指针),第二个参数(即第二个字符串指针)都是学霸
*

But,因为第二个参数太长,可能会超出第一个参数的界限,于是就会出现安全问题!!

(即学霸的答案太详细,学渣发现自己字太大抄不下了??)
那该怎么办呢??

不慌,下面有安全版本的函数,可以限制抄作业的量,以保证不会超过界限

船新版本!比原来函数多了一个n,而且函数多了一个参数,来限制抄作业的数量
对于strcmp,它变成strncmp之后,多了个参数n,可以把两个字符串从左到右限制为n个参赛选手的个数


  • 5.strchr和strrchr

功能是查找

前者是从左往右找
后者多了个r,是从右往左找
第一个参数是字符串
第二个参数是要找的字符(注意是int类型啊!!不是char,比如'l'
返回的是指针,指向要找的字符
在这里插入图片描述

如上图,怎么在"Hello"中找到第二个’l’呢?

啊可恶,当然是找两次啊!!!
第一次指针p返回第三个字符'l'的地址,这个时候指针p是返回"llo",那么p+1就是"lo"
接下来,再来一次p=strchr(p+1,'l');
这样返回的指针p就指向第二个'l',其实也就是指向'lo'(后面有\0)
就找到了第二个'l'的位置了!!
妙啊~~

那么我们已经会取"llo"

如果我想取前面的"He"呢?该怎么办?

在这里插入图片描述

p指针指向第一个'l'

char c用于存放这个'l',最后要复原字符串用啊!!
然后通过*p=’\0’把’l’替换掉
于是字符串变成了"He\0lo\0"
这里其实变成了两个字符串,一个是"He",一个是"llo"
又因为s是数组名,代表数组的首地址,所以字符串s就是第一个字符串"He"
然后指派一个指针tstrcpy去抄s的作业就行了
最后的最后,复原字符串,把"He\0lo\0"变回"Hello\0"
就用*p='l'就OK了
图解:

在这里插入图片描述

真的是非常的Amazing啊!!!


在这里插入图片描述

  • 6.strstr和strcasestr:

字符串中找一个字符串(返回的是一个指针)

strstr就是在字符串中找一个字符串
strcasestr功能相同,就是**【忽略大小写】**!!

转载地址:http://ortki.baihongyu.com/

你可能感兴趣的文章
数字地和模拟地处理的基本原则
查看>>
集电极开路,漏极开路,推挽,上拉电…
查看>>
长尾式差分放大电路2
查看>>
十种精密整流电路
查看>>
红外线遥控原理
查看>>
放大电路的主要性能指标?
查看>>
稳压、调压、监控、DC/DC电路大全
查看>>
放大电路的主要性能指标?
查看>>
运放电压和电流负反馈的讨论
查看>>
运放自激问题
查看>>
运放电压和电流负反馈的讨论
查看>>
终于&nbsp;整明白了中断的工作原…
查看>>
终于&nbsp;整明白了中断的工作原…
查看>>
终于&nbsp;整明白了中断的工作原…
查看>>
终于&nbsp;整明白了中断的工作原…
查看>>
2010年11月19日
查看>>
2010年11月19日
查看>>
TC35i&nbsp;单片机
查看>>
TC35i&nbsp;单片机
查看>>
AT&nbsp;命令详解
查看>>