c复习day06

内存

  • RAM:运行内存,所有的程序都会运行在上面
  • DDR2 DDR3主要的区别在于频率(读写的速率)
  • 物理存储器
  • 启动一个程序系统会在内存是给程序分配一块内存空间
  • 内存由一个个字节组成每个字节都会有地址编号我们把这个编号(地址)叫做指针

指针变量

  • 存放指针(地址)的变量
  • 因为地址的编号(0x0000 0000),所以我们的指针4个字节就可以存下
  • 64位编译器,内存的编号,需要8个字节

指针变量的定义和初始化

  1. *与符号结合代表是一个指针变量
  2. 要保存谁的地址,将他的 定义形式放在此处
  3. 用*p替换掉定义的变量
1
2
3
4
5
6
7
#include <stdio.h>
int main()
{
int a = 10;
int *P = &a;

}
  1. p是变量,p的类型是将变量本身涂黑,剩下的就是指针变量的类型int *
  2. 指针变量p用来保存什么类型数据的地址,将指针变量p和距离指针变量最近的*一起涂黑
  3. 剩下什么类型就是保存什么类型数据的地址

指针变量保存了谁的地址就指向了谁

1
*p = 100;
  • 在使用的时候*与怕结合代表,取p指针所指向的那块空间的内容

在使用时,对一个表达式取*,就会对表达式减一级 *,如果对表达式取&就会加 *

指针变量的大小

  • 不管什么类型的指针,大小只和系统编译器有关
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>
int main()
{
char *p1;
short *p2;
int *p3;
int **p3;

printf("%d\n",sizeof(p1));
printf("%d\n",sizeof(p2));
printf("%d\n",sizeof(p3));
printf("%d\n",sizeof(p4));

return 0;

}

不同类型的指针变量,取指针指向的内容宽度

  • 指针的宽度 = sizeof(将指针变量与指针变量最近的*涂黑,剩下的类型)

  • 宽度也就做步长

  • 步长:指针加1跨过多少字节

  • char *p 1

  • short *p 2

  • int *p 4

  • int **p sizeof (int *) 4

  • 通过*取指针变量所在那块空间的内容时,取的内存宽度和指针变量本身的类型有关

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
int main()
{
int num = 0x01020304;
char *p1 = (char *)&num;
short *p2 = (short *)&num;
int *p3 = (int *)&num;

printf("%x\n",*p1);
printf("%x\n",*p2);
printf("%x\n",*p3);

return 0;

}

野指针

  • 野指针就是没有初始化的指针,指针的指向是随机的,不可以操作野指针
  • 指针保存的地址一定是定义过的(向系统申请过的
1
2
3
4
5
6
7
8
9
10
#include <stdio.h>
int main()
{
int *p;//野指针
*p = 200;
printf("%d\n",*p);

return 0;

}

空指针

  • 将使用完的指针赋值位NULL,在使用时判断一下指针是否位NULL,就知道指针有没有被使用
1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
int main()
{
int a;
int *P = NULL;//给指针p的内容赋值为0

*p = 300;//因为保存了0地址,这个地址是不可以使用的
printf("%d\n",*p);

return 0;

}

万能指针

  • 万能指针可以保存任意的地址
  • 不可以定义void类型的变量,以为编译器不知道给变量分配多大空间
  • 但是可以定义void *类型,以为指针都是4个字节
  • 万能指针可以保存任意地址
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
#include <stdio.h>
int main()
{
//void a;
int a = 10;
int b = 30;

void *p = (void *)&a;//万能指针可以保存任意地址
void *q = (void *)&b;

//printf("%d\n",*p);//erro p是void*,不知道取几个字节的大小
printf("%d\n",*(int *)p);
printf("%d\n",*(short *)p);
return 0;
}

const修饰的指针变量

  • 需要注意的是const修饰的是p还是*
1
2
3
4
5
6
7
8
9
10
11
12
#include <stdio.h>
int main()
{
int a = 10;
int b = 20;
const int *p = &a;//不能通过*p修改p所指向空间的内容
int * const q = &b;//不能修该q保存的地址

const int *const p1 = &a;
return 0;

}

多级指针

  • 定义多级指针保存数据的地址时,定义的指针的类型只需要比要保持的数据多一级*
  • *符号结合,代表这是一个指针变量
  • 将标识符涂黑,剩下的是标识符的类型
  • 将标识符和最近的*涂黑,就是保存什么类型的地址
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
int main()
{
int a = 10;
//*p int a int *p
int *p = &a;
//*q int *p int **q
int **q = &p;
//如果*&相遇,相互抵消
//**q = *(*p) = *(&a) == a;
printf("%d\n",**p);
return 0;
}

指针结合数组

  • 指针加1,跨过一个步长
  • int *p;
  • 步长:sizeof(int)
  • 要得到内存的数据,就应该先得到数据的地址,*(地址)得到的就是地址里面的内容
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <stdio.h>
int main()
{
int a[10] = {0};
//a :数组名,首元素地址
int *p = a;//指针p保存的是首元素的地址
for (int i = 0;i < sizeof(a)/sizeof(a[0]);i++)
{
//printf("%d ",a[i]);
//printf("%d ",*(p+1));
*(p+i) = i;
}
for ( int i = 0; i < sizeof(a)/sizeof(a[0]); i++)
{
printf("%d ",a[i]);
}

return 0;
}

指针运算

  • 指针(类型一致)相减得到的是中间快过多少元素
  • 两个指针相加没有意义
1
2
3
4
5
6
7
8
9
10
11
12
13
#include <stdio.h>
int main()
{
int a[10] = {1,2,3,4,5,6,7,8,9,10};
int *p = a;
//int *q = &a[9];
int *q = (int *)(&a + 1) - 1;

printf("%d\n",q-p);//p+9 = q
printf("%d\n",*(p+3));

return 0;
}

[] 不是数组的专属

  • [ } = = *( )
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h>
int main()
{
int a[10] = {1,2,3,4,5,6,7,8,9,10};
int *p = a;
for (int i = 0; i < sizeof(a) / sizeof(a[0]); i++)
{
// printf("%d ",a[i]);
// printf("%d ",*(p+i));
// printf("%d ",p[i]);
printf("%d ",*(a + i));
}
printf("\n");

int b = 10;
int *q = &b;
q[0] = 100;
printf("%d ",b);

return 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
#include <stdio.h> 
int main()
{
int a = 10;
int b = 20;
int c = 30;
//需求:数组中的每一个元素都是指针(地址)

int *num[3] = {&a,&b,&c};
printf("%d\n",sizeof(num));

for (int i = 0; i < sizeof(num)/sizeof(num[0]); i++)
{
printf("%d ",*num[i]);
}
printf("\n");
//定义一个指针用来保存数组num首元素的地址
//因为num[0]是int *类型,要保存int *类型的地址,要比他多一级的*
int **k = num;
for (int i = 0; i < sizeof(num)/sizeof(num[0]); i++)
{
printf("%d ",**(k + i));
}
return 0;
}

指针作为函数的形参

  • 指针作为函数的形参,可以改变实参的值
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
#include <stdio.h>
void swap(int *,int *);
int main()
{
int a = 10;
int b = 20;
swap(&a,&b);
printf("a = %d,b = %d\n",a,b);
return 0;
}
void swap(int *x,int *y)
{
int temp = *x;
*x = *y;
*y = temp;

}

数组作为函数的形参

  • 数组作为函数的形参会退化为指针
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
#include <stdio.h>
void printarr(int *b,int n);
int main()
{
int a[10] = {1,2,3,4,5,6,7,8,9,10};
printarr(a,sizeof(a)/sizeof(a[0]));
printf("\n");
return 0;
}
void printarr(int *b,int n)
{
for (int i = 0; i < n; i++)
{
printf("%d ",b[i]);
}
}

指针作为函数的返回值

  • 在函数外面定义的变量叫做全局变量整个工程都可以使用
  • 整个变量在程序启动时开辟空间,知道程序结束释放空间
  • {} 中定义的变量叫做局部变量,局部变量在函数结束之后就会被释放
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
#include <stdio.h>
#include <time.h>
#include <stdlib.h>

int num = 0;
int * getnum();
int main()
{
int *p = getnum();
printf("%d \n",*p);
return 0;
}

int * getnum()
{
srand(time(NULL));
num = rand();
return &num;
}
你的支持是我最大的动力!
0%