第八周指针与字符串

一、指针

sizeof

是一个运算符,给出某个类型或变量在内存中所占的字节数。

%ld 表示输入输出为长整型

运算符&

scanf("%d",&i); 里的&

获得变量的地址,它的操作数必须是变量

        int i; printf("%x",&i);

地址的大小是否与int类型相同取决于编译器

inti; printf("%p",&i);

地址的大小是否与int类型相同取决于

%x  以16进制输出变量地址

%p 打印地址

%lu  输出无符号长整型整数 (long unsigned)

&不能取的地址

&不能对没有地址的东西取地址

        &(a+b)    &(a++)    &(++a)

可取的地址

变量的地址

相邻的变量的地址,,,差距永远是4

&的结果的sizeof

数组的地址,,,第0位的地址

数组单元的地址,,,第0位的地址

相邻的数组单元的地址,,,差距是4

堆栈stack是自上而下的

 指针

就是保存地址的变量

int i;

int* p = &i;

int* p,q;

int *p,q;

int* p,q;  ==  int *p,q;(意思是一样的)

*p是一个int

指针变量

变量的值是内存的地址

        普通变量的值是实际的值

        指针变量的值是具有实际值的变量的地址

作为参数的指针

void f(int *p);

在被调用的时候得到了某个变量的地址;

        int i=0; f(&i);

在函数里面可以通过这个指针访问外面的i

访问那个地址上的变量  *

*是一个单目运算符,用来访问指针的值所在的地址上的变量

可以做右值也可以做左值

        int k = *p;

        *p = k+1;

数组参数

以下四种函数原型是等价的:

        int sum(int *ar, int n);

        int sum(int *, int);

        int sum(int ar[], int n);

数组变量是特殊的指针

数组变量本身表达地址,所以

        int a[10]; int *p=a;     //无需用&取地址

        但是数组的单元表达的是变量,需要用&取地址

        a == &a[0]

[]运算符可以对数组做,也可以对指针做:

        p[0] <==> a[0]

*运算符可以对指针做,也可以对数组做:

        *a = 25;

数组变量是const的指针,所以不能被赋值

        int a[] <==> int * const a=...

 

二、字符类型

char是一种整数,也是一种特殊的类型:字符。这是因为:    (character)

        用单引号表示的字符字面量:‘a’, ‘1’

        "也是一个字符

        printf和scanf里用%c来输入输出字符

字符的输入输出

如何输入‘1’这个字符给char c

        scanf("%c",&c); ——>1

        scanf("%d",&i); c=i; ——>49

'1'的ASCII编码是49,所以当c==49时,它代表'1'

一个49各自表述!

 %c:以字符形式输出,

混合输入

注意输入的空格

scanf("%d %c",&i ,&c);

scanf("%d%c",&i ,&c);

字符计算

一个字符加一个数字得到ASCII码表中那个数之后的字符

两个字符的减,得到它们在表中的距离

大小写转换

’a‘-’A‘可以得到两段之间的距离,于是

        a+’a‘-’A‘可以把大写变小写;

        a+‘A‘-’a‘可以把小写变大写;

要变的-原先的

大变小

#include<stdio.h>

int main()
{
    char c = 'A';
    int i=c+'a'-'A';
    printf("%c\n",i);
   
    return 0;
}

小变大

#include<stdio.h>

int main()
{
    char c = 'a';
    int i=c+'A'-'a';
    printf("%c\n",i);
   
    return 0;
}

 逃逸字符

用来表达无法印出来的控制字符或特殊字符,它由一个反斜杠“\”开头,后面跟上另一个字符,这两个字符合起来,组成了一个字符

printf("请分别输入身高的英尺和英寸,"
       “如输入\"5 7\"表示5英尺7英寸:”);

三、字符串

以0(整数0)结尾的一串字符

        以0或'\0'是一样的,但是和'0'不同

0标志字符串的结束,但它不是字符串的一部分

        计算字符串长度的时候不包含这个0

字符串以数组的形式存在,以数组或指针的形式存在

        更多的是以指针的形式

string.h里有很多处理字符串的

char *str = "Hello";  有一个名为str的指针,它指向了这个字符数组这里面放的内容是Hello

char word[] = "Hello";  有一个字符数组,里面的内容是Hello

char line[10] = "Hello";  有一个字符数组line,line数组里面有10个,数组里面有是个字节那么大,往里面放了Hello,这个Hello里面有5个字符,加上‘0’总共六个。

字符串常量

"Hello"   字符串常量,

"Hello"   会被编译器变成一个字符数组放在某处,这个数组的长度是6,结尾还有表示结束的0 

两个相邻的字符串常量会被自动连接起来

唯一特殊的地方是字符串字面量可以用来初始化字符数组

以及标准库提供了一系列字符串函数

字符串

C语言的字符串是以字符数组的形态存在的

        不能用运算符对字符串做运算

        通过数组的方式可以遍历字符串

字符串变量的两种形式

        char* s = "Hello,world!";

        char word[]= "Hello,world!";

作为数组:字符串在这里

        作为本地变量空间自动被回收

作为指针:字符串不知道在哪里

        处理参数

        动态分配空间

如果要构造一个字符串——>数组

如果有处理一个字符串——>指针

s是一个指针,初始化为指向一个字符串常量

        由于这个常量所在的地方,所以实际上s是const char *s,但是由于历史的原因,编译器接受不带const的写法

        但是试图对s所指的字符串做写入会导致严重的后果

#include<stdio.h>
 int main(void)
 {
    int i = 0;
    char *s = "Hello World";
    char *s2 = "Hello World";

    //s[0] = 'B';
    printf("s =%p\n",s);
    printf("s2=%p\n",s2);
    printf("&i=%p\n",&i);
    //printf("Here!s[0]=%c\n",s[0]);
     
    return 0;
 }

输出为

s =0000000000404000
s2=0000000000404000
&i=000000000061FE0C

s和s2地址很小,因为s和s2存在于只读代码段。而且是只读的。

如果需要修改字符串,应该用数组的方式定义:

char s[] = "Hello,world!";

char*是字符串?

字符串可以表达为char*的形式

char*不一定是字符串

        本意是指向字符的指针,可能指向的是字符的数组(就像int*一样)

        只有它所指的字符数组有结尾的0,才能说它所指的是字符串

四、字符串计算

字符串赋值

char *t = "title"; 

char *s;

s = t;

并没有产生新的字符串,只是让指针s指向了t所指的字符串,对s的任何操作就是对t做的.

字符串输入输出

(string:  字符串)

char string[8];

scanf("%s",string);

printf("%s",string);


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

scanf是不安全的,因为不知道要读入的内容的长度

安全的输入

char string[8];

scanf("%7s",string);


在%和s之间的数字表示最多允许读入的字符的数量,这个数字应该比数组的大小小一

        下一次scanf从上一个读完的结尾开始。

常见错误

char *string;

scanf("%s",string);


以为char*是字符串类型,定义了一个字符串类型的变量string就可以直接使用了。

        由于没有对string初始化为0,所以不一定每次运行都出错。

指针要初始化!!

空字符串

相邻的紧挨着的两个双引号是一个空的字符串(也是有效的字符串)

char buffer[100]="";

        这是一个空的字符串,buffer[0] == '\0'

char buffer[] = '';

        这个数组的长度只有1

字符串函数

string.h

#include<string.h>

        strlen(lenth长度)

size_t strlen(const char *s);

返回s的字符串长度(不包括结尾的0)

        strcmp  (compare比较)

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

比较两个字符串,返回:

        0:s1 == s2

        1:  s1 > s2

        -1:  s1 < s2

        strcpy(copy)

char *strcpy(char *restrict dst, const char *restrict src);

把src的字符串拷贝到dst

        restrict表明src和dst不重叠(C99)

返回dst

        为了能链起代码来

        strcat(链接)

char *strcat(char *restrict s1, const char *restrict s2);

把s2拷贝到s1的后面,接成一个长的字符串

返回s1

s1必须具备足够的空间

strcpy和strcat都可能出现安全问题

如果要拷贝\链接的地方没有足够的空间,就会出现问题

安全版本

char *strcpy(char *restrict dst, const char *restrict src, size_t n);

char *strcat(char *restrict s1, const char *restrict s2, size_t n);

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

n:比较前n个数

n:最多只能操作的字符数

        strchr(字符串中找字符)

char *strchr(const char *s, int c);      //在字符串s中,寻找c第一次出现的位置。从左边数(返回的是指针)

char *strrchr(const char *s, int c);     //从右边找

返回NULL表示没有找到

        strstr

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值