C语言指针(二)
承接上文C语言指针(一),链接为:C语言指针(一)
一、多级指针
1.1 多级指针的定义及应用
把一个指向指针的变量称为多级指针变量,常用二级指针,其实二级指针都用的不太多。
二级指针变量说明形式:<存储类型> <数据类型> **<指针名>
例如: char **q;
示例程序如下:
#include <stdio.h>
int main(int argc , char **argv)
{
int m = 100;
int *p = &m;
int **q = &p;
printf("m = %d &m = %p p = %p &p = %p\n q = %p &q = %p *q = %p \
**q = %d\n", m , &m , p , &p , q, &q , *q , **q);
return 0;
}
1.2 多级指针的运算
多级指针运算也是以其目标变量为单位进行偏移,比如int* p ,p+1是移动一个int变量占用的内存空间,int **p , p+1就是移动一个int *变量占用的内存空间 , int ***p , p+1就是移动一个int **所占的内存空间。代码演示如下:
#include <stdio.h>
int main(int argc , char **argv)
{
int m = 100;
int *p = &m;
int **q = &p;
printf("q = %p &q = %p *q = %p **q = %d\n" , q , &q , *q , **q);
printf("q+1 = %p sizeof(q) = %ld\n" ,q+1 , sizeof(q));
return 0;
}
可以看出q+1比q大了8个字节,多级指针+1,就是移动一个指针变量,不管是几级指针,都是存储内存编号(地址),在64位机器上,占8字节,因此多级变量指针本身也是占用8字节,所以多级指针偏移以8字节为单位。
二、指针数组
2.1 指针数组的定义及初始化
指针数组的定义:
指针数组是指由若干个指针构成的集合,指针数组一般形式为:<存储类型> <数据类型> *<指针数组名>[<大小>]
,例如:int p[2]
缘由是[]优先级比高,p先和[]结合形成数组,然后数组的每个元素都是指针变量。指针数组名就是指针数组的储存首地址,即指针数组名为数组的指针。
指针数组的初始化:
声明一个指针数组: double * pa[2] ,a[2][3];
把一维数组a[0]和a[1]的首地址分别赋予指针变量数组的数组元数pa[0]和pa[1]:
pa[0]=a[0] ; // 等价pa[0] = &a[0][0];
pa[1]=a[1]; // 等价pa[1] = &a[1][0];
此时pa[0]指向了一维数组a[0]的第一个元素a[0][0], 而pa[1]指向了一维数组a[1]的第一个元素a[1][0]。,如下图所示:
三、void指针和const修饰符
3.1 void指针的用法
概念:void指针是一种不确定数据类型的指针变量,它可以通过强制类型转换让该变量指向任何数据类型的变量。
一般形式:void * <指针变量名称> ;
对于void指针,在没有强制类型转换之前,不能进行任何指针的算术运算。如下程序所示:(printf里,如果不做转换,由于void的p读取字节不定,没法取值。)
#include <stdio.h>
int main(int argc, char const *argv[])
{
void *p;
int a = 10;
p = (void *)&a;
printf("%d\n", *(int *)p); //如果不做转换,由于void的p读取字节不定,没法取值
return 0;
}
3.2 const与指针
在C语言中,关键字const修饰变量,可以使得变量常量化。const修饰基本简单类型(非指针)时,很容易理解,就是变量的值不允许被修改,下面两种写法均可:
const int m = 10;
int const m = 10;
若要用const修饰指针,由于const放置的位置不同,修饰的内容也不同,主要是如下三种情况:
1、常量化指针目标表达式
一般说明形式:const <数据类型> * <指针变量名称>[= <指针运算表达式>] ;
例如:int m = 100 ;const int p = &m; //此时p的值不可被修改,但是p指向的位置可以移动。如下演示:
#include <stdio.h>
int main(int argc, char const *argv[])
{
int m = 100;
const int *p = &m;
*p = 101;
return 0;
}
#include <stdio.h>
int main(int argc, char const *argv[])
{
int m = 100;
const int *p = &m;
//*p = 101;
p++;
return 0;
}
2、常量化指针变量
一般说明形式为:<数据类型> * const <指针变量名称>[= <指针运算表达式>] ;
例如:int * const m = 100 ;//此时,指向的目标值可以变,但是指针地址不可变,意思是指针不能移动,示例如下:
/*可修改目标值*/
#include <stdio.h>
int main(int argc, char const *argv[])
{
int m = 100;
int* const p = &m;
*p = 101;
return 0;
}
/*不可修改指针地址,否则编译报错,提示地址是只读的*/
#include <stdio.h>
int main(int argc, char const *argv[])
{
int m = 100;
int* const p = &m;
//*p = 101;
p++;
return 0;
}
3、常量化指针变量及其目标表达式
一般说明形式如下: const <数据类型> * const <指针变量名> = <指针运算表达式> ;
常量化指针变量及其目标表达式,使得既不可以修改<指针变量>的地址,也不可以通过*<指针变量名称>修改指针所指向变量的值
const总结:左值右指
const出现在左边,代表值不可修改(指针指向的目标不可修改),const在右边,代表指针(地址)不可修改。左右都有const,代表值和指针地址都不可修改。
四、字符指针与字符串
4.1 字符指针概念
字符指针就是存储字符变量的地址,在C语言中没有字符串这个数据类型,通常用字符数组存储字符串。字符指针可以存储字符串的起始地址,即指针指向字符串的第一个字符。通常,我们把char数据类型的指针变量称为字符指针变量。字符指针变量与字符数组有着密切关系,它也被用来处理字符串。
4.2 字符指针初始化
初始化字符指针是把内存中字符串的首地址赋予指针,并不是把该字符串复制到指针中。
char str[] = “Hello World”;
char *p = str;
在C当中,如果直接把一个字符串给一个指针的话,会变成字符串常量,是不能被修改的。
如:char *p = “hello world”; *p = ‘h’这个是不行的(很重要)
,这样写相当于const char *p = “hello world”;
如果使用 char str[] = “hello world”; char *p = str;这样指针就是指向字符串的首地址。
4.3 字符串
字符串操作演示代码(把字符串进行大小写转换,大写字母变为小写,小写字母变为大写):
/*
* @Description:
* @Author: 余红祥
* @Date: 2022-07-03 18:21:18
* @LastEditTime: 2022-07-03 18:21:21
* @LastEditors:
*/
#include <stdio.h>
#include <ctype.h>
#include <string.h>
int main(int argc, char *argv[])
{
char str[] = "Ation";
char *p = str;
for(int i = 0;i<strlen(str);i++)
{
if(isalpha(*p))
{
if(isupper(*p))
{
*p = tolower(*p); //大写变小写
}
else
{
*p = toupper(*p); //小写变大写
}
}
p++;
}
p = str;
printf("%s %s\n",str,p);
return 0;
}
4.4 字符指针数组
若数组中存储若干个字符串的地址,则该数组叫做字符指针数组。形式:char *a[3];
示例程序如下:
#include <stdio.h>
#include <string.h>
int main(int argc, char const *argv[])
{
char s1[] = "welcome";
char s2[] = "to";
char s3[] = "jiangxi";
char *a1[3] = {s1, s2, s3};
char *a2[3] = {"welcome", "to" , "jiangxi"};
char **p = a1;
int i = 0;
printf("array1:%s %s %s\n", a1[0], a1[1], a1[2]);
for (i = 0; i < sizeof(a1)/sizeof(char *); i++)
printf("%s ", *(p+i));
printf("\n");
p = a2;
printf("array2:%s %s %s\n", a2[0] , a2[1] , a2[2]);
for (i = 0; i < sizeof(a2)/sizeof(char *); i++)
printf("%s ", *(p+i));
printf("\n");
return 0;
}
四、综合练习
1、不使用strcat连接函数,用指针编程实现字符串连接功能。
#include <stdio.h>
#include <ctype.h>
#include <string.h>
int main(int argc, char *argv[])
{
char dest[256] = "attion";
char src[256] = "please";
char *p = dest;
char *q = src;
int qlen = strlen(q);
int plen = strlen(dest);
while (*q != '\0')
{
for (int i = 0; i < qlen; i++)
{
*(p+plen) = *q;
p++;
q++;
}
}
printf("dest: %s\nsrc: %s\n", dest, src);
return 0;
}
2、用指针编程实现字符串反转功能。
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[])
{
char string[100] = "please";
char *p = string;
char *q = string + strlen(string) -1;
char temp = 0;
while (p < q)
{
temp = *q;
*q = *p;
*p =temp;
p++;
q--;
}
printf("string: %s\n", string);
}
3、利用指针数组处理一个二维数组,要求求出二维数组所有元素的和
答:
#include<stdio.h>
int main(int argc, char *argv[])
{
int a[2][3] = {0};
int *p[2] = {a[0],a[1]};
int i = 0 ,j = 0;
int sum = 0;
for(i = 0;i<2; i++)
{
for(j = 0;j < 3;j++)
{
scanf("%d",&a[i][j]);
}
}
for(i = 0; i < 2 ; i++ )
{
for(j = 0; j < 3 ; j++)
{
printf("%d ",a[i][j]);
sum += *(p[i]+j);
}
putchar('\n');
}
printf("%d\n",sum);
return 0;
}
4、用指针写出strcmp函数
答:
#include <stdio.h>
int main(int argc,char *argv[])
{
char str1[100];
char str2[100];
char *p = str1;
char *q = str2;
char temp;
puts("please input the first str:");
gets(p);
puts("please input the second str:");
gets(q);
while(*p == *q)
{
if(*p == '\0')
break;
p++;
q++;
}
temp = *q - *p;
printf("the cmp return val is %d\n",temp);
return 0;
}
5、利用指针实现strncmp函数功能
答:
#include <stdio.h>
int my_strncmp(char *p,char *q,int n);
int main(int argc,char *argv[])
{
char str1[100];
char str2[100];
char *p = str1;
char *q = str2;
char temp = 0;
//char test = 0;
puts("please input the first str:");
gets(p);
puts("please input the second str:");
gets(q);
//temp = strncmp(p,q,5); //用于测试
temp = my_strncmp(p,q,5); //比较前5个字符
printf("the cmp return val is %d\n",temp);
return 0;
}
//比较两个字符串的前n个字符
int my_strncmp(char *p, char *q, int n)
{
int i = 0;
for(i = 0;i < n-1;i++)
{
if(*p == *q)
{
if(*p == '\0')
break;
}
p++;
q++;
}
return *p - *q;
}