C语言回顾(指针篇)

指针

指针就是一个地址。它指向(代表)了内存中的一块空间

指针的类型

1、指针的类型

把指针声明语句里的指针名字去掉,剩下的部分就是这个指针的类型

2、指针所指向的类型

把指针声明语句中的指针名字和名字左边的指针声明符*去掉,剩下的就是指针所指向的类型。

(1)int*ptr; //指针类型是int* 指针所指向的类型是 int
(2)int**ptr; //指针类型是int** 指针所指向的的类型是 int* 指向的内容也是一个指针a,这个指针a的类型是int* 指向的内容是int(这里的a是随便起的一个名字,方便描述)
(3)int(*ptr)[3]; //指针所指向的的类型是 int()[3]
(4)int*(*ptr)[4]; //指针所指向的的类型是 int*()[4] 指向的内容也是一个指针a,这个指针a的类型是int*()[4],a指向的类型int()[4],是有4个元素的数组,数组内容是int型(这里的a是随便起的一个名字,方便描述)

指针的运算

指针的自增自减运算的意义与通常的数值加减运算的意义不一样,其结果和指针指向的类型有关。

char a[20];
int *ptr=(int *)a; //强制类型转换并不会改变 a 的类型
ptr++;

指针所指向的类型是int,int的长度为4。ptr++,编译器对其增加了sizeof(int),所以ptr此时的值加了4,因为数组a是char类型,每个元素所占的长度为1,且地址连续,所以ptr此时所指的内容就是a[4]

struct Test
{
   int Num;
   char *pcName;
   short sDate;
   char cha[2];
   short sBa[4];
}*p;

假设p 的值为0x100000。如下表表达式的值分别为多少?
   p + 0x1 = 0x___ ?
   (int)p + 0x1 = 0x___?
   (int*)p + 0x1 = 0x___?

指针变量与一个整数相加减并不是用指针变量里的地址直接加减这个整数。这个整数的单位不是byte 而是元素的个数。所以:p + 0x1 的值为0x100000+sizof(Test)*0x1。至于此结构体的大小为20byte。所以p +0x1 的值为:0x100014。

(int)p + 0x1 的值呢?这里涉及到强制转换,将指针变量p 保存的值强制转换成型数。任何数值一旦被强制转换,其类型就改变了。所以这个表达式其实就是一个整型数加上另一个整数。所以其值为:0x100001。

( int*)p + 0x1 的值呢?这里的p 被强制转换成一个指向整型的指针。所以其值为:0x100000+sizof(int)*0x1,等于0x100004。

数组与指针

1、数组名

数组名相当于指针,指向数组的首地址

2、指针数组与数组指针

指针数组,数组中存储的内容是指针。数组指针,就是指向数组的指针。

int *p1[3];   // 指针数组 中括号[]的优先级高,因此与p1先结合,表示一个数组,这个数组中有3个元素,这3个元素都是指针,它们指向的是int型数据。可以这样来理解:如果有这个定义int p[3],很容易理解这是一个有3个int型元素的数组,那么把int换成int*,意味着数组里的元素类型是int*型(指向int型数据的指针)。

int (*p2)[3]; // 数组指针 小括号让p2与*结合,表示p2是一个指针,这个指针指向了一个数组,数组中有3个元素,每一个元素的类型是int型。可以这样来理解:如果有这个定义int p[3],很容易理解这是一个有3个int型元素的数组,那么把数组名p换成是*p2,也就是p2是一个指针,指向了这个数组。
int a = 1, b = 2, c = 3;
int *p1[3];
p1[0] = &a;
p1[1] = &b;
p1[2] = &c;
//如果p1++ ,则p1只是增加了sizeof(int),因为其指向的内容是int型。可以这样理解,中括号[]的优先级高,p1先与[]结合,再与*结合,p1与[3]结合后看做一个整体a 所以就变成了 int *a,所以指向的类型就是int
int a[3] = {1, 2, 3};
int (*p2)[3] = a;
printf("0x%x \n", p2++);
//如果p2++,则p2增加了12,因为其指向的类型是int ()[3],是一个包含三个元素的数组,其长度是12

a与&a

其实a和 &a结果都是数组的首地址,但他们的类型是不一样。a表示&a[0],也即对数组首元素取地址,a+1表示首地址+sizeof(元素类型)。&a虽然值为数组首元素地址,但类型为:类型 (*)[数组元素个数],所以&a+1大小为:首地址+sizeof(a)。

应该在了解数组名即是数组的首地址的同时,也要知道,数组名仅仅是“相当于”指针,而并非真的是指针,数组名是只是个常量(一个值为数组首元素地址的常量),所以不能进行++或者–运算。而常量更是无法取地址的,而之所以有&a,其实这里的a的意义早已经不是当初那个数组名了,它此时代表了整个数组。

结构体与指针

1、需要使用->箭头操作符来获取结构体中的成员变量

2、结构体名字不是地址,需要对其进行取址(&)操作。

函数与指针

函数指针,其本质是一个指针变量,该指针指向这个函数。总结来说,函数指针就是指向函数的指针。函数的名字就代表函数的地址。

/* 声明格式 类型说明符 (*函数名) (参数) */
int (*fun)(int x,int y);
/* 将一个函数的地址赋值给函数指针 下面两种方式都可以*/
fun = &Function;
fun = Function;
/* 函数指针的调用 下面两种都可以,建议第一种,清晰明确 */
x = (*fun)();
x = fun();

函数指针数组

int (*p[4])(int, int);//先分析中间部分,标识符p与中括号[]结合(优先级高),所以p是一个数组,数组中有4个元素;然后剩下的内容表示一个函数指针,那么就说明数组中的元素类型是函数指针,也就是其他函数的地址

/* 示例代码 */
int add(int a, int b) { return a + b; }
int sub(int a, int b) { return a - b; }
int mul(int a, int b) { return a * b; }
int divide(int a, int b) { return a / b; }

int main()
{
    int a = 4, b = 2;
    int (*p[4])(int, int);
    p[0] = add;
    p[1] = sub;
    p[2] = mul;
    p[3] = divide;
    printf("%d + %d = %d \n", a, b, p[0](a, b));
    printf("%d - %d = %d \n", a, b, p[1](a, b));
    printf("%d * %d = %d \n", a, b, p[2](a, b));
    printf("%d / %d = %d \n", a, b, p[3](a, b));
}

指针函数,简单的来说,就是一个返回指针的函数,其本质是一个函数,而该函数的返回值是一个指针。

/* 声明格式 类型标识符 *函数名(参数表)*/
int *fun(int x,int y);//返回值是一个地址

你可能感兴趣的:(嵌入式,c语言,数据结构)