指针的优点:
- 使程序更简洁、紧凑、高效
- 有效的表达更复杂的数据结构
- 动态分配内存
- 得到多于一个数的函数返回值
1. 指针的基本用法
1.1 指针的概念
- 内存地址:内存中每个字节单位都有一个编号(一般用十六进制表示)
- 指针:指针就是内存地址
- 指针变量:用于存放地址的变量就叫做指针变量
指针变量画图展示:
1.2 格式
存储类型 数据类型 *指针变量名;
int *p; //定义了一个指针变量p,指向的数据是int类型的。
int a = 5;
int *p = &a;
char c='v';
char *q=&c;
printf("%p %p\n", p, &a);
printf("%p %p\n",q,&c);
printf("%d %d\n",a,*p);
printf("%c %c\n",c,*q);
访问指针所指向空间的内容用取内容运算符*
那么p变量存放的就是a的地址,q变量存放的是c的地址。
符号*可以访问地址里面的内容。
指针与所指变量之间的关系如下图:
int i=3;
int *i_potinte=&i;
2.3 指针操作符
- &:取地址符:取变量的地址
- *:取内容符:取地址里面存放的内容
*&a=a;//*和&是互逆运算
&*a//错误(因为运算符优先级)
2.4 指针变量初始化和赋值
指针变量使用前不仅要定义,还要初始化。未初始化的指针变量不能随便使用,不然可能会产生野指针。
(1)将普通变量的地址赋值给指针变量
#include
int main(int argc, char const *argv[])
{
int a=10;
int *p = &a;//定义的同时赋值
int *q=NULL;//可以初始化为空指针
int *p2;
p2=p;//先定义后赋值
printf("%d %d %d\n",a,*p,*p2);//打印a的值
printf("%p %p %p\n",&a,p,p2); //打印a的地址
*p=20; //同过指向a的指针改变a的值
printf("%d %d %d\n",a,*p,*p2);//打印a的值
printf("%p %p %p\n",&a,p,p2); //打印a的地址
return 0;
}
(2)将数组的首地址赋值给指针变量
char s[10]="hello";
char *p = s;
int arr[5]={1,2,3,4,5};
int *q=arr;
printf("%c\n",*p);//h
printf("%d\n",*q);//1
(3)将指针变量里面保存的地址赋值给另一个指针变量
int a=10;
int *p=&a;
int *q=p;
printf("%d %d %d\n",a,*p,*q);
*q=20;//通过指针改变变量a的值
printf("%d %d %d\n",a,*p,*q);
p和q都指向了变量a
2. 指针运算
2.1 算术运算- +
对指针加减操作其实就是让指针向前向后移动
char str[32]="hello";
char *p=str;
printf("%c\n",*p);
p++;
printf("%c\n",*p);
p--;
printf("%c\n",*p);
int *p;p++;//移动4字节
double *q;q++;//移动8字节
p+n:访问高地址方向的第n个数据的地址,指针的指向不发生变化。
p-n:访问低地址方向的第n个数据的地址,指针的指向不发生变化。
偏移了多少字节=n*sizeof(数据类型)
2.2 关系运算 > >= < <= == !=
指针之间的关系运算比较的是它指向地址的高低
指向高地址的指针是大于指向低地址的指针
char s[10]="hello";
char *p1=s;
char *p2=&s[2];
if(p2>p1)
printf("p2>p1");
else
printf("p2);
练习:以下程序打印出来什么
char s[32]="hello";
char *p=s;
p++;c
char y=(*--p)++;
printf("%c",y);//h
练习:以下程序打印什么结果
int x[] = {10, 20, 30};
int *px = x;
printf("%d,", ++*px);//11
printf("%d\n", *px); //11
px = x;
printf("%d,", (*px)++);//11
printf("%d\n", *px);//12
px = x+1;
printf("%d,", *px++);//20
printf("%d\n", *px);//30
px = x+1;
printf("%d,", *++px);//30
printf("%d\n", *px);//30
练习:下面程序段的运行结果是
char a[ ]=”language” , *p ;
p=a ;
while (*p!=’u’) { printf(“%c”,*p-32); p++ ; }
A)LANGUAGE B)language C)LANG D)langUAGE
C
3. 指针的大小和段错误
3.1 指针的大小
计算指针大小用:sizeof(指针变量名)
int a=5;
short b=6;
char c='a';
int *p1=&a;
short *p2=&b;
char *p3=&c;
printf("%d %d %d\n",sizeof(p1),sizeof(p2),sizeof(p3));//4 4 4 4
总结:
- 32位操作系统指针大小是4字节。64位操作系统,指针大小是8字节。
- 内存地址是固定的,但是变量的地址不是固定的。
- 指针类型根据指针指向的空间的数据类型来匹配
练习:
利用指针判断输入的字符串是否为回文
#include
#include
int main(int argc, char const *argv[])
{
char a[32]={};
char *p1,*p2;
int flag=1;
gets(a);
p1=a;
p2=a+strlen(a)-1;
while(p2>p1)
{
if(*p1!=*p2)
flag=0;
p1++;
p2--;
}
if(flag==0)
printf("no!\n");
else
printf("yes!\n");
return 0;
}
练习:编写一个程序实现功能:将字符串“Computer Science”赋值给一个字符数组,然后从第一个字母开始间隔的输出该字符串,用指针完成。结果:Cmue cec
#include
#include
int main(int argc, char const *argv[])
{
char string[32] = "Computer Science";
char *p = string;
while (*p != '\0')
{
printf("%c", *p);
p += 2;
}
printf("\n");
return 0;
}
3.2 使用指针时报段错误
段错误: Segmentation fault (core dumped)
(1)野指针,没有规定指向的指针会在内存中乱指。
野指针产生的原因,主要有两种:
【1】指针变量没有初始化
【2】指针被free之后,没有置NULL,会让人认为时合法指针。
这两种情况都是没有给指针规定指向。
例如:int *p;
scanf(“%d”, p);
printf(“%d\n”,*p);
修改:
int a=10;
int *p=&a;
scanf("%d",p);
printf("%d\n",*p);
(2)内存泄露,对非法空间进行赋值。
练习1.将字符串转换成整型数字输出。用指针实现
#include
#include
int main(int argc, char const *argv[])
{
char a[32]="123";
char *p=a;
int num=0;
while(*p != '\0')
{
num = num*10+(*p-48);
p++;
}
printf("num=%d\n",num);
return 0;
}
4. 指针修饰
4.1 const 常量化
(1)修饰普通变
const int a=10;
int const b=10;
此时a和b只读,不可以修改。但是可以通过指针修改。
const int a=10;
int const b=20;
int *p=&a,*q=&b;
printf("%d %d\n",a,b);//10 20
*p=1;
*q=2;
//a=1;//error: assignment of read-only variable ‘a’
//b=2;//error: assignment of read-only variable ‘b’
printf("%d %d\n",a,b);//1 2
a的值 | a的地址 | p的地址 |
a | &a | &p |
*p | p | q |
**q | *q |
验证:
#include
#include
int main(int argc, char const *argv[])
{
int a=10;
int *p=&a;
int **q=&p;
printf("%d %d %d\n",a,*p,**q);
printf("%p %p %p\n",&a,p,*q);
printf("%p %p\n",&p,q);
return 0;
}
结果:
10 10 10
0xbf9839b0 0xbf9839b0 0xbf9839b0
0xbf9839b4 0xbf9839b4
(2) 修饰指针指向的内容
也就是修饰*p,此时指针指向的内容不能改变,但是指向可以改变。
const int *p;
int const *p;
#include
#include
int main(int argc, char const *argv[])
{
int a=10;
int b=20;
int const *p=&a;
const int *q=&b;
printf("%d %d\n",a,b);//10 20
//*p=1;//*p只读不可以被更改
//*q=2;//*q只读不可以被更改
p=q;
printf("%d %d\n",*p,*q);//20 20
return 0;
}
(3) 修饰指针指向
int *const p;
此时const修饰p,指针指向不能被更改,但是指向的内容可以被更改。
#include
#include
int main(int argc, char const *argv[])
{
int a=10;
int *const p=&a;
printf("%d\n",*p);
//p=NULL;//error: assignment of read-only variable ‘p’
*p=20;
printf("%d\n",*p);
return 0;
}
4.2 void
(1) 不允许修饰普通变量:void a;//错误
(2) 可以修饰指针:void *p;
此时p是一个任意类型的指针
使用场景:函数参数或函数返回值。
注意:通过void类型修饰的指针进行取内容时,需要进行强制转换。
转换方式:(int *)p 为右值
int a=100;
void *p=&a;
int *q=(int *)p;
printf("%d %d\n",*(int *)p,*q);
标签:int,C语言,char,++,printf,include,指针
From: https://blog.51cto.com/u_14458591/6400784