学习C语言 8.7 指针操作数组

目录

一、指针操作一维字符型数组 

1.定义指针

2.指针 + 字符串 


一、指针操作一维字符型数组 

1.定义指针

char s[] = "hello"';

char *p=&a[0];

char *p = s; //数组名的值就是首元素的地址

2.指针 + 字符串 

字符串 // 在c语言中是按照字符数组的形式存储
            // 字符串常量 --- 存储在字符串常量区 
       
处理字符串:
   char s[] = "hello"; //表示 在栈上开辟一块空间,用字符串常量中的 "hello"进行初始化 
                        
   const char *p = "hello"; //表示 p指向了 字符串常量区中的 "hello"
                                       //因为 是指向了字符串常量区 ,所以只能做读取操作,不能修改

3.const 关键字

const //表示只读  

const int a; //a 此时是一个只读的变量

const int *p = &a;   //const限定是 基类型 
                     //表示不能通过 *p 的方式 修改基类型数据 
                     
int const *p = &a;   //const限定是 基类型 
                     //表示不能通过 *p 的方式 修改基类型数据 

                     
int * const p = &a; //const限定是 指针变量p 
                    //表示将p限定位只读 
                    //表示p不能被修改 
                    
const int * const p = &a;  //基类型和指针变量 都被限定为只读
                           // p = &b; //不能修改 
                           //*p = b;  //不能修改

原则:
   就近原则  //const 离谁近 就限定谁  
应用:
    1.如果 不想 通过*p方式改变基类型对应的数据 
      const int *p = &a;  
      int const *p = &a;  
    2.如果 指针变量p 定义好后,不想再指向别的变量 
      则 
        int * const p = &a;
                     

在函数中形参设计为 const char *
    目的:防止函数中的误操作 
    好处:
    (1).提前发现问题 
        将运行时才出现的问题,提前到编译时  
    (2).const char *
        可以接收(可以将可读可写的传给只读的,但不能反过来,否则会使得权限扩大) 
        char *
        const char *

       实参:
         可以 数组名 
         可以 指针变量  char *p //const char *p         
         可以 直接是一个字符串常量 
        提高参数的适用性 
        
    所以能写成const的 都写const。

gets函数,通过指针形式

#include <stdio.h>

char * mygets(char *s)
{
	char *ret = s;
	scanf("%c",s);
	while(*s!='\n')
	{
		scanf("%c",++s);
	}
	*s='\0';
	return  ret;
}


int main(void)
{
	char b[100];
	mygets(b);
	puts(b);

	return 0;
}

puts函数,通过指针形式

#include <stdio.h>

int myputs(const char *s)
{
	if(s==NULL)
	{
		return -1;
	}
	while(*s != '\0')
	{
		putchar(*s++);
	}
	putchar('\0');

	return 0;
}

int main(void)
{
	char a[]="hello";
	char *p=a;
	//char *p=&a[0];

	const char *q="world";

	myputs(p);
	myputs(a);
	myputs(q);
	myputs("well");

	return 0;

}

指向栈上的的指针,指向字符串常量区的指针,数组名,和字符串常量都可以输出。

strlen函数,通过指针形式

#include <stdio.h>

size_t mystrlen(const char *s)
{
	int i=0;
	while(*s!='\0')
	{
		++s;
		++i;
	}
	return i;
}

int main(void)
{
	char a[]="hello";
	puts(a);
	printf("%ld\n",mystrlen(a));

	return 0;
}

strcpy函数,strncpy函数通过指针形式

char src[] = "hello"
strncpy(dest,src,8);

    char *Strncpy(char *dest, const char *src, size_t n)
    {
        //1.始终拷贝了n下 
        
        //1. 拷贝 
            '\0' && n 
        //2. 考虑n 
             n有没有结束 
             完成剩余的次数的拷贝 
             剩余的拷贝过去的数据是 '\0'
    }

#include <stdio.h>

char * mystrcpy(char *dest,const char *src)
{
	char *ret=dest;
	while(*src!='\0')
	{
		*dest=*src;
		dest++;
		src++;
	}
	*dest='\0';

	return ret;
}

char * mystrncpy(char *dest,const char *src,size_t n)
{
	char *ret=dest;
	int i=0;
	while(*src!='\0' && i!=n )
	{
		*dest=*src;
		dest++;
		src++;
		i++;
	}
	if(i<n)
	{
		int j=0;
		for(j=0;j<(n-i);++j)
		{
			*dest='\0';
			dest++;
		}
	}
	return ret;
}

int main(void)
{
	char a[100]="helloworld";
	char b[100]={1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1,1};

	puts(a);
	mystrncpy(b,a,15);
	puts(b);

	int i=0;
	for(i=0;i<20;++i)
	{
		printf("b[%d]%c %d\n",i,b[i],b[i]);
	}
	return 0;
}

strcat函数,strncat函数通过指针形式

char *strcat(char *dest, const char *src)
{
  //1.定位 dest的 '\0'
  //2.拷贝 
    直到src到达'\0'
}

char src[] = "hello";

strncat(dest,src,3);
char *Strncat(char *dest, const char *src, size_t n)
{
   //1.可以指定 n 
   //如果 src 长度 > n  
    就将前n个字符拼接过去 
   //如果 src 长度 < n
    直接将src字符串拼接过去
    
   最终 一定要保证 dest是一个字符串 '\0'

}

#include <stdio.h>

char * mystrcat(char *dest,const char *src)
{
	char *ret=dest;
	while(*dest!='\0')
	{
		dest++;
	}
	while(*src!='\0')
	{
		*dest=*src;
		dest++;
		src++;
	}
	*dest='\0';

	return ret;
}

char * mystrncat(char *dest,const char *src,size_t n)
{
	char *ret=dest;
	while(*dest!='\0')
	{
		dest++;
	}
	while(*src!='\0'&&n!=0)
	{
		*dest=*src;
		dest++;
		src++;
		n--;
	}
	*dest='\0';

	return ret;
}

int main(void)
{
	char a[100]={'h','e','l','l','o','\0',1,1,1,1,1,1,1,1,1,1,1,1};
	char b[100]="world";

	mystrncat(a,b,3);
	puts(a);
	
	int i=0;
	for(i=0;i<20;++i)
	{
		printf("a[%d]%c %d\n",i,a[i],a[i]);
	}

	

strcmp函数,strncmp函数通过指针形式

#include <stdio.h>

int mystrcmp(const char *s1,const char *s2)
{
	while(*s1==*s2 && *s1!='\0' && *s2!='\0')
	{
		s1++;
		s2++;
	}
	return *s1-*s2;
}

int mystrncmp(const char *s1,const char *s2,size_t n)
{
	while(*s1==*s2 && *s1!='\0' && *s2!='\0'&& n>1)
	{
		s1++;
		s2++;
		n--;
	}
	return *s1-*s2;
}
int main(void)
{
	char a[100]="hello";
	char b[100]="help";

	puts(a);
	puts(b);

	int ret = mystrncmp(a,b,3);
	
	printf("%d\n",ret);
	

	return 0;
}

n减到0的时候,两个字符串最后停位置是在后一个,所以条件是n>1而不是n不为0。

以上函数的返回值有些是如char *的指针类型,这是为了进行链式操作

eg: char s1[10];
        char s2[10];

strcpy(s2,strcpy(s1,"hello"));//链式操作 

strcpy只能拷贝字符串,而memcpy可以拷贝任意类型的数据,只要有地址。但要注意不同类型之间拷贝的话,可能会出现数据覆盖。

void *memcpy(void *dest, const void *src, size_t n)
 {
      //一个字节一个字节拷贝(char类型刚好是一个字节) 
 }

 
 void * //NULL 空指针 
        //空类型的指针 --- 万能指针
        //可以接收任意类型的指针
        
注意:如果用空类型指针进行间接运算必须转换成有明确类型的指针 

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

void * mymemcpy(void *dest, const void *src, size_t n)
{
	char *p=dest;
	const char *q=src;
	int i=0;
	for(i=0;i<n;++i)
	{
		*p=*q;
		p++;
		q++;
	}
	return p;
}

int main(void)
{
	long a[5]={1,2,3,4,5};
	long b[5];

	mymemcpy(b,a,5*sizeof(a[0]));

	int i=0;
	for(i=0;i<5;++i)
	{
		printf("%ld\n",b[i]);
	}

	return 0;
}

二、指针操作二维数组 

int a[2][3];

//二维数组 
        c语言中并不存在,真正的二维数组。
        二维数组本质 是一维数组的一维数组 
        二维数组 也 符合数组的特点 //连续性,有序性,单一性 

//从二维数组的本质出发 
int[3] a[2]; 

1.定义指针

    //a[0]  --- int[3]
    //&a[0] --- int[3] * 
    //c语言中 不支持 int[3] *  
    //正确写法 int(*)[3]

int(*p)[3] = a; //p指向二维数组 a 
                //p的基类型 int[3]

2.访问数组中的元素

*p <=> a[0] // 相当于是内部这个一维数组的数组名 
 a[0][0] <=> (*p)[0] //一维数组的元素是通过*(p+i)访问的
                    *(*(p+0)+0) //**p

*(*(p+1)+1) <=> a[1][1]
*(*(p+i)+j) <=> a[i][j]       

   二维数组的本质 一维数组的 一维数组

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值