三、指针指向数组
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<myhead.h>
int main(int argc, const char *argv[])
{
//定义一个一维数组
int arr[] = {3,8,3,2,4};
int len = sizeof(arr)/sizeof(arr[0]); //求数组长度
//定义指针指向一维数组
int *ptr = arr; //int *ptr = &arr[0];
//数据输出方式1,从值的角度
printf("数据元素分别是:");
for(int i=0; i<len; i++)
{
printf("%d\t", arr[i]);
}
printf("\n");
//输出方式2:从数组名的角度
printf("数据元素分别是:");
for(int i=0; i<len; i++)
{
printf("%d\t", *(arr+i) );
}
printf("\n");
//输出方式3:从指针变量的角度
printf("数据元素分别是:");
for(int i=0; i<len; i++)
{
printf("%d\t", *(ptr+i) );
}
printf("\n");
//输出方式4:从指针的角度找值
printf("数据元素分别是:");
for(int i=0; i<len; i++)
{
printf("%d\t", ptr[i]);
}
printf("\n");
//输出方式5:从指针变量的角度
printf("数据元素分别是:");
for(int i=0; i<len; i++)
{
printf("%d\t", *(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<myhead.h>
#define MAX 100
//定义输入函数
void input_score(int *score_ptr, int *size_ptr)
{
printf("请输入班级人数:");
scanf("%d", size_ptr); //输入班级人数
//输入学生成绩
for(int i=0; i<*size_ptr; i++)
{
printf("请输入第%d个学生成绩:", i+1);
scanf("%d", score_ptr+i); //score_ptr[i] <==> *(score_ptr +i)
}
printf("录入成功\n");
}
//定义输出函数
void output_score(int *score_ptr, int size)
{
printf("目前学生分数分别是:");
for(int i=0; i<size; i++)
{
printf("%d\t", score_ptr[i]);
}
printf("\n");
score_ptr[0] = 100;
}
/***********************主程序**********************/
int main(int argc, const char *argv[])
{
int score[MAX] = {0}; //定义足够大的数组
int size = 0; //数组的实际大小
//调用函数完成输入工作
input_score(score, &size);
//调用函数完成输出工作
output_score(score, size);
output_score(score, 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函数的功能
2> 自定义函数(my_strcpy)实现strcpy函数的功能
3> 自定义函数(my_strcmp)实现strcmo函数的功能
4> 自定义函数(my_strcat)实现strcat函数的功能
5> (my_strstr)实现求src字符串中是否包含子串dest字符串
#include <stdio.h>
// 实现 strlen 功能
int my_strlen(const char *str) {
int count = 0;
while (*str != '\0') {
count++;
str++;
}
return count;
}
// 实现 strcpy 功能
char* my_strcpy(char *dest, const char *src) {
char *original_dest = dest; // 保存dest的初始地址
while (*src != '\0') {
*dest = *src;
dest++;
src++;
}
*dest = '\0'; // 在dest字符串末尾添加终止符
return original_dest;
}
// 实现 strcmp 功能
int my_strcmp(const char *str1, const char *str2) {
while (*str1 && *str2 && *str1 == *str2) {
str1++;
str2++;
}
return *(const unsigned char *)str1 - *(const unsigned char *)str2;
}
// 实现 strcat 功能
char* my_strcat(char *dest, const char *src) {
char *original_dest = dest; // 保存dest的初始地址
while (*dest) {
dest++; // 寻找dest字符串的结尾
}
while (*src != '\0') {
*dest = *src;
dest++;
src++;
}
*dest = '\0'; // 在新字符串末尾添加终止符
return original_dest;
}
// 实现 strstr 功能
const char* my_strstr(const char *haystack, const char *needle) {
size_t len = my_strlen(needle);
if (len == 0)
return haystack;
for (; *haystack; haystack++) {
if (my_strcmp(haystack, needle) == 0)
return haystack;
}
return NULL;
}
int main() {
const char *str1 = "Hello, world!";
char str2[50];
// 测试 my_strlen
printf("Length of '%s': %d\n", str1, my_strlen(str1));
// 测试 my_strcpy
my_strcpy(str2, str1);
printf("Copied string: %s\n", str2);
// 测试 my_strcmp
const char *str3 = "Hello, world!";
if (my_strcmp(str1, str3) == 0)
printf("Strings '%s' and '%s' are equal.\n", str1, str3);
else
printf("Strings '%s' and '%s' are not equal.\n", str1, str3);
// 测试 my_strcat
char str4[] = "Hello, ";
my_strcat(str4, str3);
printf("Concatenated string: %s\n", str4);
// 测试 my_strstr
const char *str5 = "world";
const char *result = my_strstr(str1, str5);
if (result != NULL)
printf("Substring found at position %lu\n", result - str1);
else
printf("Substring not found.\n");
return 0;
}