您的位置:首页 > 编程语言 > C语言/C++

C语言指针详解

2017-05-24 15:33 525 查看
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;
}
内容来自用户分享和网络整理,不保证内容的准确性,如有侵权内容,可联系管理员处理 点击这里给我发消息
标签: