day13-c指针,函数

day13-c指针,函数

一、复习

1、指针数组

​ 本质:数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
<存储类型> <数据类型>*指针数组名[元素个数];
char a[50] = "hello";
char b[50] = "asd";
char c[50] = "qwe";
char *p[3] = {a, b, c};
p[0] == a;
p[2] == b;
p[3] //error
*(p[0]) == 'h'

char **q = p = &a;
q+1 = p+1 = &b;
*q = *p = *(&a) == a;
**q = *a = 'h'

p == &p[0];

int a[2][3] = {1,2,3,4,5,6};
int *p[2] = {a[0], a[1]};
*(p[0]) == **p == p[0][0] = a[0][0];

2、二级指针

​ 将一级指针的地址称为二级指针

​ int a = 2;

​ int *p = &a;

​ int **q = &p; //q就是定义的一个二级指针,地址中存放一级指针的值

3、const指针

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
int a = 2;
int b = 3;
int *p = &a;

const int *p = &a;
p = &b; //right
*p = 10; //error

int * const p = &a;
p = &b; //error
*p = 10; //right

const int *const p = &a;
p = &b; //error
*p = 10; //error

4、void指针

1
2
3
4
5
6
7
8
9
10
int a = 2;
char b = 'k';
void *p = &a;
p = &b;
p+1 // error void类型指针在使用时需要类型强转
(int *)p+1 // 偏移4字节
(char *)p+1 // 偏移1字节

注意:void类型的指针不能使用递增递减运算符

5、字符指针和字符串

1
2
3
4
5
6
7
char a[6] = "haha";
char *p = "hello"; //将字符串hello的首地址赋值给指针变量p
printf("%c\n", *p); //right
*p = 'z'; //error hello是一个字符串常量,不能修改里面的字符

strcpy(p, "asd"); //error
strcpy(a, "asd"); //right

二、函数

概念:函数是一个实现特定功能的代码模块,函数有返回值,也可能没有

​ 返回值:函数的结果

1、函数的封装(定义)

1
2
3
4
5
6
7
8
9
10
11
12
一般形式:
<数据类型> 函数名(形式参数)
{
功能代码模块; //语句块

return 表达式;
}
数据类型:跟函数返回值的类型一致,如果一个函数没有返回值,则填void
函数名:遵循标识符标识符的命名规范,函数命名一般和功能相关。函数名也代表函数的起始地址
形式参数:形式参数决定了,函数调用时需要传入的实参的个数、类型、顺序,多个形式参数之间用逗号隔开。
如果函数不需要形式参数,可以省略不写,或者填void
return:函数结束的标志,后面的表达式的值为函数的结果。如果没有返回值,可以选择不填或者只填return

2、函数的调用

1
2
3
一般形式:
函数名(实际参数);
实际参数必须跟形式参数的个数、类型、顺序一致。如果没有形式参数,那么实际参数可以省略

3、函数的声明

​ 在使用函数之前需要对函数进行函数声明

1
2
3
4
声明的一般形式:
<数据类型> 函数名(形式参数);

函数的声明中变量名是可以省略的

注:在add.h中声明了#include <stdio.h>后,在其他要用到#include <stdio.h>的函数中可以直接声明#include”add.h”就行。

4、头文件一般格式

1
2
3
4
5
6
7
8
9
#ifndef __ADD_H__
#define __ADD_H__

头文件声明

函数声明

#endif

5、函数的传参

(1)赋值传递

  在调用函数时,将普通变量的值直接赋值给形参。因为形式参数和实际参数在内存中存储的地址不同,所以 在函数中无论怎样改变形式参数的值,对实际参数是没有任何影响的

(2)地址传递

  在调用函数时,将普通变量的地址直接赋值给形参。可以通过修改形式参数,间接修改实参的值

(3)全局变量

  因为全局变量的作用域在整个文件中有效,所有在当前文件的任何一个函数中都可以当作参数使用

6、数组传参

  数组传参需要传入指定数组的首地址,如果该数组是一个整型数组,那么在传入数组首地址的同时,还需要传入数组元素的个数




7、易错点

1
2
3
4
5
6
7
int a[3][3]={1,2,3,4,5,6,7,8,9};
int *p[3]=a; //error
int *p=a;//error
sizeof(a[0]);//error一定为8

int row=a[1]-a[0]; //二维数组列数计算,用下一行的地址减去第一行的地址。即使二维数组只有一列也行
int line=sizeof(a)/(row*sizeof(a[0][0]));​ //二维数组行数计算

指针数组与数组指针的区别

例:
int a[2][3]={1,2,3,4,5,6};
int (*p)[3]=a;
int *p[2]={a[0],a[1]};

指针数组 数组指针
本质 元素是指针的数组 指向数组的行指针
形式 int *p[3]={a[0],a[1]}; int (*p)[3]=a;
p+1 =&p[1]=&a[1]=&&a[1][0] =&p[1]=&a[1]=&&a[1][0]
sizeof(p) 整个数组的大小 一定为8(即指针的大小)
*(p+1)值一样但形式不一样 p[1]=a[1]=&a[1][0] =a[1]=&a[1][0]
sizeof(*p) 一定为8(即指针的大小) 一列的大小
二级指针x 有二级指针 int **x=p 没有二级指针,不能 int **x=p
**p =**x=*p[0]=*a[0]=a[0][0] =*a[0]=a[0][0]

Donate
  • Copyright: Copyright is owned by the author. For commercial reprints, please contact the author for authorization. For non-commercial reprints, please indicate the source.
  • Copyrights © 2020-2024 nakano-mahiro
  • Visitors: | Views:

请我喝杯咖啡吧~

支付宝
微信