day10 1.指针概述2.指针指向普通变量作为函数参数指针指向数组3.指针指向数组

作业

1> 自定义函数(my_strlen)实现strlen函数的功能

#include <stdio.h>
#define M 100

void my_strlen(char *arr)            //定义函数实现strlen功能
{
	int sum=0;
	while(1)
	{
		char n=*arr++;                 
		if(n != '\0')				//遍历字符串的每一个值判断是否结束	
		{
			sum++;
		}else
		{
			printf("%d\n",sum);
			return;
		}
	}
}

/**************主函数******************/
int main(int argc, const char *argv[])
{
	char arr[M]="";
	printf("请输入一个字符串:");
	gets(arr);
	my_strlen(arr);

	return 0;
}

2> 自定义函数(my_strcpy)实现strcpy函数的功能

#include <stdio.h>
#define M 100

void my_strcpy(char *arr,char *brr)          //定义my_strcpy函数
{	
	while(1)
	{
		if(*brr != '\0')                     //判断循环结束点               
		{
			*arr++ = *brr++;                  //给对应数组位置赋值  
		}else
		{
			*arr='\0';
			return;
		}
	}
}

/***************主函数************************/
int main(int argc, const char *argv[])
{
	char arr[M]={0};
	char brr[M]={0};
	printf("请输入第一个字符串:");
	gets(arr);
	printf("请输入第二个字符串:");
	gets(brr);
	my_strcpy(arr,brr);	
	printf("实现结果:%s %s\n",arr,brr);

	return 0;
}

3> 自定义函数(my_strcmp)实现strcmp函数的功能

#include <stdio.h>
#define M 100

void my_strcmp(char *arr,char *brr)               //定义my_strcmp函数
{
	while(*arr)                                    //遍历次数
	{
		if(*arr>*brr)                             
		{
			printf("my_strcmp(arr,brr)>0\n");        
			return;
		}
		else if(*arr<*brr)
		{
			printf("my_strcmp(arr,brr)<0\n");
			return;
		}
		arr++;
		brr++;
	}
		if(*arr==*brr)
		{
			printf("my_strcmp(arr,brr)=0\n");
			return;
		}
}

int main(int argc, const char *argv[])
{
	char arr[M]={0};
    char brr[M]={0};
    printf("请输入第一个字符串:");
    gets(arr);
    printf("请输入第二个字符串:");
    gets(brr);
	my_strcmp(arr,brr);
	return 0;
}

4> 自定义函数(my_strcat)实现strcat函数的功能

#include <stdio.h>

void my_strcat(char *arr,char *brr)
{
	char *p=arr;                        //定义指针变量p,可以放心操作arr,同时接收连接字符串
	while(*arr)                        //偏移指针,放到arr字符串的下一位
	{
		arr++;
	}
	while(*brr)                         //从arr字符串的下一位开始赋值brr
	{
		*arr=*brr;
		brr++;
		arr++;
	}
	*arr='\0';
	printf("%s\n",p);
}

int main(int argc, const char *argv[])
{
	char arr[100]={0};
	char brr[100]={0};
	printf("请输入第一个字符串:");
	gets(arr);
	printf("请输入第二个字符串:");
	gets(brr);
	my_strcat(arr,brr);

	return 0;
}

5> 自定义函数(my_strstr)实现求src字符串中是否包含子串dest字符串

#include <stdio.h>

#define M 100

// 自定义的 strstr 函数
char *my_strstr(const char *arr, const char *brr) {
    const char *p = arr;
    const char *q = brr;
    while (*p) {
        p = arr;
        q = brr;
        while (*p && *q) {
            if (*p != *q) {
                break;
            }
            p++;
            q++;
        }
        if (*q == '\0') { // 子串匹配完毕
            return (char *)arr; // 返回子串开始的地址
        }
        arr++; // 移动到下一个字符继续匹配
    }
    return NULL; // 没有找到子串
}

int main(int argc, const char *argv[]) {
    char src[M] = {0};
    char dest[M] = {0};
    printf("请输入str字符串:");
    fgets(src, M, stdin); // 使用 fgets 代替 gets
    printf("请输入dest字符串:");
    fgets(dest, M, stdin); // 使用 fgets 代替 gets

    char *found = my_strstr(src, dest);
    if (found) {
        printf("str包含dest\n");
    } else {
        printf("str不包含dest\n");
    }

    return 0;
}

一、指针概述

1.1 指针相关概念

1> 引入目的:能够从地址的角度,找到内存中的数据,而不是以变量的角度去找,效率较高

2> 指针:就是内存地址编号

3> 指针变量:由于指针这个地址编号很难记忆,我们引入指针变量存储指针

                        存储地址的变量称为指针变量

4> 指针变量中,指针存储地址,作为一个特殊的数据类型,其大小是固定的 8 字节

1.2 指针变量的定义 

1> 定义格式:数据类型 * 指针名;

        例如:int * ptr;

2> 指针变量的初始化

1、使用一个相同数据类型的变量的地址为其进行初始化
        int num = 520;
        int * ptr = &num;              //将num的地址赋值个指针变量 ptr   //定义一个指针变量                                                             ptr,指向num
2、使用一个已经初始化了的指针变量给一个新的指针变量进行初始化
        int * qtr = ptr;              //此时表示两个指针变量同时存储了num的地址   int *qtr = &num;
3、使用地址的0 就是 NULL为其初始化
        int *wtr = NULL;            
4、注意:没有初始化的指针变量不能直接使用,因为该指针变量中存储了一个随机地址,          如果对其进行更改,可能会导致系统瘫痪
5、野指针:指向非法内存的指针称为野指针
        产生情况:
            1)定义指针时,没有为其进行初始化
            2)  指向了一个内存空间,但是随着程序的进行,该内存空间被回收了,那么该指针也是野指针(悬空指针)
            3) 数组下标越界时,访问的地址也是野指针

 3> 指针变量的使用:使用运算符 ‘ * ’来取得指针变量中的值,我们也称该运算为 取值运算

1、指针变量在定义时,*号只是身份的象征,表示该语句定义的是指针变量
2、指针变量使用是,*号表示一个运算,取值运算,就是取得该指针变量指向的内存空间中的值
3、总结一下 * 号在C语言中的用途
        1)    表示乘号,是一个双目运算符
        2)     定义指针时,是身份的象征,表示定义的是指针变量
        3)    使用指针时,是取值运算符,表示取得指针变量指向的内存空间中的值
4、总结一下 & 在C语言中的用途
        1)    一个&表示双目运算符 按位 与运算
        2)    两个&&表示双目运算符 逻辑 与运算
        3)    一个&表示单目运算符 取址运算
5、&与*在指针的方面,互为逆运算
                int num = 520;
                int *ptr = &num;
        1)    *&num    ==> *(&num)    ==>    *(ptr)    ==> num
        2)    &*ptr    ==> &(*ptr)      ==>    &(num)    ==> ptr
        3)    *&ptr    ==>*(&ptr)       ==>    *(ptr的二级地址)    ==>    ptr
        4)    &*num    ==>报错

4> 指针的大小与指针的类型之间的关系

        不同数据类型的指针所占内存空间都是一样的,都是指针的大小,32位系统下为4字节,64位系统下为 8字节

        指针的数据类型存在的意义,不是为了给指针分配内存空间的,而是为了指针偏移使用的

        不同类型的指针,在进行指针偏移时,偏移的大小跟指针的数据类型有关

        指针每偏移一个单位,内存空间就会偏移一个数据类型大小的字节数

        指针指向普通变量时,指针的偏移是没有意义的,但是,指针指向数组时,指针的偏移就有了现实的意义,表示指向上一个元素或者下一个元素的地址

5> 指针可以使用的运算

        关系运算: == 判断两个指针是否指向同一个内存地址,ptr==NULL,判空指针

        数加运算:表示对指针进行偏移

        取值运算(*)、取址运算(&)

二、指针指向普通变量作为函数参数

 1> 指针作为函数的参数进行数据传递时,不一定是地址传递

 三、指针指向数组

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;

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;
}

4>指针与字符串的关系

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;
}

5> 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 = &num;    //p1保护的是指针指向内存空间中的值
	int const *p2 = &num;    //与p1一样
	int * const p3 = &num;   //p3保护的是指针中的值
	const int * const p4 = &num; //两个都保护
 
	//验证p1保护哪个内容
	//*p1 = 999;           //更改指针指向内存空间中的值,报错
	//p1 = &key;           //更改指针的值
	
	//验证p2保护哪个内容
	//*p2 = 999;           //更改指针指向内存空间中的值,报错
	// p2 = &key;           //更改指针的值
 
	//验证p3保护哪个内容
	//*p3 = 999;           //更改指针指向内存空间中的值,报错
	// p3 = &key;           //更改指针的值
 
	//验证p4保护哪个内容
	*p4 = 999;           //更改指针指向内存空间中的值,报错
	p4 = &key;           //更改指针的值
 
 
	return 0;
}

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值