Day7 指针专题(二)
字符指针与字符串
C语言通过使用字符数组来处理字符串。通常我们把char数据类型的指针变量称为字符指针变量,字符指针变量与字符数组有着密切关系,它也被用来处理字符串。
1.初始化字符指针是把内存中字符串的首地址赋予指针,并不是把该字符串复制到指针中,可通过指针将字符串的内容做修改。
例:
#include <stdio.h>
#include <ctype.h>
int main(int argc, char *argv[])
{
char ch1[] = "hello World!";
char ch2[] = "hello World!";
char * p;
p = ch1;
//ch1[0]---*(ch1+0)----p[0], *p
if(isalpha(*p)) {
if (isupper(*p))
*p = tolower(*p);
else
*p = toupper(*p);
}
printf("%p %s\n", p, p);
p = ch2;
printf("%p %s\n",p, p);
return 0;
}
2.在C编程中,当一个字符指针直接指向一个字符串常量时,不能修改指针指向对象的值。通过指针直接存储字符串常量,指针存储字符串常量的起始地址,且输出时不需要加“*”。
例:
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
char ch[50] = "welcome";
char * p1 = "hello World!";
//strcpy(ch, p1);//可以将p1拷贝到ch
strcpy(p1, ch);//不可以将ch拷贝到p1,因为字符串常量不能修改
puts(ch);
puts(p1);
return 0;
}
3.程序举例
不利用任何字符串函数,编程实现字符串连接函数的功能。
#include <stdio.h>
int main(int argc, char *argv[])
{
char ch[100] = "welcome";
char * p = "hello World!", * q;
int i = 0;
q = p;
while (*(ch+i) != '\0')
i++;
while (*p != '\0') {
*(ch+i) = *p;
i++;
p++;
}
*(ch+i) = *p;
p = q;
puts(ch);
puts(p);
return 0;
}
指针数组
1.指针数组的定义
所谓指针数组是指有若干个具有相同存储类型和数据类型的指针变量构成的集合,通常和二维数组联合使用。
指针数组的一般说明形式:
<存储类型> <数据类型> * <指针数组名> [<大小>] ;
指针数组名表示该指针数组的起始地址。
例:
//声明一个指针数组
double * pb[2] , b[2][3] ;
//把一维数组b[0]和b[1]的首地址分别赋予指针变量数组的元素pb[0]和pb[1]
pb[0] = b[0] ; //等价于pb[0] = &b[0][0] ;
pb[1] = b[1] ; //等价于pb[1] = &b[1][0] ;
//此时pb[0]指向了一维数组b[0]的第一个元素b[0][0];而pb[1]指向了一维数组b[0]的第一个元素b[1][0]。
例:
#include <stdio.h>
int main(int argc, char *argv[])
{
int a[2][3] = {{1, 4, 6}, {12, 9, 7}};//a----a[0] a[1]
int * p[2];
p[0] = a[0];//&a[0][0]
p[1] = a[1];//&a[1][0]
printf("%d\n", a[0][1]);//4
printf("%d\n", *(a[0]+1));//4
printf("%d\n", *(p[0]+1));//4
printf("%d\n", *(p[1]+2));//7
return 0;
}
2.程序举例
编程利用指针数组处理一个二维数组,要求遍历二维数组所有元素并求出二维数组所有元素的和。
#include <stdio.h>
int main(int argc, char *argv[])
{
int a[2][3] = {{1, 4, 6}, {12, 9, 7}};//a----a[0] a[1]
int * p[2] = {a[0], a[1]};
int i, j, sum = 0;
int * * q;
q = p;//q = &p[0]
printf("total:%d\n", sizeof(p));
//printf("%p %p\n", p[0], a[0]);
//printf("%p %p\n", p[1], a[1]);
for (i = 0; i < 2; i++) {
for (j = 0; j < 3; j++)
sum += *(p[i]+j);
//printf("%d %d ", *(a[i] + j), *(p[i]+j));
// printf("%d %d ", *(*(a+i) + j), *(*(p +i)+j));
//puts("");
}
问:如何计算指针数组占用的内存空间?
答:一个指针占用4个字节(32位),指针数组占用内存空间=指针数组元素*4
问:指针数组名加1,移动多少字节?
答:4
问:指针数组名相当于什么样的指针?
答:二级指针
例:
int a[2][3] ;
int *p[2] = {a[0] , a[1]} ;
int * *q ;
//第一个“*”号表示q所存储的变的数据类型为指针类型
//第二个“*”号表示声明q也是一个指针变量,存储指针变量的地址
q = p ;//q = &(p[0])
多级指针
1.多级指针的定义
把一个指向指针变量的指针变量,称为多级指针变量。对于指向处理数据的指针变量称为一级指针变量,简称一级指针;而把指向一级指针变量的指针变量称为二级指针白能量,简称二级指针。
二级指针变量的说明形式如下:
<存储类型> <数据类型> ** <指针名> ;
第一个“*”表示指针变量所存储的变量(指针变量)的数据类型为指针类型
第二个“*”表示声明为指针变量
2.多级指针的运算
指针变量加1,是向地址大的方向移动一个目标数据的地址量。类似的道理,多级指针运算也是以其目标变量为单位进行偏移。比如:int *p ; p+1移动一个int*变量所占的内存空间;再比如int **p ; p+1移动一个int**所占的内存空间。
3.多级指针和指针数组
指针数组也可以用另外一个指针来处理
例:
#include <stdio.h>
int main(int argc, char *argv[])
{
//有一个一维字符数组ps[5]
char * ps[5] = {“Beijing city” , “Moscow city” , “New York city” , “Paris city” , “London city” } ;
//定义另外一个指针变量pps,并且把指针数组的首地址赋予指针pps
char ** pps;
int i, n;
i = 0;
n = sizeofp(s) / sizeof(char *);
pps = &ps[0];//pps = ps;
while (i < n){
printf("%s %s\n", ps[i], *(pps + i));
i++;
}
例:
#include <stdio.h>
int main(int argc, char *argv[])
{
int a[] = {3, 6, 9};
int * p[2] = {&a[0], &a[1]};//int * --- p[0] p[1]
int ** q;
q = &p[0];//p
q = p;
printf("%d %d %d\n", a[0], *p[0], **q);
printf("%d %d %d\n", a[1], *p[1], **(q+1));
printf("%d %d %d\n", a[2], *(p[1]+1), *((*(q + 1))+1));
return 0;
}
问:多级指针在内存中占几个字节?
答:4(32位机)
问:多级指针加1,移动多少字节?
答:4
Void指针
void指针是一种不确定数据类型的指针变量,它可以通过强制类型转换让该变量指向任何数据类型的变量。
一般形式如下:
void * <指针变量名称> ;
对于void指针,在没有强制类型转换之前,不能进行任何指针的算术运算。void指针在使用时必须强制转换为目标指针类型,赋值时可以省略。
例:
int main(int argc, char *argv[])
{
int m = 10;
double n = 3.14;
void * p, * q;
p = &m;//(void *)&m;
printf("%d %d\n", m, *(int *)p);
printf("%p\n", p);
p++;
printf("%p\n", p);
q = &n;//(void *)&n;
printf("%.2lf %.2lf\n", n, *(double *)q);
printf("%p\n", p);
q++;
printf("%p\n", q);
return 0;
}
程序举例:使用void指针遍历一维数组
#include <stdio.h>
int main(int argc, char *argv[])
{
int a[] = {5, 9, 1, 6, 9, 10};
int i, n;
void * p;
p = a;
n = sizeof(a) / sizeof(int);
for (i = 0; i < n; i++)
printf("%d ", *((int *)p + i));
puts("");
return 0;
}
const修饰指针
1.常量化变量的值
一般形式:
const <数据类型> <变量名> = [<表达式>] ;
常量化变量是为了使变量的值不能修改。变量有const修饰时,若想用指针间接访问变量,指针也要由const修饰。
2.常量化指针目标表达式
一般形式:
const <数据类型> * <指针变量名> [=<指针运算表达式>] ;
常量化指针目标是限制通过指针修改其目标的数值,但<指针变量>存储的地址值可以修改。
3.常量化指针变量
一般形式:
<数据类型> * const <指针变量名> [=<指针运算表达式>] ;
使得<指针变量>存储的地址值不能修改,但可以通过*<指针变量名>修改指针所指向变量的数值。
4.常量化指针变量及其目标表达式
一般形式:
const <数据类型> * const <指针变量名> [=<指针运算表达式>] ;
常量化指针变量及其目标表达式,使得及不可以修改<指针变量>的地址值,也不可以通过*<指针变量名>修改指针所指向变量的值。
例:
#include <stdio.h>
int main(int argc, char *argv[])
{
int m = 10;
const int * p;
int * const q = &m;
const int * const r = &m;
p = &m;//right;
//(*p)++; //error;
//q = &m; //error;
*q = 20;//right
r++;//error;
(*r)++;//error;
return 0;
}
问:void指针由什么用?
答:使得指针可以通过不同类型转换来完成不同场合的应用。
问:main函数是否可以带参数(涉及到const指针)?
答 :可以
#include <stdio.h>
int main(int argc, const char * argv[]) {
//const char * argv[] = {"./a.out", "192.168.1.5", "9999"};
int i;
printf("argc=%d\n", argc);
for (i = 0; i < argc; i++) {
printf("%s\n", argv[i]);
}
return 0;
}
/*
结果:
argc=1
./a.out
若输入执行代码为:./a.out 192.168.1.7 6000
则结果为:
argc=3
./a.out
192.168.1.7
6000
*/