三、指针指向数组
3.1 指针与数组的关系
1> 一维数组的数组名,本质上是一个该数组的第一个元素的地址
int arr[5]; arr &arr[0]
2> 数组名是一个地址常量,不能被重新赋值,但是,数组名可以进行偏移
3> 二维数组的数组名,从数值上来说也是一个该数组第一个元素的地址
int arr[3][4]; arr &arr[0] arr[0] &arr[0][0] arr[1] &arr[1][0]
3.2指针与一维数组的关系实现
1:指针与一维数组的关系
#include<stdio.h>
int main(int argc, char const *argv[])
{
int arr[]={1,2,3,4,5};
int len = sizeof(arr)/sizeof(arr[0]);
int *ptr =arr;
//从值的角度
printf("数据元素分别是:\n");
for (int i = 0; i < len; i++)
{
printf("%d\t",*(arr+i));//arr是指针常量不能自增
}
printf("\n");
//从数组名的角度
for (int i = 0; i < len; i++)
{
printf("%d\t",arr[i]);
}
printf("\n");
//从指针变量的角度
for (int i = 0; i < len; i++)
{
printf("%d\t",*(ptr+i));
}
printf("\n");
//从指针的角度
for (int i = 0; i < len; i++)
{
printf("%d\t",ptr[i]);
}
printf("\n");
for (int i = 0; i < len; i++)
{
printf("%d\t",*(ptr++));//ptr是指针变量,可以自增
}
printf("\n");
return 0;
}
2: 指针指向一维整型数组作为函数参数传递
当实参使用的是数组名进行传递时,本质上传递的是数组首元素的地址
被调函数的形参可以是一个数组接收,也可以是一个指针变量接收
虽然使用的是数组接收,但是,本质上也还是使用的是指针接收
#include<myhead.h>
//使用数组接受
/*
void sort(int arr[], int n)
{
for(int i=1; i<n; i++)
{
for(int j=0; j<n-i; j++)
{
if(arr[j] > arr[j+1])
{
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
printf("排序成功\n");
}
*/
//使用指针接受
void sort(int *arr, int n)
{
for(int i=1; i<n; i++)
{
for(int j=0; j<n-i; j++)
{
if(arr[j] > arr[j+1]) //if(*(arr+j) > *(arr+j+1))
{
int temp = arr[j];
arr[j] = arr[j+1];
arr[j+1] = temp;
}
}
}
printf("排序成功\n");
}
/***************************主程序**********************/
int main(int argc, const char *argv[])
{
int arr[5] = {3,9,2,7,6};
//调用排序函数,将数组进行排序
sort(arr, 5); //sort(&arr[0], 5)
printf("排序后的结果为:");
for(int i=0; i<5; i++)
{
printf("%d\t", arr[i]);
}
printf("\n");
return 0;
}
练习:
主函数中定义一个长度为8的数组,调用自定义函数完成输入、自定义函数完成输出、自定义函数求最大值、自定义函数完成数组的逆置。并对这些函数进行测试。要求,形参使用指针接收
#include<stdio.h>
//(排序)使用指针来接受
void sort(int *arr,int n)
{
for (int i = 1; i < n; i++)
{
for (int j = 0; i < n-i; j++)
{
if (arr[j]>arr[j+1])
{
int temp=arr[j];
arr[j]=arr[j+1];
arr[j+1]=temp;
}
}
}
}
//求数组最大值
int max(int *arr,int *size)
{
int max=0;
for (int i = 0; i < *size; i++)
{
if (arr[i]>max)
{
max=arr[i];
}
}
return max;
}
//输入数组
void input_arr(int *arr,int *size)
{
printf("请输入实际个数数");
scanf("%d",size);
for (int i = 0; i < *size; i++)
{
printf("请输入第%d个数:",i+1);
scanf("%d",arr+i);
getchar();
}
}
//输出数组
void print_arr(const int *arr,int *size)
{
for (int i = 0; i < *size; i++)
{
printf("%d\t",arr[i]);
}
printf("\n");
}
//倒置
void daozhi(const int *arr,int *size)
{
int brr[8]={0};
for (int i = 0; i < *size; i++)
{
brr[i]=arr[*size-1-i];
}
for (int i = 0; i < *size; i++)
{
printf("%d\t",brr[i]);
}
printf("\n");
}
int main(int argc, char const *argv[])//*argv[]是指针数组
{
int arr[8]={0};
int size=0; //数组实际大小
input_arr(arr,&size);
printf("最大值为%d\n",max(arr,&size));
daozhi(arr,&size);
print_arr(arr,&size);
return 0;
}
3: 指针指向一维字符数组作为函数参数传递
1、由于字符串有结束标识,所以接收字符串时,可以不用接收字符串长度
2、一般对传入的字符串如果不进行更改操作的话,需要加上关键字const修饰
#include<myhead.h>
#include<ctype.h>
//定义筛选函数
void fun(const char *src, char *dest)
{
char temp = 0;
//遍历所有src中的字符
while(temp = *src++)
{
//判断该字符是否为字母字符
if(isalpha(temp))
{
*dest++ = temp;
}
}
*dest = '\0'; //给新串放入结束标志
}
/***************主程序*********************/
int main(int argc, const char *argv[])
{
//功能:传入一个源字符串,调用函数实现,将该字符串中的
//字母字符放入新数组中传递给主调函数
char src[100] = "";
char dest[100] = "aaaaaaaaaaaaaaa";
printf("请输入一个字符串:");
gets(src);
//调用挑选数据的函数
fun(src, dest);
printf("新字符串为:%s\n", dest);
return 0;
}
3、指针与字符串的关系
1、字符串本质上是一个指针常量,可以定义一个指针指向一个字符串
2、当一个指针指向一个字符串时,不能通过该指针改变字符串中的内容
#include<myhead.h>
int main(int argc, const char *argv[])
{
//定义数组存储字符串、
char str[100] = "hello world";
//定义指针指向字符串常量
char *ptr = "I love China";
printf("str = %s, ptr = %s\n", str, ptr);
str[0] = 'H'; //给数组元素进行重新赋值
//ptr[0] = 'i'; //?
printf("str = %s, ptr = %s\n", str, ptr);
//请看案例
char s[100] = "acb\x12ef";
printf("strlen(s) = %ld\n", strlen(s)); //?
char c = '\x12';
printf("c = %d\n", c);
return 0;
}
4: const 关键字
1、const 中文含义 常量,常属性
2、该关键字是一个变量的存储格式,修饰变量时,表示给该变量添加常属性
3、const修饰的变量,虽然有常属性,但是,还依然是一个变量
4、定义变量的格式 const 数据类型 变量名;
5、修饰变量时,包括修饰普通变量和指针变量,有所不同
#include<myhead.h>
int main(int argc, const char *argv[])
{
int num = 520; //定义的是普通变量
const int key ; //定义的是常变量
//常变量跟普通变量一样,可以被访问
printf("num = %d, key = %d\n", num, key);
num = 999;
//key = 666; //不能直接通过key对key的值进行修改
int *ptr = &key;
*ptr = 666;
printf("num = %d, key = %d\n", num, key);
return 0;
}
6> const修饰指针变量(重要)
定义指针变量的格式: 数据类型 * 指针名;
#include<myhead.h>
int main(int argc, const char *argv[])
{
int num = 520;
int key = 1314;
//定义指针变量指向普通变量
const int *p1 = # //p1保护的是指针指向内存空间中的值
int const *p2 = # //与p1一样
int * const p3 = # //p3保护的是指针中的值
const int * const p4 = # //两个都保护
//验证p1保护哪个内容
//*p1 = 999; //更改指针指向内存空间中的值,报错
//p1 = &key; //更改指针的值
//验证p2保护哪个内容
//*p2 = 999; //更改指针指向内存空间中的值,报错
// p2 = &key; //更改指针的值
//验证p3保护哪个内容
//*p3 = 999; //更改指针指向内存空间中的值,报错
// p3 = &key; //更改指针的值
//验证p4保护哪个内容
*p4 = 999; //更改指针指向内存空间中的值,报错
p4 = &key; //更改指针的值
return 0;
}
作业
1> 自定义函数(my_strlen)实现strlen函数的功能
//1> 自定义函数(my_strlen)实现strle
#include<stdio.h>
int my_strlen(char *arr)
{
int n;
while(*arr++)
{
n++;
}
return n;
}
int main(int argc, char const *argv[])
{
char str[100]={};
printf("请输入一个字符串:");
scanf("%s",str);
printf("%d\n",my_strlen(str));
return 0;
}
2> 自定义函数(my_strcpy)实现strcpy函数的功能
//2> 自定义函数(my_strcpy)实现strcpy函数的功能
#include<stdio.h>
void my_strcpy(char *src,const char *dest)
{
char temp = 0;
//遍历所有src中的字符
while(temp = *dest++)
{
*src++ = temp++;
}
*src = '\0';
}
int main(int argc, char const *argv[])
{
char str[100]={""};
char arr[100]={""};
printf("请输入一个str字符串:");
scanf("%s",str);
printf("请输入一个arr字符串:");
scanf("%s",arr);
my_strcpy(str,arr);
printf("%s\n",str);
return 0;
}
3> 自定义函数(my_strcmp)实现strcmo函数的功能
//3> 自定义函数(my_strcmp)实现strcmo函数的功能
#include<stdio.h>
int my_strcmp(const char *arr,const char *brr)
{
char temp = 0;
//遍历所有src中的字符
while(temp = *arr++)
{
if (*brr > temp)
{
return -1;
}else if (*brr < temp)
{
return 1;
}
else
{
*brr++;
}
}
return 0;
}
int main(int argc, char const *argv[])
{
char str[100]={""};
char arr[100]={""};
printf("请输入一个str字符串:");
scanf("%s",str);
printf("请输入一个arr字符串:");
scanf("%s",arr);
printf("%d\n",my_strcmp(str,arr));
return 0;
}
4> 自定义函数(my_strcat)实现strcat函数的功能
//4> 自定义函数(my_strcat)实现strcat函数的功能
#include<stdio.h>
void my_strcat(char *arr,const char *brr)
{
char temp = 0;
//遍历所有arr中的字符
while(*arr)
{
*arr++;
}
while(temp = *brr++)
{
*arr++ = temp++;
}
*arr = '\0';
}
int main(int argc, char const *argv[])
{
char str[100]={""};
char arr[100]={""};
printf("请输入一个str字符串:");
scanf("%s",str);
printf("请输入一个arr字符串:");
scanf("%s",arr);
my_strcat(str,arr);
printf("%s\n",str);
return 0;
}
5> 自定义函数(my_strstr)实现求src字符串中是否包含子串dest字符串
// 5> 自定义函数(my_strstr)实现求src字符串中是否包含子串dest字符串
#include <stdio.h>
char *my_strstr(const char *src, const char *dest)
{
// 初始化三个字符指针:s1,s2和stu,其中stu初始指向src的首地址
char *s1 = NULL;
char *s2 = NULL;
char *str = (char *)src;
// 特殊情况:如果dest为空字符串(只包含结束符'\0'),则返回src的首地址
if (*dest == '\0')
{
return (char *)src;
}
// 主循环,遍历字符串src直到遇到结束符'\0'
while (*str)
{
// 将s1和s2分别复位
s1 = str;
s2 = (char *)dest;
// 内部循环,逐个比较s1和s2指向的字符,如果相同则继续比较下一个字符
// 直到遇到任意一个字符串的结束符'\0'或者发现不相等的字符为止
while (*s1 && *s2 && (*s1 == *s2))
{
s1++;
s2++;
}
if (*s2 == '\0') // 如果s2已经指向结束符'\0',则说明在stu开始的位置找到了子串dest,返回stu
{
return str; // 找到子串dest
}
if (*s1 == '\0') // 如果s1已经指向结束符'\0',说明当前stu所在子串长度不足以匹配dest,终止本次查找
{
return NULL;
}
*str++; // 移动stu指针,使其指向下一个可能的子串起始位置
}
// 遍历结束后仍未找到子串dest,则返回NULL
return NULL; // 没找到
}
int main(int argc, char const *argv[])
{
char str[100] = {""};
char arr[100] = {""};
printf("请输入一个str字符串:");
scanf("%s", str);
printf("请输入一个arr字符串:");
scanf("%s", arr);
printf("%s\n", my_strstr(str, arr));
return 0;
}