目录
指针和数组
直接访问:通过数组名访问
间接访问:通过指针访问
指针和一维数组
int a[5]={5,6,4,2,8};
int *p=a;
直接访问:
取地址 | 元素 | 取元素 | ||
a | &a[0] | 5 | a[0] | *a |
a+1 | &a[1] | 6 | a[1] | *(a+1) |
a+2 | &a[2] | 4 | a[2] | *(a+2) |
a+3 | &a[3] | 2 | a[3] | *(a+3) |
a+4 | &a[4] | 8 | a[4] | *(a+4) |
间接访问:
取地址 | 元素 | 取元素 | ||
&p[0] | p | 5 | *p | p[0] |
&p[1] | p+1 | 6 | *(p+1) | p[1] |
&p[2] | p+2 | 4 | *(p+2) | p[2] |
&p[3] | p+3 | 2 | *(p+3) | p[3] |
&p[4] | p+4 | 8 | *(p+4) | p[4] |
a和p本质不一样:a是地址常量,p是变量;a不能执行++操作,p可以
访问数组元素a[i]的值:
直接访问:a[i] *(a+1)
间接访问:p[i] *(p+1)
访问数组元素a[i]的地址:
直接访问:&a[i] a+i
间接访问:&p[i] p+i
运算方法:
1)++和*都是单目运算符,优先级相同
2)单目运算符从右向左运算
(*p)++:首先取出指针 p 指向的内存地址处的值,然后对取出的值进行自增值加1,将自增后的值存回原来的内存地址
*p++:单目运算符先算p++,由于++在后,取p指向的内存地址处的值;后对地址进行++
++*p:先取指针p的值,再对值自增
++(*p):同上
*++p: p自加,取自加后的值
*(++p): 同上
*(p++):先算p++,由于++在后,取p指向的内存地址处的值;后对地址进行++
练习:
1.
2.
3.
补充:
char *p="hello";
// p在栈区开辟4字节空间存放字符串常量"hello"的首地址
// hello存放在常量区
char buf[33]="hello";
// buf:在栈区开辟32字节空间,存放"hello"字符串
二维数组
如:
int a[2][3]={1,2,3,4,5,6};
a:数组名,表示第一行的首地址
a+1:第二行首地址
a是行地址,怎么用a表示列?
行地址和列地址级别不一样,一行可以有多列,所以行地址大于列地址,,,,所以要降级
在a前边加*,表示把行地址降级为列地址
*a:第一行第一列的地址 a[0]
*a+1:第一行第二列
*(a+1):第二行第一列
*(a+1)+1:第二行第二列
取地址 | 取元素 | |||||
a[0] | *a | a | 1 | a[0][0] | **a | *a[0] |
a[0]+1 | *a+1 | 2 | a[0][1] | *(*a+1) | *(a[0]+1) | |
a[0]+2 | *a+2 | 3 | a[0][2] | *(*a+2) | *(a[0]+2) | |
a[1] | *(a+1) | a+1 | 4 | a[1][0] | **(a+1) | *a[1] |
a[1]+1 | *(a+1)+1 | 5 | a[1][1] | *(*(a+1)+1) | *(a[1]+1) | |
a[1]+2 | *(a+1)+2 | 6 | a[1][2] | *(*(a+1)+2) | *(a[1]+2) |
访问a[i][j]的地址:
*(a+i)+j &a[i][j] a[i]+j
访问a[i][j]的值:
a[i][j] *(*(a+i)+j) *(a[i]+j)
练习:
数组指针
美丽的人
本质是指针,指向数组 行指针
格式:存储类型 数据类型 (*指针变量名)[列数]
int a[2][3]={2,3,4,5,6};
int (*p)[3]=a;
printf("%p %p\n",a,a+1);
printf("%p %p\n",p,p+1);
地址 | ||||||
p[0] | *p | a | p | 1 | **p | *p[0] |
p[0]+1 | *p+1 | 2 | *(*p+1) | *(p[0]+1) | ||
p[0]+2 | *p+2 | 3 | *(*p+2) | *(p[0]+2) | ||
p[1] | *(p+1) | a+1 | p+1 | 4 | **(p+1) | **p[1] |
p[1]+1 | *(p+1)+1 | 5 | *(*(p+1)+1) | *(p[1]+1) | ||
p[1]+2 | *(p+1)+2 | 6 | *(*(p+1)+2) | *(p[1]+2) |
大小:
sizeof(p)==4
注意:指针大小是一定的,不因指向的内容而改变,只跟操作系统有关;就Linux而言,32位为4字节,64位为8字节。
指针数组
本质是数组,里边存放指针
格式:
存储类型 数据类型 *数组名[元素个数]
int *arr[2];
应用场景:
1)存放普通变量的地址
int a=10,b=20,c=30;
int *p[3]={&a,&b,&c};
访问数组元素:数组名[下标];指针数组存放的内容是地址
p[0]------->&a
p[1]------->&b
p[2]------->&c
printf("%p %p\n",p[1],&b);
访问b的地址:(数组的第二个元素)
p[1]
*(p+1):p是数组首地址,p+1访问数组第二个元素的地址,*(p+1)取内容
访问b的值:
*p[1]
*(*(p+1))
2)存放二维数组的每一行第一个元素的地址(列地址)
int a[2][3]={1,2,3,4,5,6};
int *p[2]={a[0],a[1]};
访问a[1][2]的地址:(数组第二行第三列)
p[1]+2:p[1]先取数组第二个元素(a[1]第二行第一列的地址),p[1]+2向后移动2个数据单位
*(p+1)+2:p数组首地址,p+1取指针数组第二个元素的地址,*(p+1)取指针数组第二个元素(a[1]),*(p+1)+2
访问a[1][2]的值:
*(p[1]+2)
*(*(p+1)+2)
3)存放字符串
char *p[3]={"hello","world","hqyj"};
打印"world"字符串:
printf("%s\n",p[1]);
printf("%s\n",*(p+1));
打印'd'这个字符:
*(p[1]+4):p[1]获取指针数组第二个元素的值("world"的首地址),向后移动4个数据单位
*(*(p+1)+4):p数组首地址,p+1取指针数组第二个元素的地址,*(p+1)取指针数组第二个元素(a[1])("world"的首地址),向后移动4个数据单位,取内容
4)main函数命令行参数
int main(int argc, char const *argv[])
argc:表示argv里存放的数据的个数,也就是命令行存放的字符串
argv:是指针数组,里边存放命令行传递的字符串 ./a.out
printf("%s %d\n",argv[1],argc);
./a.out hello world
练习:
已有定义int k=2;int *ptr1,*ptr2;且ptr1和ptr2均已指向变量k,下面不能正确执行的赋值语句是 。
A)k=*ptr1+*ptr2 B)ptr2=k C)ptr1=ptr2 D)k=*ptr1*(*ptr2)
若有语句:int *p,a=4;和p=&a;下面均代表地址的一组选项是 。
A)a,p,*&a B)&*a,&a,*p C)*&p,*p,&a D)&a,&*p,p
下面判断正确的是 。
A)char *a=”china”; 等价于 char *a; *a=”china” ;
B)char str[10]={“china”}; 等价于 char str[10]; str[ ]={“china”} ;
C)char *s=”china”; 等价于 char *s; s=”china” ;
定义一个指针,指针存放地址 "china"存放在字符串常量区,常量区首地址赋值给指针
D)char c[4]=”abc”,d[4]=”abc”; 等价于 char c[4]=d[4]=”abc” ;
下面程序段中,for循环的执行次数是 。
char *s=”\t a \014 b c” ;
for ( ; *s!=’\0’ ; s++) printf(“*”) ;
A)2 B)7 C)6 D)5
设有程序段:char s[10]=”china”; char *p ; p=s ;则下面叙述正确的是 。
A)s和p完全相同
B)数组s中的内容和指针变量p中的内容相等
C)s数组长度和p所指向的字符串长度相等
D)*p与s[0]相等
下面程序段的运行结果是 。
char a[ ]=”language” , *p ;
p=a ;
while (*p!=’u’) { printf(“%c”,*p-32); p++ ; }
A)LANGUAGE B)language C)LANG D)langUAGE
设有说明语句:char a[]=”It is mine”;char *p=”It is mine”;则以下不正确的叙述是
A)a+1表示的是字符t的地址
B)p指向另外的字符串时,字符串的长度不受限制
C)p变量中存放的地址值可以改变
D)a中只能存放10个字符
若有程序段:int a[2][3],(*p)[3]; p=a;则对a数组元素的正确引用是 。
A)(p+1)[0] B)*(*(p+2)+1) C)*(p[1]+1) D)p[1]+2
下面程序的运行结果是 。
main ( )
{ int x[5]={2,4,6,8,10}, *p, **pp ;
p=x , pp = &p ;
printf(“%d”,*(p++));
printf(“%3d”,**pp);
}
A)4 4 B)2 4 C)2 2 D)4 6
若有说明:char *language[]={“FORTRAN”,”BASIC”,”PASCAL”,”JAVA”,”C”};则language[2]的值是 。
A)一个字符 B)一个地址 C)一个字符串 D)一个不定值
有以下程序段
#include <stdio.h>
int main()
{ int x[] = {10, 20, 30};
int *px = x;
printf("%d,", ++*px); printf("%d,", *px);//11 11 {11,20,30}
px = x;
printf("%d,", (*px)++); printf("%d,", *px); //11 12 {12,20,30}
px = x;
printf("%d,", *px++); printf("%d,", *px); //12 20 {12,20,30}
px = x;
printf("%d,", *++px); printf("%d\n", *px); //20 20
return 0;
}
程序运行后的输出结果是( )
A)11,11,11,12,12,20,20,20 B)20,10,11,10,11,10,11,10
C)11,11,11,12,12,13,20,20 D)20,10,11,20,11,12,20,20
const char *p、char const *p、char *const p 有什么区别?(北京信果科技)
请写出输出结果 (晟安信息)
int main()
{
int a[10] = {0};
int *p = a;
int *q = &a[6];
printf("%d\n", q-p); //6
printf("%d\n", (int)q - (int)p);//4*6=24
}
以下为linux下的32位C程序 (飞音时代)
char str[] = "Hello"; char *p = str; int n = 10;
请计算:
(1) sizeof(str) = ___6_____ (2) sizeof(p) = ___4_____
(3)sizeof(n) = ___4____
下列程序输出结果是?
#include <stdio.h>
int a[] = {0, 2, 4, 6, 8};
main()
{
int i;
int *p = a;
for(i = 0; i < 4; i++) a[i] = *p++;
printf("%d\n", a[2]);
}
写出下面的声明:
(1) 指向常整形数的指针(整形数是不可修改的,但指针可以)
______________________________________________________________
(2) 指向整型数的常指针(指针指向的整型数是可以修改的,但指针是不可修改的