011-指针(上)-C语言笔记

学习目标

1.【掌握】字符串常用函数

2.【掌握】指针变量的声明

3.【掌握】指针变量的初始化

4.【掌握】函数与指针

5.【掌握】指针的数据类型

6.【掌握】多级指针

7.【掌握】指针与数组

一、字符串常用函数

puts和gets函数的声明在stdio.h头文件中,strcmp、strlen、strcpy、strcat函数的声明在string.h头文件中。

puts()函数

语法:puts(存储字符串数据的数组名);

输出一个字符串数据,并自动换行。不过只能输出字符串,并且不能使用格式控制符。

 
1
2
3
#include <stdio.h>
charname[]="jack";
puts(name);//输出name字符数组里的字符串数据

gets()函数

语法:gets(存储字符串数据的数组名);

从控制台接收一个字符串数据,并存储在制定的字符数组之中。并且能读取到空格,scanf不能读取。不过gets只能接收字符串。无论是gets函数还是scanf函数在接收字符串的时候都是不安全的。如果输入字符串长度不够的时候,就会出问题。

 
1
2
3
#include <stdio.h>
charname[20];
gets(name);//接收20个字符内的字符串数据存储到name里

strcmp()函数

语法:strcmp(字符串1,字符串2);//返回int类型

根据每个字符对应的ASCII码依次比较两个字符串的每个字符的大小,如果比较到两个字符不同,就返回结果。如果返回正数,说明第一个字符串大,返回负数,说明第二个大。返回0,说明每个字符的ASCII相同。

 
1
2
3
4
5
#include <string.h>
charname[]="afdaf";
charname1[]="adfdg";
intcmp=strcmp(name,name1);//比较两个字符串的大小
printf("cmp = %d\n",cmp);//打印len = 5

strlen()函数

语法:strlen(字符串);

计算字符串的长度,一个一个字符计数,直到遇到'\0'为止。返回值是unsigned long。

 
1
2
3
4
#include <string.h>
charname[]="afdaf";
unsignedlonglen=strlen(name);
printf("len = %d\n",len);//打印len = 5

strcpy()函数

语法:strcpy(字符串1,字符串2);

将字符串2拷贝到字符串1里,并且覆盖掉字符串1里的数据。如果字符串1放不下字符串2,就会保错。

 
1
2
3
4
5
#include <string.h>
charname[]="afdaf";
charname1[]="adfdg";
strcpy(name,name1);//会覆盖掉name
puts(name);//输出 adfdg

strcat()函数

语法:strcat(字符串1,字符串2);

将字符串2中的数据追加到字符串1后面,不会覆盖,只会拼接。如果字符串1放不下字符串2,就会保错。

 
1
2
3
4
5
#include <string.h>
charname[20]="afdaf";
charname1[]="adfdg";
strcat(name,name1);//不会覆盖掉name,只是name1连接到name屁股后面
puts(name);//输出 afdafadfdg

二、指针变量的声明

我们声明一个变量,实际是在内存中申请一个指定字节数的字节空间来存储数据,分配变量空间的时候,是从高地址到底地址来分配的。

概念:

1.变量的值:是存储在变量空间里的数据。

2.变量的地址:声明变量时申请到的字节空间中低字节的地址。

3.指针:变量的地址就叫做指针,地址就是指针,指针就是地址,只是换了个说法而已。

4.指针变量:其实也就是一个变量,只不过这个指针变量的值是个地址。

访问变量的两种方式:

1.直接访问:直接使用变量名来访问。

2.间接访问:让一个指针指向这个变量,通过这个指针可以间接的访问这个变量。

指针变量的声明

语法:

声明普通变量:数据类型 变量名;

声明指针变量:数据类型 *指针变量名;

 
1
2
3
int*p;//表示我们声明了一个指针变量,名字叫p,*只是说明这是一个指针变量,而不是普通变量。
int*p1;//*的位置可以挨着数据类型,也可以单独空一格
int*p2;

注意:

 
1
2
3
4
int*p3;//*在这里只是说明这是一个指针变量,而不是普通变量。
int*p4;//p4只能存储int类型的变量的地址
float*p5;//p5只能存储float类型的变量的地址
double*p6;//p6只能存储double类型的变量的地址

指针变量名也是一个标识符,也需要符合变量的命名规则和规范。一般情况下,我们变量名都以p开头,这样让别人一眼都能看出是指针变量。

 
1
2
int*p1,p2,p3;//是错误的,这样声明的只有p1才是指针变量,p2,p3是int类型普通变量
int*p1,*p2,*p3;//这才是正确的。

三、指针变量的初始化

指针变量中只能存储和指针变量类型相同的变量的地址,所以不能直接给指针变量赋值一个其他非地址的数据。使用&取地址运算符可以获取变量的地址。

语法:数据类型 *指针变量名 = 相同数据类型的变量的地址;

 
1
2
3
intnum=10;
int*p=&num;//获取num的地址并赋值给指针变量p
int*p1=p;//将p中存储的值赋值给新声明的指针变量p1。等价于 int *p1 = &num;

通过指针变量访问指针变量指向的普通变量,使用*取值符来取出指针变量指向的普通变量。

 
1
2
3
4
intnum=10;
int*p=&num;//将num的地址赋值给指针变量p
*p=20;//把20赋值给了p指向的num,这里的*p表示取出指针(p)的值(num的地址)的变量(num变量)。
printf("num = %d\n",num);//打印 num = 20

注意:

野指针:声明一个指针变量而没有初始化,这个指针变量的值是一个随机内存地址。通过这个指针去为指针指向的空间赋值的时候,就有可能改掉别人的数据,造成崩溃。

空指针:声明一个指针变量的时候不确定指向哪个变量,可以给他赋值NULL或者0(这里0就代表NULL,不是整型0),代表这个指针不指向任何空间。

四、函数与指针

在函数中操作实参

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
#include <stdio.h>
 
//计算最大值、最小值、平均值、高级平均值
voidgetMaxAndMin(intarr[],intlength,int*max,int*min,int*sum,float*avg,float*avg2);
//改变实参数据
voidziZeng(int*num);
 
intmain(){
    intarr[]={1,2,3,4,5,6,7};
    intlength=sizeof(arr)/sizeof(int);
    intmax=arr[0],min=arr[0],sum=0;
    floatavg=0.0f,avg2=0.0f;
    
    //调用函数
    getMaxAndMin(arr,length,&max,&min,&sum,&avg,&avg2);
    
    printf("max = %d  min = %d  sum = %d  avg = %.2f  avg2 = %.2f\n",max,min,sum,avg,avg2);
    
    intnum=1;
    ziZeng(&num);
    printf("num = %d\n",num);
}
 
//计算最大值、最小值、平均值、高级平均值
voidgetMaxAndMin(intarr[],intlength,int*max,int*min,int*sum,float*avg,float*avg2){
    for(inti=0;i<length;i++){
        //最大值
        if(arr[i]>*max){
            *max=arr[i];
        }
        //最小值
        if(arr[i]<*min){
            *min=arr[i];
        }
        //累加和
        *sum+=arr[i];
    }
    //平均值
    *avg=(float)*sum/length;
    
    //去掉一个最大值和一个最小值后的平均值
    *avg2=(*sum-*max-*min)/(length-2);
}
//改变实参数据
voidziZeng(int*num){
    for(inti=0;i<5;i++){
        (*num)++;
    }
}

五、指针的数据类型

通过指针操作指针指向的变量的时候,只能找到被指向那个变量的低字节的地址,到底要操作几个字节的空间是根据指针的类型来决定的。例如:

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
 
intmain(intargc,constchar*argv[]){
    
    charch1='a';
    charch2='b';
    charch3='c';
    charch4='d';
    int*p1=&ch4;
    *p1='a';
    printf("ch1 = %c\n",ch1);//ch1 = 0
    printf("ch2 = %c\n",ch2);//ch2 = 0
    printf("ch3 = %c\n",ch3);//ch3 = 0
    printf("ch4 = %c\n",ch4);//ch4 = a
    
    return0;
}

原理:这里指针操作指针指向的变量的时候,指针认为他指向的是int类型的变量,int类型占4个字节的空间,所以操作了4个字节的空间。

六、多级指针

一级指针:如果一个指针变量中存储的是一个普通变量的地址,那么这样的指针就叫做一级指针。

 
1
2
intnum=10;
int*p=&num;

二级指针:如果一个指针变量中存储的是一个一级指针变量的地址,那么这样的指针就叫做二级指针。

 
1
2
3
intnum=10;
int*p1=&num;
int**p2=&p1;

三级和多级同理。

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
 
intmain(){
    
    intnum=10;
    int*p1=&num;//p1存储num的地址
    int**p2=&p1;//p2存储p1的地址
    int***p3=&p2;//p3存储p2的地址
    
    *p1=100;//*p1取出num变量
    **p2=200;//**p2取出num变量
    ***p3=300;//***p3也是取出num变量
    printf("num = %d\n",num);
    printf("num = %d\n",***p3);
    
    return0;
}

七、指针与数组

指针可以和整数进行加减运算

 
1
2
3
4
5
6
7
charch='a';
char*p=&ch;
p++;//p的值增加了一个char类型字节数
 
intnum=10;
int*p1=&num;
p1++;//p1的值增加了一个int类型字节数

遍历数组大法:

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
#include <stdio.h>
 
intmain(){
    
    intnum[]={1,2,3,4,5,6,7,8,9,0};
    intlength=sizeof(num)/sizeof(int);
    int*p=num;
    
    //第一种,传统遍历大法
    for(inti=0;i<length;i++){
        printf("%d ",num[i]);
    }
    printf("\n");
    
    //第二种,移动地址指向 并取值来遍历
    for(inti=0;i<length;i++){
        printf("%d ",*(p+i));
    }
    printf("\n");
    
    //第三种,因为p == num,移动地址指向 并取值来遍历
    for(inti=0;i<length;i++){
        printf("%d ",*(num+i));
    }
    printf("\n");
    
    //第四种,根据每个元素的地址来获取值
    for(inti=0;i<length;i++){
        printf("%d ",*(&num[i]));
    }
    printf("\n");
    
    //第五种,根据每个元素的地址来获取值
    for(inti=0;i<length;i++){
        printf("%d ",*((&num[0]+i)));
    }
    printf("\n");
    
    //第六种,判断地址大小
    for(;p<=&num[length-1];p++){
        printf("%d ",*p);
    }
    //重置p的值
    p=num;
    printf("\n");
    
    //第七种,p自增
    for(inti=0;i<length;i++,p++){
        printf("%d ",*p);
    }
    //重置p的值
    p=num;
    printf("\n");
    
    //第八种,p自增
    for(inti=0;i<length;i++){
        printf("%d ",*(p++));
    }
    //重置p的值
    p=num;
    printf("\n");
    
    return0;
}

指针数组:

所谓的指针数组,指的是一个专门用来保存多个相同数据类型指针的数组。

 
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
#include <stdio.h>
 
intmain(intargc,constchar*argv[]){
    
    intnum1=10;
    intnum2=20;
    intnum3=30;
    
    int*p1=&num1;
    int*p2=&num2;
    int*p3=&num3;
    
    int*arr[]={p1,p2,p3};
    int**p4=arr;
    
    for(inti=0;i<3;i++){
        printf("%d\n",**(p4+i));
    }
    
    return0;
}

011-指针(上)-C语言笔记的更多相关文章

  1. 005-循环结构(上)-C语言笔记

    005-循环结构(上)-C语言笔记 学习目标 1.[掌握]switch-case结构 2.[理解]case语句穿透 3.[理解]Xcode断点调试 4.[理解]while循环结构初体验 5.[掌握]w ...

  2. 重新认识C语言的指针(上)

    ​ 独创性并不是首次观察某种新事物,而是把旧的.很早就是已知的,或者是人人都视而不见的事物当新事物观察,这才证明是有真正的独创头脑 -尼采 本文已经收录至我的GitHub,欢迎大家踊跃star 和 i ...

  3. C语言之漫谈指针(上)

    C语言之漫谈指针(上) 在C语言学习的途中,我们永远有一个绕不了的坑,那就是--指针. 在这篇文章中我们就谈一谈指针的一些基础知识. 纲要: 零.谈指针之前的小知识 一.指针与指针变量 二.指针变量的 ...

  4. R语言笔记

    R语言笔记 学习R语言对我来说有好几个地方需要注意的,我觉得这样的经验也适用于学习其他的新的语言. 语言的目标 我理解语言的目标就是这个语言是用来做什么的,为什么样的任务服务的,也就是设计这个语言的动 ...

  5. Go 语言笔记

    Go 语言笔记 基本概念 综述 Go 语言将静态语言的安全性和高效性与动态语言的易开发性进行有机结合,达到完美平衡. 设计者通过 goroutine 这种轻量级线程的概念来实现这个目标,然后通过 ch ...

  6. 013-结构体-C语言笔记

    013-结构体-C语言笔记 学习目录 1.[掌握]返回指针的函数 2.[掌握]指向函数的指针 3.[掌握]结构体的声明 4.[掌握]结构体与数组 5.[掌握]结构体与指针 6.[掌握]结构体的嵌套 7 ...

  7. 娓娓道来c指针 (0)c语言的梦魇:c指针

    (0)c语言的梦魇:c指针 序 c语言中有一个重点:c指针.它也是一个难点.当然,这是一句废话:重点往往也是难点.在c标准中,对指针的定义是这种: 指针的类型是derived from其他类型,也就是 ...

  8. 【C语言探索之旅】 第二部分第二课:进击的指针,C语言的王牌!

    内容简介 1.课程大纲 2.第二部分第二课: 进击的指针,C语言的王牌 3.第二部分第三课预告: 数组 课程大纲 我们的课程分为四大部分,每一个部分结束后都会有练习题,并会公布答案.还会带大家用C语言 ...

  9. Scala语言笔记 - 第一篇

    目录 Scala语言笔记 - 第一篇 1 基本类型和循环的使用 2 String相关 3 模式匹配相关 4 class相关 5 函数调用相关 Scala语言笔记 - 第一篇 ​ 最近研究了下scala ...

随机推荐

  1. Caused by: java.lang.IllegalArgumentException

    Caused by: java.lang.IllegalArgumentException 是因为jdk较高而项目需要的是低版本的问题 1.将idea或idea里的语言级别调到适合自己项目的版本比如安 ...

  2. 物联网 软硬件系统 树莓派 单片机 esp32 小程序 网页 开发 欢迎相互交流学习~

    物联网软硬件开发 知识分享 多年学生项目开发经验 物联网 软硬件系统 树莓派 单片机 esp32 小程序 网页 开发 欢迎相互交流学习~ http://39.105.218.125:9000/

  3. Functional mechanism: regression analysis under differential privacy_阅读报告

    Functional mechanism: regression analysis under differential privacy 论文学习报告 组员:裴建新   赖妍菱    周子玉 2020 ...

  4. 《JavaScript 模式》读书笔记(4)— 函数4

    这篇文章我们主要来学习下即时对象初始化.初始化时分支.函数属性-备忘模式以及配置对象.这篇的内容会有点多. 六.即时对象初始化 保护全局作用域不受污染的另一种方法,即时对象初始化模式.这种模式使用带有 ...

  5. 我们是怎么实现Grpc CodeFirst

    前言: Grpc默认是ProtoFirst的,即先写 proto文件,再生成代码,需要人工维护proto,生成的代码也不友好,所以出现了Grpc CodeFirst,下面来说说我们是怎么实现Grpc ...

  6. 强化学习之四:基于策略的Agents (Policy-based Agents)

    本文是对Arthur Juliani在Medium平台发布的强化学习系列教程的个人中文翻译,该翻译是基于个人分享知识的目的进行的,欢迎交流!(This article is my personal t ...

  7. 近期 github 机器学习热门项目top5

    磐创智能-专注机器学习深度学习的教程网站 http://panchuang.net/ 磐创AI-智能客服,聊天机器人,推荐系统 http://panchuangai.com/ [导读]:Github是 ...

  8. CNN更新换代!性能提升算力减半,还即插即用

    传统的卷积运算,要成为过去时了. Facebook和新加坡国立大学联手提出了新一代替代品:OctConv(Octave Convolution),效果惊艳,用起来还非常方便. OctConv就如同卷积 ...

  9. redis++:Redis的两种持久化 RDB 和 AOF

    Redis持久化备份数据的方式有两种:RDB(Redis DataBase) . AOF(Append Only  File). RDB 什么是RDB: 在指定时间间隔内,将内存中的数据集快照写入磁盘 ...

  10. 集合和映射(Set And Map)

    目录 集合 Set 基于二分搜索树实现集合 基于链表实现集合 集合的时间复杂度分析 映射 Map 基于链表实现映射 基于二分搜索树实现映射 映射的时间复杂度分析 leetcode上关于集合和映射的问题 ...