C语言指针详解

来源:互联网 发布:淘宝上卖高仿鞋 编辑:程序博客网 时间:2024/06/11 00:21
1、指针的概念:
指针变量也是一个变量
指针存放的内容是一个地址,该地址指向一块内存空间

2、指针的用法:
可以定义一个指向一个变量的指针变量。
int *p;//表示定义一个指针变量。
*p;//代表指针所指内存的实际数据
切记,指针变量只能存放地址,不能将一个int型变量直接赋值给一个指针。
int *p = 100;
代码:
#include <stdio.h>

int main()
{
int a = 10;
int *p;//定义一个指针变量p ,p是一个存放整型的的内存
p = &a;//让指针p指向a的地址 (a的地址用&a 获取)
printf("p的值为:%p\n", p);//打印指针的值
*p = 10;//修改指针的中存放的值
printf("p的值为:%p\n", p);//打印指针的值

printf("a的值为:%d\n", a);//再打印a值 打印的结果为10,a通过指针间接的改变了a的值 等价于printf("a的值为:%d\n", *p);
//printf("a的值为:%d\n", *p);

int b = *p;
printf("b的地址为:%p\n", &b);

return 0;
}
打印结果:
p的值为:00DBFE14
p的值为:00DBFE14
a的值为:10
b的地址为:00DBFDFC

3 数组与指针
1 数组名就是数据的指针名:
2 数组指针指向的地址是数组的第一个元素的地址
int arr[10];
printf("%u,%u,%u\n", arr, &arr[0], &arr[1]);
打印结果:
6225508,6225508,6225512
3 用指针给数组赋值
代码:
#include <stdio.h>
void print_s(char s[]);

int main()
{
int s[10];
int *p = s;
printf("p = %p\n", p);//此时数组指向的数组的第一个字符
for (int i = 0; i < 10; i++)
{
*p = i * 10;
printf("p = %d\n", p);
p += 4;//这里p++也相当于p += 4
}
print_s(s);
printf("p = %p\n", p);//此时数组指向的数组的第最后一个字符
return 0;
}
void print_s(int s[]) //打印字符串的数组
{
for (int i = 0; i < 10;i++)
{
printf("s[%d] = %d\n", i, i * 10);
}
}
打印结果:
p = 0031F828
p = 3274792
p = 3274808
p = 3274824
p = 3274840
p = 3274856
p = 3274872
p = 3274888
p = 3274904
p = 3274920
p = 3274936
s[0] = 0
s[1] = 10
s[2] = 20
s[3] = 30
s[4] = 40
s[5] = 50
s[6] = 60
s[7] = 70
s[8] = 80
s[9] = 90
p = 0031F8C8
4 把ip字符串转换成int类型整数再转成ip
代码:
#include <stdio.h>
int ip2int(char ip[]);
void int2ip(int n);

int main()
{
char s[] = "192.168.2.1";//定义一个ip字符串
int ipint = ip2int(s);
int2ip(ipint);
return 0;
}

int ip2int(char ip[]) //将字符串转化为一个int整数
{
int a, b, c, d;
sscanf(ip, "%d.%d.%d.%d", &a, &b, &c, &d);//分别读取字符串的数字部分
printf("a=%d,b=%d,c=%d,d=%d\n", a, b, c, d);
int intip = 0;
char *p = &intip;
*p = a;
p++;
*p = b;
p++;
*p = c;
p++;
*p = d;
printf("ip = %d\n", intip);
return intip;
}

void int2ip( int n)//将一个整数转为ip并打印
{
unsigned char *p = &n;
printf("%u.%u.%u.%u\n", *p, *(p + 1), *(p + 2), *(p + 3));
}
打印结果:
a=192,b=168,c=2,d=1
ip = 16951488
192.168.2.1
5 求数组中第二大元素
代码:
int second_e(int *ar)
{
int *p = ar;
int max = 0;//用来放数组中最大的元素
int second = 0;
int min_dis = 0;//来
for (int i = 0; i < 10; i++)
{
if (*(p + i) > max)
{
max = *(p + i);
}
}
p = ar;
int cnt = 0;
while (max - (*p) == 0)
{
p++;
cnt++;
}
min_dis = max - (*p);
printf("%d\n", min_dis);
second = *p;
printf("%d\n", second);
printf("cnt=%d\n", cnt);
for (int i = 0; i < 10-cnt; i++)
{
if (max - (*(p + i)) < min_dis && max - (*(p + i)) != 0)
{
min_dis = max - (*(p + i));
second = *(p + i);
}
}
return second;
}
6 数组与多维数组
在二维数组zip[3][2]中:
1 ,zip是首元素的地址 所以 *zip == zip[0] 相同 又 zip[0] 是第一个数组元素的地址 所以 *(zip[0]) == zip[0][0]  所以 **zip == zip[0][0]   zip==&zip[0] == &zip[0][0];
2 ,zip是一个指向 zip[0] zip[0]是有两int类型元素的数组长度为8,所以zip+1 会在zip的基本上加8
*zip 是zip[0][0] 是一个int类型整数 ,长度为4 ,所以*zip +1 会在*zip 的基础上加止4
3 ,zip 是地址的地址,也是就指针指针,双重间接的典型例子
4 ,声明一个指向二维数组的指针 int (*p)[2]  
代码:
void zip()
{
int zip[3][2] = { { 1,2 },{ 3,4 } ,{ 5,6 } };
int(*p)[2]; //定义一个指向二个int类型元素的数组的指针
p = zip;//zip指向是&zip[0]  
printfzip(zip);
//int *p = zip;
printf("zip = %p zip[0] = %p, zip[0][0] = %p \n", zip, &zip[0], &zip[0][0]); //多维数组的指针就是第一个第一个元素的地址 结果:zip = 0028F830 zip[0] = 0028F830, zip[0][0] = 0028F830
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 2; j++)
{
printf("&zip[%d][%d] = %p, ", i, j, &zip[i][j]);
}
printf("\n");
}
printf("zip = %p; *zip = %p\n", zip, *zip);
int *p1, *p2;
p1 = zip + 1;// 在zip的基础上加了8
p2= *zip + 1;//在*zip 的基础加了4
printf("p1 = %p, p2 = %p\n", p1,p2);//结果:p1 = 0028F834


int(*p)[2]; //定义一个指向二个int类型元素的数组的指针
p = zip;//zip是&zip[0]  指向一个二个int类型元素的数组的指针
}

void printfzip(int **ar)//打印的一个二维数组
{
int *p = ar;
for (int i = 0; i < 3; i++)
{
for (int j = 0; j < 2; j++)
{
printf("zip[%d][%d] = %d, ", i,j,*p++);
}
printf("\n");
}
}

4 无类型指针
定义一个指针变量,但不指定它指向具体哪种数据类型。可以通过强制转化将void *转化为其他类型指针,也可以用(void *)将其他类型指针强制转化为void类型指针。
void *p //无类型指针只是一个指针变量,不指向具体的数据类型
p = NULL; //值为NULL的为空指针,没有值的指针变量为野指针

代码:
int *p ;//p 在这里就是一个野指针
p
5 指针兼容性
指针之间赋值比普通数据类型赋值检查更为严格,例如:不可以把一个double *赋值给int *
原则上一定是相同类型的指针指向相同类型的变量地址,不能用一种类型的指针指向另一种类型的变量地址。
代码:
int i = 0x1314;
char *p1 = &i;
printf("%x\n", *p1);//打印结果为14
打印结果:
14
结果分析:
int i 在内存占4个字节存放的方式为:14 13 00 00
当把你i的地址给p1 ,p1是一个指向char类型的指针,char只有一个字节,所以p1中能读取其中的第一个字节的内容也就是14,所以打印出十六进制的14

6 指向常量的指针与常量指针
const char *p;//定义一个指向常量的指针
char *const p;//定义一个指针常量,一旦初始化之后其内容不可改变
代码:
#include <stdio.h>

int main()
{
int a = 10;
int b = 20;
char *p = &a;//定义一个指向常量的指针 即*p 是一个常量
//*p = 30; //非法操作 因为*p是一个常量,不能直接用“=”赋值
a = 30;//合法
printf("%d\n", *p); //打印结果 30
p = &b; //合法
printf("%d\n", *p); //打印结果 20

char *const p2 = &a;//定义一个指针常量,一旦初始化之后其内容不可改变
//p2 = &b;//非法操作 p2 是一个常量,不能直接用“=”赋值
*p2 = 40;
printf("%d\n", *p2);
a = 50;//
printf("%d\n", *p2);
return 0;
}
打印结果:
30
20
40
50
总结:
1 指向常量的的指针(const char *p = &a) 不能执行 *p = 10 操作)
2 常量指针(char *const p = &a一旦初始化之后其内容不可改变 不能执行p = &b 操作

7 指针与函数
1 int sum(int *ar,int n) 与 int sum(int ar[],int n) 两种写法是等价的
2 sum函数 有两个 参数 ,一个int 数组类型的指针, 一个int类型 整数
在调用sum时,传入函数的只是数据的指针,指针操作的数据就是原数组数据 所以函数是可以改变数组的
3 如果不想破坏原数组中的数据可以使用const 关键
int sum(const int *ar,int n) //告诉编译器把 ar 指向的数组当成常量不能改变
所以不需要修改数组的时候只可以用const 关键字来保护数组数据,如果要通过函数改变数组就去掉const 关键字
4 常量的地址不能赋给普通指针,否则可以通过指针改变常量的值
int ar[10] = { 2,1,24,12,25,41,26,23,52,14};
const int ar1[] = { 1,2,3 };
int *p = ar;
p = ar1;
*p = 4;
printf("%d",ar1[0]);
注:编译没问题
代码:
int sum(const int *ar,int n)//数组名为数组第一个元素的地址,即可以用一个指向int类型的指针代替 等价于
{
int total = 0;
int *p = ar;
for (int i = 0; i < n; i++)
{
total += *p++;//依次取出p指针的数值
}
return total;
}
5 要通过函数改变实参,必须要通过指针:
代码:
#include <stdio.h>

void swap1(int a, int b)
{
int tmp = a;
a = b;
b = a;
}
void swap2(int *a,int *b)
{
int tmp = *a;
*a = *b;
*b = tmp;
}

int main()
{
int a = 10;
int b = 20;
swap1(a, b);
printf("a = %d,b=%d\n", a, b); //打印结果:a=10,b=20 所以值传递不能改变实参的值
swap2(&a, &b);
printf("a = %d,b=%d\n", a, b);//打印结果:a=20,b=10 改变实参的值只能通过指针来完成
}
打印结果:
a = 10,b=20
a = 20,b=10

6 将二维数组做为函数参数
void sum2d(int (*p)[3]); //int (*p)[3] 表示一个指针有三个int元素的数组
等价:void sum2d(int p[][3]);

8 指针的操作:
指针操作汇总:
1 赋值:可以将一个地址赋给指针 int *p = &a;
2 求值:用*号可以取出指针中的数值 操作:*p
3 取指针地址:指针是一个变量,也有存储地址, 取出指针变量p的存储地址操作:&p  
4 指针加一个整数(可以是负数): 操作:p+i  意义:将 p的地址 + i*sizeof(指针类型) 得到的新地址就是 p+ 4 的结果 如:p 是int 类型 ,p1=0036F808  p1+4 = 0036F818( p1+4 * sizeof(int))
5 指针可以自增或自减:p++ 原理同指针加一个正整数
6 指针-指针 可以得出两个指针的差值,差值相可以是一个整数,数组中两个元素的指针减法就可以得到元素的距离
7 比较 :相同类型的指针可以用 == 运算符比较
代码:
void pointer_op()
{
int ar[5] = { 100,200,300,400,500};
int *p1, *p2, *p3;
p1 = &ar[0]; // 等价p1 = ar[0]
p2 = &ar[2];
printf("*******打印指针p1,*p1,&p1*******\n");
printf("\np1=%p, *p1 = %d,&p1 = %p\n", p1, *p2, &p1);//打印结果:p1=0036F808, *p1 = 300,&p1 = 0036F7FC
printf("*******指针相int类型常量*******\n");
p3 = p1 + 4;
printf("\np1+4 = %p, *(p1+4) = %d, *(p1+3) = %d\n", p3, *(p1+4), *(p1 + 3)); //打印结果:p1+4 = 0036F818, * (p1+4) = 500, *(p1+3) = 400 可见int类型指针,每加1 就是指向下一个int类型数
printf("*******指针与另一个指针的减法*******\n");
int i = p2 - p1;
printf("\np2 - p1 = %d\n", i); //打印结果 p2 - p1 = 2
return 0;
}

9 函数指针:
指针函数的用法 :
代码
int add(int a, int b)
{
return a + b;
}
int max( int a ,int b)
{
return a > b ? a : b;
}
int main()
{
int a = 10;
int b = 20;
int(*p)(int, int);// 定义一个指向函数的指针
//int status = 0;
//scanf("%d",&status);
p = add; //
int sum = p(a, b);//通过指针调用函数
printf("%d",sum);
return 0;
}



原创粉丝点击