网易云课堂_C语言程序设计进阶_第二周:指针:取地址运算和指针、使用指针、指针与数组、指针与函数、指针与const、指针运算、动态内存分配...

 

2.1指针的使用

2.2指针的计算

2.3字符串操作

2.4字符串函数的实现

 

2.1指针的使用

 

指针应用场景一

交换两个变量的值

 

1 void swap(int *pa, int *pb)
2 {
3     int t = *pa;
4     *pa = *pb;
5     *pb = t;
6 }

 

指针应用场景二a

函数返回多个值,某些值就只能通过指针返回

传入的参数实际上是需要保存带回的结果的变量

 

 1 #define _CRT_SECURE_NO_WARNINGS
 2 
 3 #include <stdio.h>
 4 #include <stdlib.h>
 5 
 6 void minmax(int a[], int len, int *max, int *min);
 7 
 8 main()
 9 {
10     int a[] = { 1,2,3,4,5,6,7,8,9,12,13,14,16,17,21,23,55, };
11     int min, max;
12 
13     minmax(a, sizeof(a) / sizeof(a[0]), &max, &min);
14 
15     printf("min=%d,max=%d\n", min, max);
16 
17     system("pause");
18 }
19 
20 void minmax(int a[], int len, int *max, int *min)
21 {
22     int i;
23     *min = *max = a[0];
24 
25     for (i = 1;i < len;i++)
26     {
27         if (a[i] < *min)
28         {
29             *min = a[i];
30         }
31         if (a[i] > *max)
32         {
33             *max = a[i];
34         }
35     }
36 }

 

指针应用场景二b

函数返回运算的状态,结果通过指针返回

常用的套路是让函数返回特殊的不属于有效范围内的值来表示出粗:

-1或0(在文件操作会看到大量的例子)

但是当任何数值都是有效的可能结果时,就得分开返回了

 

状态用函数return返回,结果值通过指针参数返回。

好处:容易把状态放到if语句

 

 1 #define _CRT_SECURE_NO_WARNINGS
 2 
 3 #include <stdio.h>
 4 #include <stdlib.h>
 5 
 6 int divide(int a, int b, int *result);
 7 
 8 main()
 9 {
10     int a = 5;
11     int b = 2;
12     int c;
13 
14     if (divide(a, b, &c))
15     {
16         printf("%d/%d=%d\n", a, b, c);
17     }
18 
19     system("pause");
20 }
21 
22 int divide(int a, int b, int *result)
23 {
24     int ret = 1;
25 
26     if (b == 0)
27     {
28         ret = 0;
29     }
30     else
31     {
32         *result = a / b;
33     }
34     return ret;
35 }

 

指针最常见的错误

定义了指针变量,还没有指向任何变量,就开始是使用指针

 

p指向了一个未知地址,赋值可能会使得程序崩溃

 

严重性 代码 说明 项目 文件 行 禁止显示状态
错误 C4700 使用了未初始化的局部变量“p”

 

 1 #define _CRT_SECURE_NO_WARNINGS
 2 
 3 #include <stdio.h>
 4 #include <stdlib.h>
 5 
 6 main()
 7 {
 8     int i = 6;
 9     int *p;
10     int k;
11     k = 12;
12     *p = 12;
13 
14     system("pause");
15 }

 

数组参数

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

1 int sum(int *ar, int n);
2 int sum(int *,int);
3 int sum(int ar[], int n);
4 int sum(int[], int);

 

数组变量是特殊的指针

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

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

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

a == &a[0];

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

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

 

1     int min = 2;
2 
3     int *p = &min;
4 
5     printf("%d,%d\n", *p, p[0]);

 

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

*a = 25;

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

 

指针是const

表示一旦得到了某个变量的地址,不能再指向其他变量

 

严重性 代码 说明 项目 文件 行 禁止显示状态
错误 C2166 左值指定 const 对象

 

1     int i = 1;
2     int * const q = &i;//q是const
3 
4     *q = 26;//OK
5 
6     q++;//ERROR

 

所指是const

表示不能通过这个指针去修改那个变量(并不能使得那个变量成为const)

 

1     int i = 1;
2     int j = 1;
3 
4     const int *p = &i;//ERROR (*p)是const
5 
6     i = 26;//OK
7 
8     p = &j;//OK

 

判断哪个被const了的标志是const在*的左边还是右边

 

1     int i = 1;
2     
3     const int *p1 = &i;
4     int const *p2 = &i;
5     int * const p3 = &i;

 

转换

总是可以把一个非const的值转换成const的

比如:结构体

 

1     int a = 15;
2     f(&a);
3     const int b = a;
4 
5     f(&b);//OK
6 
7     b = a + 1;//ERROR

 

当要传递的参数的类型比地址大的时候,这是常用的手段:既能用比较少的字节数传递值给参数,又能避免函数对外面的变量的修改

 

const数组

const int a[]={1,2,3,4,5,6,};

数组变量已经是const的指针了,这里的const表明数组的每个单元都是const int

所以必须通过初始化进行赋值

 

保护数组值

因为把数组传入函数时传递的是地址,所以那个函数内部可以修改数组的值

为了保护数组不被函数破坏,可以设置参数为const

int sum(const int a[], int length);

 

2.2指针的计算

 

指针运算

这些算术运算可以对指针做:
给指针加、减一个整数(+, +=, -, -=)

递增递减(++/--)

两个指针相减

 

1     int a[] = { 1,2,3,4,5,6,7,8 };
2 
3     int *p1 = &a[0];
4     int *p2 = &a[4];
5 
6     printf("%d\n", p2 - p1);//4

 

*p++

取出p所指的那个数据来,完事之后顺便把p移到下一个位置去

*p的优先级虽然高,但是没有++高

常用于数组类的连续空间操作

在某些CPU上,这可以直接被翻译成一条汇编指令

 

指针比较

<, <=, ==, >, >=, !=都可以对指针做

比较它们在内存中的地址

数组中的单元的地址肯定是线性递增的

 

0地址

当然你的内存中有0地址,但是0地址通常是个不能随便碰的地址

所以你的指针不应该具有0值

因此可以用0地址来表示特殊的事情:

返回的指针是无效的

指针没有被真正初始化(先初始化为0)

NULL是一个预定定义的符号,表示0地址

有的编译器不愿意你用0来表示0地址

 

指针的类型转换

void *表示不知道指向什么东西的指针

计算时与char *相同(但不相通)

指针也可以转换类型

int *p=&i;

void *q=(void *)p;

这并没有改变p所指的变量的类型,而是让后人用不同的眼光通过p看它所指的变量

 

用指针来做什么

需要传入较大的数据时用作参数

传入数组后对数组做操作

函数返回不至一个结果

需要用函数来修改不止一个变量

动态申请的内存

 

输入数据

如果输入数据时,先告诉你个数,然后再输入,要记录每个数据

C99可以用变量做数组定义的大小,C99之前呢?

int *a=(int *)malloc(n*sizeof(int));

 

malloc

#include <stdlib.h>

void * malloc(size_t size);

向malloc申请的空间的大小是以字节为单位的

返回的结果是void *,需要类型转换为自己需要的类型

(int *)malloc(n*sizeof(int))

 

 1 #define _CRT_SECURE_NO_WARNINGS
 2 
 3 #include <stdio.h>
 4 #include <stdlib.h>
 5 
 6 main()
 7 {
 8     int num;
 9     int *a;
10     int i;
11     scanf("%d", &num);
12 
13     a = (int *)malloc(num*sizeof(int));
14 
15     for (i = 0;i < num;i++)
16     {
17         scanf("%d", &a[i]);
18     }
19 
20     for (i = num - 1;i >= 0;i--)
21     {
22         printf("%d ", a[i]);
23     }
24 
25     free(a);
26         
27     system("pause");
28 }

 

没空间了?

如果申请失败则返回0,或者叫做NULL

 

free()

把申请得来的空间还给“系统”

申请过的空间,最终都应该要还

只能还申请来的空间的首地址

 

常见问题

申请了没free->长时间运行内存逐渐下降

新手:忘了

老手:找不到合适的free的时间

free过了再free

地址变过了,直接去free

 

办法:

写了一个malloc,马上写上free

 

 1     int a[] = { 0 };
 2     int *p = a;
 3 
 4     if (p == a[0])//false
 5     {
 6         printf("true\n");
 7     }
 8     else
 9     {
10         printf("false\n");
11     }
12 
13     if (p == &a[0])//true
14     {
15         printf("true\n");
16     }
17     else
18     {
19         printf("false\n");
20     }
21 
22     if (*p == a[0])//true
23     {
24         printf("true\n");
25     }
26     else
27     {
28         printf("false\n");
29     }
30         
31     if (p[0] == a[0])//true
32     {
33         printf("true\n");
34     }
35     else
36     {
37         printf("false\n");
38     }

 

2.3字符串操作

 

putchar

int putchar(int c);

向标准输出写一个字符

返回写了几个字符,EOF(-1)表示写失败

 

getchar

int getchar(int c);

向标准输入读入一个字符

返回类型是int是为了返回EOF(-1)

Windows->Ctrl-Z

Unix->Ctrl-D

 

字符串数组和字符型指针数组不一样

char ch[3][5] <> char *pa[3]

 

image

 

程序参数

int main(int argc, char const *argv[])

argv[0]是命令本身

当使用Unix的符号链接时,反映符号链接的名字

 

2.4字符串函数的实现

 

strlen

size_t strlen(const char *s);

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

 

strcmp

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

比较两个字符串,返回:

0: s1==s2

1: s1>s2

-1: s1<s2

 

strcpy

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

把str的字符串拷贝到dst

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

返回dst

为了能链起代码来

 

字符串中找字符

char *strchr(const char *s, int c);

char *strrchr(const char *s, int c);

返回NULL表示没有找到

 

字符串中找字符串

char *strstr(const char *s1, const char *s2);

char *strcasestr(const char *s1, const char *s2);

 

转载于:https://www.cnblogs.com/denggelin/p/5579079.html

  • 0
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值