C进阶——指针和字符串

一、数组与指针的关系

数组:数组是用于储存多个相同类型数据的集合。
指针:指针相当于一个变量,但是它和不同变量不一样,它存放的是其它变量在内存中的地址。
PS:使用const创建数组时必须初始化赋值,后续无法在进行赋值。
数组是实际上是一块连续的地址,而指针也是表示地址,所以说数组是特殊的指针,数组是const类型的指针,即数组的地址不可以赋值,在函数中,数组传参是会退化成指针。
看下面的例子:

#include<stdio.h>
#include<stdlib.h>

void show_1(int a[])
{
	int i = 0;
	while (a[i] != -1)
	{
		printf("%d\t", a[i++]);
	}
	printf("\n");
}

void show_2(int *a)
{
	while (*a != -1)
	{
		printf("%d\t",*a++);
	}
	printf("\n");
}

int main()
{
	int a[5] = { 1, 2, 3, 4, -1 };	//-1作为结束标志位

	show_1(a);
	show_2(a);
	return 0;
}

在这里插入图片描述
可见对函数传递数组时可以使用指针进行操作。

二、指针

1.初始化

定义指针时最好初始化,可以这么初始化int *p = NULL; or int *q = 0;或者直接指向一个向量地址如int i = 5; int *r = &i;

2.const位置

(1)如果const在号前面的话说明不能通过指针对指针所指地址里面的值进行修改;
(2)若果const在
号后面的话就说明不能修改指针所指的地址;

下面这个例子就是两种const的错误示范:

	int i = 5;
	int k = 3;
	const int *p = &i;		//const数值
	int * const q = &i;		//const指针
	*p = 132;				//无法对指针所指地址里面的值进行修改
	q = &k;					//无法对指针进行重赋值
3.指针加1

我们知道对一个数值加1,比如1+1=2;这个很简单,但是对指针加1会是什么样子呢?我们先上一段代码

#include<stdio.h>
#include<stdlib.h>


int main()
{
	char b[] = { 1,2,3,4,5,6 };
	int a[] = { 1,2,3,4,5,6 };
	
	int *p1 = &a[0];
	int *p2 = &a[5];

	char *q1 = &b[0];
	char *q2 = &b[4];

	printf("%p\n", p1);
	printf("%p\n", p2);
	printf("%p\n", p1+1);
	printf("%p\n", p2+1);


	//选中代码段,先按住Ctrl+k,再按Ctrl+c,就可以进行如下注释
	//printf("%p\n", q1);
	//printf("%p\n", q2);

	return 0;
}

我们运行程序可以看见p1和(p1+1)的值相差4;而q1和(q1+1)却只相差1。这是因为p1是int型的,在计算机中为四个字节,所以(p1+1)就表示增加了一个int,同理q1也是如此。
在这里插入图片描述

4.两个指针相减
#include<stdio.h>
#include<stdlib.h>

int main()
{
	char b[] = { 1,2,3,4,5,6 };
	int a[] = { 1,2,3,4,5,6 };
	
	int *p1 = &a[0];
	int *p2 = &a[5];

	char *q1 = &b[0];
	char *q2 = &b[4];

	//printf("p1的地址 = %p\n", p1);
	//printf("p1+1的地址 = %p\n", p1+1);
	//printf("q1的地址 = %p\n", q1);
	//printf("q1+1的地址 = %p\n", q1+1);

	printf("%d\n", p2 - p1);
	printf("%d\n", q2 - q1);

	return 0;
}

得到结果
在这里插入图片描述
原因和第3点一样不重复说明。

PS:*p++指的是先取出p里面的值,然后再把地址加1。这条语句可以被某些CPU直接翻译成汇编语言,所以效率高。

5. 0地址

使用:

  1. 假设动态分配内存失败,则会返回一个NULL
  2. 指针初始化
    int *p = NULL;
6. void* 和动态分配内存

void* 表示创建不知道指向什么的指针,假设我们刚开始不知道这个指针要指向什么,我们可以先这么创建,之后再利用强制转换改变类型。
malloc():动态分配内存。申请失败返回NULL or 0。
free():只能释放掉动态分配的内存。
两个一定要成对使用,避免内存越用越小,导致程序速度越来越慢。

#include<stdio.h>
#include<stdlib.h>

int main()
{
	int len = 5;
	int *p = (int*)malloc(sizeof(int) * len);
	free(p);
	return 0;
}

三、字符串

1. 字符串头文件

常用字符串函数都包含在头文件#include<string.h>里面

2. 常用字符串函数

1、字符串的拷贝

/直接将源中的字符串复制到目标/

char *strcpy(char *dest, const char *src)
{
    char *tmp = dest;
    while ((*dest++ = *src++) != '\0');
    return tmp;
}

/将源字符串中的前count 个字符复制到目标/

char *strncpy(char *dest, const char *src, size_t count)
{
	char *tmp = dest;
	while (count)、
	 {
		 if ((*tmp = *src) != 0)
		 src++;
		 tmp++;
		 count--;
	}
	return dest;
}

2、连接两个字符串

char *strcat(char *dest, const char *src)
{
    char *tmp = dest;
    while (*dest)
    dest++;
    while ((*dest++ = *src++) != '\0')
    	;
    return tmp;
}

/将源字符串中的前count个字符附加到目标字符串的尾部/

char *strncat(char *dest, const char *src, size_t count)
{
    char *tmp = dest;
    if (count)
     {
	    while (*dest)
	    dest++;
	    while ((*dest++ = *src++) != 0) 
	    {
		    if (--count == 0)
		     {
			    *dest = '\0';
			    break;
		    }
	    }
    }
    return tmp;
}

3、比较两个字符串

int strcmp(const char *cs, const char *ct)
{
    int res;
    while (1)
     {
	    if ((res = *cs - *ct++) != 0 || !*cs++)
	    	break;
    }
    return  res;
}

/只比较前count个字符/

int strncmp(const char *cs, const char *ct, size_t count)
{
    signed char __res = 0;
    while (count) 
    {
	    if ((__res = *cs - *ct++) != 0 || !*cs++)
	    	break;
	    count--;
    }
    return __res;
}

4、在字符串中查找找一个字符

/在字符串中查找第一次出现要查找的字符/

char *strchr(const char *s, char c)
{
    for (; *s != c; ++s)
	    if (*s == '\0')
	    	return NULL;
    return (char *)s;
}

/在字符串中查找最后一次出现要查找的字符/

char *strrchr(const char *s, int c)
{
       const char *p = s + strlen(s);
       do {
           if (*p == (char)c)
               return (char *)p;
       } while (--p >= s);
       return NULL;
}

/在有限制长度的字符串中查找第一次出现要查找的字符/

char *strnchr(const char *s, size_t count, char c)
{
    for (; count-- && *s != '\0'; ++s)
	    if (*s == c)
	   		return (char *)s;
    return NULL;
}

5、求字符串的长度

size_t strlen(const char *s)
{
    const char *sc;
    for (sc = s; *sc != '\0'; ++sc);
    return sc - s;
}

6、在源字符串中查找子字符串

char *strstr(const char *s1, const char *s2)
{
    int l1, l2;
    l2 = strlen(s2);
    if (!l2)
    	return (char *)s1;
    	
    l1 = strlen(s1);
    while (l1 >= l2) 、
    {
	    l1--;
	    if (!memcmp(s1, s2, l2))
	    	return (char *)s1;
	    	
	    s1++;
    }
    return NULL;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值