C语言指针的用途

模拟实现strlen

  1. 递归
int my_strlen(char *str)
{
	if(*str == '\0')
	{
		return  0;
	}
	else
	{
		return 1+my_strlen(str+1);
	}
}
int my_strlen(char *str)
{
	char *p = str;
	while(*p!='\0')
	{
		p++;
	}
	return p-s;
}

模拟实现strcpy

char *my_strlcpy(char *str1,char*str2)
{
	char *ret = str1;
	 // str1 的起点保存 
	 
	// 断言 
	assert(str1!='\0');
	assert(str2!='\0');
	while(*str1++ = *str2++);
	return ret;
}

模拟实现strcat

注意*++str与*str++

char *my_strcat(char*str1,char*str2)
{
	char *ret = str1;
	 // str1 的起点保存 
	 
	// 断言 
	assert(str1!='\0');
	assert(str2!='\0');
	while(*++str1);
	while(*str1++ = *str2++);
	puts(ret);
	return ret;
	
 } 

模拟实现strstr

C 库函数 char *strstr(const char *haystack, const char *needle) 在字符串 haystack 中查找第一次出现字符串 needle 的位置,不包含终止符 ‘\0’。

char *my_strstr(const char*str1,const char*str2)
{
	assert(str1);
	assert(str2);
	
	char*cp = (char*)str1;
	char*substr = (char*)str2;
	char *s1 = NULL;
	
	if(*str2 == '\0')
		return NULL;
		
	while(*cp)
	{
		// 重置substr 
		s1 = cp;
		substr = (char*)str2;
		
		while(*s1 && *substr && (*s1==*substr))
		{
			s1++;
			substr++;
		}
		
		// 把str2遍历完了 
		if(*substr=='\0')
		{
			return cp;
		 } 
		 // 否则下一个 
		cp++;
	}
}

模拟实现strcmp

比较字符串

int my_strcmp ( char * src,  char * dst)
{
	int ret = 0 ;
	while( ! (ret = *src - *dst) && *dst)
	{
		++src;
		++dst;
	}
	printf("%d\n",ret);
		
	if ( ret < 0 )
		ret = -1 ;
	else if ( ret > 0 )
		ret = 1 ;
	return( ret );
}

模拟实现memcpy

C 库函数 void *memcpy(void *str1, const void *str2, size_t n) **从存储区 str2 复制 n 个字节到存储区 str1。

函数memcpy从str2的位置开始向后复制n个字节的数据到str1的内存位置。

void *my_memcpy(void *str1,const void*str2,int n)
{
	void *ptr1 = str1;
	while(n--)
	{
		*(char*)str1 = *(char*)str2;
		str1 = (char*)str1+1;
		str2 = (char*)str2+1;
	}
	return (ptr1);
}

拷贝长度::strlen+1 不要漏了’\0’

 // 将字符串复制到数组 dest 中//	 
	const char src[50] = "http://www.runoob.com";
   	char dest[50];
   	
//   	拷贝长度::strlen+1 不要漏了'\0' 
   	my_memcpy(dest,src,strlen(src)+1) ;
   	printf("dest = %s\n", dest);

模拟实现memmove

函数原型:void *memcpy (void *p,void *m, size_t num);

memcpy与strcpy相比,memcpy函数用来做内存拷贝,可以用它拷贝任何数据类型的对象,并且可以指定拷贝的数据长度。stycpy函数也是用来做内存拷贝,并且只能拷贝字符串类型的数据。memcpy并不是遇到"\0"就结束,而是一定会拷贝完num个字节。而strcpy 遇到"\0"就结束。

·如果源空间和目标空间出现重叠,就得使用memmove函数处理。
在这里插入图片描述

#include<stdio.h>
#include <assert.h>
#include<string.h>


char *my_memmove(void *str1,const void*str2,int n)
{
	char *ptr1 = (char*)str1;
	if(str1<str2 || (char*)str1 >= (char*)str2 + n)
	{
		while(n--)
		{
			*(char*)str1 = *(char*)str2;
			str1 = (char*)str1+1;
			str2 = (char*)str2+1;
		}
		return (ptr1);
	}
	else
	{
		str1 = (char*)str1 + n-1;
		str2 = (char*)str2 + n-1;
		while(n--)
		{
			*(char*)str1 = *(char*)str2;
			str1 = (char*)str1-1;
			str2 = (char*)str2-1;
		}
	}
	return ptr1;
	
}
char str[20] = "qyuwhsjagf";

	printf("str = %s\n", str);
	my_memmove(str+3, str , 4);

	printf("str = %s\n", str);

一维数组

//一维数组
int a[] = {1,2,3,4};
printf("%d\n",sizeof(a));
printf("%d\n",sizeof(a+0));
printf("%d\n",sizeof(*a));
printf("%d\n",sizeof(a+1));
printf("%d\n",sizeof(a[1]));
printf("%d\n",sizeof(&a));
printf("%d\n",sizeof(&a+1));
printf("%d\n",sizeof(&a[0]));
printf("%d\n",sizeof(&a[0]+1));
16
8
4
8
4
8
8
8
8

一级指针

二维数组

//二维数组
int a[3][4] = {0};
printf("%d\n",sizeof(a));
printf("%d\n",sizeof(a[0][0]));
printf("%d\n",sizeof(a[0]));
printf("%d\n",sizeof(a[0]+1));
printf("%d\n",sizeof(a+1));
printf("%d\n",sizeof(&a[0]+1));
printf("%d\n",sizeof(*a));
printf("%d\n",sizeof(a[3]));
48
4
16
8
8
8
16
16

数组名 a 在表达式中也会被转换为和 p 等价的指针!

#include <stdio.h>
int main(){
    int a[3][4] = { {0, 1, 2, 3}, {4, 5, 6, 7}, {8, 9, 10, 11} };
    int (*p)[4] = a;
    printf("%d\n", sizeof(*(p+1)));

    return 0;
}

*(p+1)+1表示第 1 行第 1 个元素的地址。如何理解呢?

*(p+1)单独使用时表示的是第 1 行数据,放在表达式中会被转换为第 1 行数据的首地址,也就是第 1 行第 0 个元素的地址

因为使用整行数据没有实际的含义,编译器遇到这种情况都会转换为指向该行第 0 个元素的指针;就像一维数组的名字,在定义时或者和 sizeof、& 一起使用时才表示整个数组,出现在表达式中就会被转换为指向数组第 0 个元素的指针。

a+i == p+i
a[i] == p[i] == *(a+i) == *(p+i)
a[i][j] == p[i][j] == *(a[i]+j) == *(p[i]+j) == *(*(a+i)+j) == *(*(p+i)+j)

((p+1)+1)`表示第 1 行第 1 个元素的值。很明显,增加一个 * 表示取地址上的数据。*

使用指针遍历二维数组

#include <stdio.h>
int main(){
    int a[3][4]={0,1,2,3,4,5,6,7,8,9,10,11};
    int(*p)[4];
    int i,j;
    p=a;
    for(i=0; i<3; i++){
        for(j=0; j<4; j++) printf("%2d  ",*(*(p+i)+j));
        printf("\n");
    }
    return 0;
}

二级指针

指针数组

在这里插入图片描述

数组指针

  • 当对数组名使用sizeof时,返回的是整个数组占用的内存字节数。当把数组名赋值给一个指针后,再对指针使用sizeof运算符,返回的是指针的大小。
int main(void)
{
    int arr[3] = {1,2,3};

    int*p = arr;
    printf("sizeof(arr)=%d\n",sizeof(arr));  //sizeof(arr)=12
    printf("sizeof(p)=%d\n",sizeof(p));   //sizeof(p)=4

    return 0;
}
  • 数值指针的引用
p[n] == *(p+n)

p[n][m] == *( *(p+n)+ m )
#include <stdio.h>

int main() {
   int arr[4][4] = {0,1,2,3,4,5,6,7,8,9,10,11,12,13,14,15};
   int (*p1)[4];   //数组指针
   int *p2[4];    //指针数组

   p1 = arr;
   printf("使用数组指针的方式访问二维数组arr\n");
   for (int i = 0; i < 4; ++i) {
       for (int j = 0; j < 4; ++j) {
           printf("arr[%d][%d]=%d\t",i,j,*(*(p1+i)+j));
      }
       printf("\n");
  }

   printf("\n使用指针数组的方式访问二维数组arr\n");
   for (int k = 0; k < 4; ++k) {
       p2[k] = arr[k];
       初始化指针数组
  }
   for (int i = 0; i < 4; ++i) {
       for (int j = 0; j < 4; ++j) {
           printf("arr[%d][%d]=%d\t",i,j,*(p2[i]+j));
      }
       printf("\n");
  }

   return 0;
}

指针和数组的定义、声明

数组参数、指针参数

C 语言中,实参传递给形参,是按值传递的,也就是说,函数中的形参是实参的拷贝份,形参和实参只是在值上面一样,而不是同一个内存数据对象

这就意味着:这种数据传递是单向的,即从调用者传递给被调函数,而被调函数无法修改传递的参数达到回传的效果。

void change(int a)
{
    a++;      //在函数中改变的只是这个函数的局部变量a,而随着函数执行结束,a被销毁。age还是原来的age,纹丝不动。
}
int main(void)
{
    int age = 19;
    change(age);
    printf("age = %d\n",age);   // age = 19
    return 0;
}

函数指针

因为传递的是age的地址,因此pa指向内存数据age。当在函数中对指针pa解地址时,会直接去内存中找到age这个数据,然后把它增1。

void change(int* pa)
{
    (*pa)++;   //因为传递的是age的地址,因此pa指向内存数据age。当在函数中对指针pa解地址时,
               //会直接去内存中找到age这个数据,然后把它增1。
}
int main(void)
{
    int age = 19;
    change(&age);
    printf("age = %d\n",age);   // age = 20
    return 0;
}

函数指针数组、函数指针的数组的指针

回调函数

  • 1
    点赞
  • 5
    收藏
    觉得还不错? 一键收藏
  • 1
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 1
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值