目录
目录
一、指针变量的定义
#include<stdio.h>
//指针变量的定义格式:数据类型 * 指针变量名
//数据类型:保存的地址上的数据类型,基类型
//指针变量:保存地址
//指针变量的类型:基类型
int main()
{
int a = 10;
int* p=NULL;
p = &a;//拿第一个编号来作为地址 &取地址运算符
//解引用 得到地址上的数据 解引用运算符 *
printf("%d ", *p);
char c = 's';
char* p1 = &c;//p1=&c,而不是*p1=&c
printf("%s ", p1);
return 0;
}
二、指针和函数的运用
1.改变指针变量的方向
#include<stdio.h>
int main()
{
int a = 10;
int b = 20;
int* p = &a;
*p = 1;//*p就相当于变量a,因为*p保存了变量a的地址
printf("%d ",a);
p = &b;
*p = 2;//将b的地址赋给p,覆盖a的地址
printf("%d ", b);
return 0;
}
2.函数的传参
#include<stdio.h>
void fun(int* x,int* y)//形参x,y接收整型数据的地址
{
*x = 1;//x=&a
*y = 2;//y=&b
}
int main()
{
//函数的传参
int a = 10;
int b = 20;
fun(&a,&b);
printf("%d %d", a, b);
return 0;
}
三、指针偏移
1)基类型所占字节数
在不同的系统上,这些类型占据的字节长度是不同的:
**16位编译器:
char/unsigned char :1字节
char :2字节
short int:2字节
int/unsigned int:2字节
long int:4字节
float:4字节
double:8字节*
32位编译器:
*char/unsigned char :1字节
char :4字节
short int:2字节
int/unsigned int:4字节
long int:4字节
float:4字节
double:8字节
long long:8字节
long double:12字节
64位编译器:
char/unsigned char :1字节
char *:8字节
short int:2字节
int/unsigned int:4字节
long int:8字节
float:4字节
double:8字节
long long:8字节
long double:16字节
2)指针偏移
#include<stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
for (int i = 0; i < 10; i++)
{
printf("arr[%d] : %#p\n\n", i, &arr[i]);//输出数组元素的地址 %p是地址的占位符
}
//定义指针变量 保存 数组元素的地址
int* p = arr;//数组的首地址 : arr或者&arr[0]
//如果int* p=整数型,则输出该整型值
p = p + 4;//加的是四个数组元素的大小 4*4=16
printf("%d\n", *p);
printf("%p\n", p);
return 0;
}
3)强制转换
#include<stdio.h>
int main()
{
int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
//强制转换
double* p = (double*)(arr);
p++;//p移动了8字节
printf("%d\n", *((int*)p));
return 0;
}
4)指针指向字符串
#include<stdio.h>
int main4()
{
//指针变量指向字符串常量的时候,不可以改变字符串常量
//但是可以改变指针变量的值
char* p = "abcdefg";
printf("%c\n\n", *p);
//*p = 'A'; 不合法 "abcdefg"是字符串常量 值不能被改变
//printf("%c", *p);
printf("%s\n\n", p);//p为地址 相当于数组名
printf("%d\n\n", sizeof(p));//p是四字节,所以长度为4
printf("%d\n\n", strlen(p));//以p为首地址,遇到\0结束
return 0;
}
四、指针进阶
1)内存四区
在系统为程序开辟内存时,将内存区域划分为四块,分别为:
栈区:存放函数的形参、局部变量等。由编译器自动分配和释放,当函数执行完毕时自动释放。
堆区:用于动态内存的申请与释放,一般由程序员手动分配和释放,若程序员不释放,则程序结束时由操作系统回收。记得释放动态内存,不然会造成空间浪费,导致一些空间不能够使用·,导致程序运行较慢,甚至一些程序访问不到内存运行失败报错。
全局静态常量区(全局区):存放常量(是字符串常量和其他常量)、全局变量和静态变量,在程序结束时有操作系统释放。
代码区:存放可执行的代码,一般为CPU执行的及机器指令。
2)结构体指针
(1)初始结构体指针
#include<stdio.h>
//申明结构体类型
struct node
{
int id;
char name[20];
};
int main()
{
//定义结构体变量
struct node n = { 45,"AAA" };
struct node* pn = NULL;//struct node是基类型
pn = &n;
printf("%d ", (*pn).id);//()里解引用完成后可以用. 否则用->
printf("%s ", pn->name);
printf("%d", (*pn));
}
(2)结构体指针数组
#include<stdio.h>
//申明结构体类型
struct node
{
int id;
char name[20];
};
int main()
{
struct node n[5] =
{
{1,"aaa"},
{2,"bbb"},
{3,"ccc"},
{4,"ddd"},
{5,"eee"},
};
struct node* p = ;
printf("%d %s\n", (*(p + 2)).id, (*p).name);//前面地址增加不影响后面的输出
printf("%d %s", (*(p + 3)).id, (*p).name);
}
运行结果:
(3)结构体中定义地址变量并调用
#include<stdio.h>
//申明结构体类型
struct node
{
int id;
char name[20];
struct node* next;//地址
};
int main()
{
struct node n[5] =
{
{1,"aaa",&n[1]},
{2,"bbb",&n[2]},
{3,"ccc",&n[3]},
{4,"ddd",&n[4]},
{5,"eee",NULL}
};
struct node* p = n;
//经典for循环
//for (int i = 0; i < 5; i++)
//{
// printf("%d %s\n", (p + i)->id, (p + i)->name);
//}
//调用结构体定义的地址变量
while (p != NULL)//当p等于null时退出循环
{
printf("%d %s\n", p->id, p->name);
p = p->next;//将p->next赋值给p 指向下一个地址
}
}
运行结果: