指针:
- 解决代码块与代码块之间的数据传递
- 一个变量的地址称为该变量的指针
指针变量:
- 用来存放另一个变量的地址的变量
- 指针变量的类型由指向的那个变量的类型决定
- 定义指针变量的时候必须赋初值,如果暂时没有初值就赋值NULL(0),没有被初始化的指针被称为失控指针(野指针)
- 内存地址 0 有特别重要的意义,它表明该指针不指向一个可访问的内存位置
- 指针变量只能存地址
- 指针变量本身永远只占据8个字节的内存空间(64位系统)
*
和&
:
*
用于定义指针变量,标识该变量是一个指针变量*
除了定义指针变量外,都是访问指针变量中可用地址的值&
是取一个变量的地址
一.指针的算术运算
C 指针是一个用数值表示的地址。因此,您可以对指针执行算术运算
我们喜欢使用指针代替数组,因为变量指针可以递增,而数组不能递增,数组可以看成一个指针常量
数组名并不是一个变量,没有分配内存空间,指针变量是有内存空间
定义一个数组,系统会分配内存空间,可以存值
定义一个指针变量,只为变量本身分配分配8个字节内存空间,不会为他分配可以存值的内存空间,无法存值
1.递增一个指针(递减一个指针同理)
//递增变量指针,以便顺序访问数组中的每一个元素
#include <stdio.h>
const int MAX = 3;
int main (){
int var[] = {10, 100, 200};
int i, *ptr;
/* 指针中的数组地址 */
ptr = var;
for ( i = 0; i < MAX; i++){
printf("存储地址:var[%d] = %x\n", i, ptr );
printf("存储值:var[%d] = %d\n", i, *ptr );
/* 移动到下一个位置 */
ptr++;
}
return 0;
}
//运行结果
存储地址:var[0] = bf882b30
存储值:var[0] = 10
存储地址:of var[1] = bf882b34
存储值: var[1] = 100
存储地址:of var[2] = bf882b38
存储值:var[2] = 200
2.指针的比较
指针可以用关系运算符进行比较,如 ==、< 和 >。
如果 p1 和 p2 指向两个相关的变量,比如同一个数组中的不同元素,则可对 p1 和 p2 进行大小比较。
//只要变量指针所指向的地址小于或等于
//数组的最后一个元素的地址 &var[MAX - 1]
//则把变量指针进行递增
#include <stdio.h>
const int MAX = 3;
int main (){
int var[] = {10, 100, 200};
int i, *ptr;
/* 指针中第一个元素的地址 */
ptr = var;
i = 0;
while ( ptr <= &var[MAX - 1] ) {
printf("Address of var[%d] = %x\n", i, ptr );
printf("Value of var[%d] = %d\n", i, *ptr );
/* 指向上一个位置 */
ptr++;
i++;
}
return 0;
}
//运行结果
Address of var[0] = bfdbcb20
Value of var[0] = 10
Address of var[1] = bfdbcb24
Value of var[1] = 100
Address of var[2] = bfdbcb28
Value of var[2] = 200
二.指针数组
int *ptr[MAX];
把 ptr 声明为一个数组,由 MAX 个整数指针组成。因此,ptr 中的每个元素,都是一个指向 int 值的指针
#include <stdio.h>
const int MAX = 3;
int main (){
int var[] = {10, 100, 200};
int i, *ptr[MAX];
for ( i = 0; i < MAX; i++){
ptr[i] = &var[i]; /* 赋值为整数的地址 */
}
for ( i = 0; i < MAX; i++) {
printf("Value of var[%d] = %d\n", i, *ptr[i] );
}
return 0;
}
//运行结果
Value of var[0] = 10
Value of var[1] = 100
Value of var[2] = 200
指针的一些复杂说明:
三.指向指针的指针
指向指针的指针
int **变量名;
是一种多级间接寻址的形式,或者说是一个指针链。通常,一个指针包含一个变量的地址。当我们定义一个指向指针的指针时,第一个指针包含了第二个指针的地址,第二个指针指向包含实际值的位置。
//当一个目标值被一个指针间接指向到另一个指针时
//访问这个值需要使用两个星号运算符
#include <stdio.h>
int main (){
int var;
int *ptr;
int **pptr;
var = 3000;
/* 获取 var 的地址 */
ptr = &var;
/* 使用运算符 & 获取 ptr 的地址 */
pptr = &ptr;
/* 使用 pptr 获取值 */
printf("Value of var = %d\n", var );
printf("Value available at *ptr = %d\n", *ptr );
printf("Value available at **pptr = %d\n", **pptr);
return 0;
}
//运行结果
Value of var = 3000
Value available at *ptr = 3000
Value available at **pptr = 3000
四.传递指针给函数
C 语言允许您传递指针给函数,只需要简单地声明函数参数为指针类型即可。
#include <stdio.h>
/* 函数声明 */
double getAverage(int *arr, int size);
int main (){
/* 带有 5 个元素的整型数组 */
int balance[5] = {1000, 2, 3, 17, 50};
double avg;
/* 传递一个指向数组的指针作为参数 */
avg = getAverage( balance, 5 ) ;
/* 输出返回值 */
printf("Average value is: %f\n", avg );
return 0;
}
double getAverage(int *arr, int size){
int i, sum = 0;
double avg;
for (i = 0; i < size; ++i)
{
sum += arr[i];
}
avg = (double)sum / size;
return avg;
}
//运行结果
Average value is: 214.40000
五.从函数返回指针
C 不支持在调用函数时返回局部变量的地址,除非定义局部变量为 static 变量。
因为局部变量是存储在内存的栈区内,当函数调用结束后,局部变量所占的内存地址便被释放了,因此当其函数执行完毕后,函数内的变量便不再拥有那个内存地址,所以不能返回其指针。
除非将其变量定义为 static 变量,static 变量的值存放在内存中的静态数据区,不会随着函数执行的结束而被清除,故能返回其地址。
//生成 10 个随机数,并使用表示指针的数组名(即第一个数组元素的地址)来返回它们
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
/* 要生成和返回随机数的函数 */
int * getRandom( ){
static int r[10];
int i;
/* 设置种子 */
srand( (unsigned)time( NULL ) );
for ( i = 0; i < 10; ++i){
r[i] = rand();
printf("%d\n", r[i] );
}
return r;
}
/* 要调用上面定义函数的主函数 */
int main (){
/* 一个指向整数的指针 */
int *p;
int i;
p = getRandom();
for ( i = 0; i < 10; i++ ){
printf("*(p + [%d]) : %d\n", i, *(p + i) );
}
return 0;
}
计算机并不能产生真正的随机数,而是已经编写好的一些无规则排列的数字存储在电脑里
把这些数字划分为若干相等的N份,并为每份加上一个编号用srand()函数获取这个编号
然后rand()就按顺序获取这些数字,当srand()的参数值固定的时候,rand()获得的数也是固定的
所以一般srand的参数用time(NULL),因为系统的时间一直在变,所以rand()获得的数也就一直在变,相当于是随机数了。
六.函数指针
https://www.jianshu.com/writer#/notebooks/29146076/notes/41287791/preview