C语言核心知识点Day03

本文详细介绍了C语言中的字符串查找函数strstr的指针实现,内存管理的calloc和realloc函数用法,以及在使用中应注意的一级指针问题。此外,还探讨了二级指针在输入输出特性中的应用,并通过示例展示了如何利用二级指针实现文件读写。最后,讲解了位运算的基本操作,包括按位取反、位与、位或、位异或以及移位运算符的使用。
摘要由CSDN通过智能技术生成

1.字串比较

strstr的指针实现:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>

//字串比较
char* findStrstr(char* sPtr,const char* buffer)
{
	while (*sPtr)
	{
		if (*sPtr == *buffer)
		{
			char* tempsPtr = sPtr;//存储开始比对的位置
			const char* tempBuffer = buffer;//临时指针指向需要比对的字符串
			while (tempBuffer != '\0')
			{
				if (*tempBuffer != *sPtr)
				{
					sPtr = tempsPtr;
					++sPtr;
					break;
				}
				++tempBuffer;
				++sPtr;
			}
			if(*tempBuffer == '\0')
				return tempsPtr;
		}
		else
			++sPtr;
	}
	return NULL;
}

int main()
{
	char str1[] = "abcdefg";
	const char* str2 = "bd";
	printf("%s\n",findStrstr(str1, str2));
	return 0;
}

2.calloc和realloc

1.calloc函数(用法与malloc类似)
#include <stdlib.h>
void *calloc(size_t nmemb, size_t size);
功能:
在内存动态存储区中分配nmemb块长度为size字节的连续区域。calloc自动将分配的内存置0。
参数:
nmemb:所需内存单元数量
size:每个内存单元的大小(单位:字节)
返回值:
	成功:分配空间的起始地址
失败:NULL
void test01()
{
	//开辟连续的十个int类型的内存空间
	int* p = (int *)calloc(10, sizeof(int));
	for (int i = 0; i < 10; ++i)
	{
		p[i] = i + 1;
	}
	for (int i = 0; i < 10; ++i)
	{
		printf("%d ", p[i]);
	}
	if (p)
	{
		free(p);
		p = NULL;
	}
}
2.	realloc函数
#include <stdlib.h>
void *realloc(void *ptr, size_t size);
功能:
重新分配用malloc或者calloc函数在堆中分配内存空间的大小。
realloc不会自动清理增加的内存,需要手动清理,如果指定的地址后面有连续的空间,那么就会在已有地址基础上增加内存,如果指定的地址后面没有空间,那么realloc会重新分配新的连续内存,把旧内存的值拷贝到新内存,同时释放旧内存。
参数:
ptr:为之前用malloc或者calloc分配的内存地址,如果此参数等于NULL,那么和realloc与malloc功能一致
size:为重新分配内存的大小, 单位:字节
返回值:
成功:新分配的堆内存地址
失败:NULL
void test02()
{
	int* p = malloc(sizeof(int) * 10);
	for (int i = 0; i < 10; ++i)
	{
		p[i] = i + 1;
	}
	for (int i = 0; i < 10; ++i)
	{
		printf("%d ", p[i]);
	}
	printf("\n");

	printf("%d\n", p);
	p = realloc(p, sizeof(int) * 10);
	printf("%d\n", p);
	for (int i = 0; i < 20; ++i)
	{
		printf("%d ", p[i]);
	}

}

3.一级指针注意事项

1 越界
2.指针叠加会不断改变指针指向
void test(){
	char *p = (char *)malloc(50);
	char buf[] = "abcdef";
	int n = strlen(buf);
	int i = 0;

	for (i = 0; i < n; i++)
	{
		*p = buf[i];
		p++; //修改原指针指向
	}
	//因为指针指向改变,因此释放时会发生错误(free内部会存储之前开辟的空间大小,释放时因为释放原开辟空间的内存大小,同时指针指向改变,因此会发生错误)
	free(p);
}
3 返回局部变量地址
4 同一块内存释放多次

4.二级指针

1.二级指针做输入特性
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
//主调函数开辟空间
void printArray(int** pArray, int len)
{
	for (int i = 0; i < len; i++)
	{
		printf("%d\n", *pArray[i]);
	}
}

void test01()
{
	//创建在堆区
	int** pArray = malloc(sizeof(int*) * 5);
	int a1 = 10;
	int a2 = 20;
	int a3 = 30;
	int a4 = 40;
	int a5 = 50;

	pArray[0] = &a1;
	pArray[1] = &a2;
	pArray[2] = &a3;
	pArray[3] = &a4;
	pArray[4] = &a5;

	printArray(pArray, 5);

	if (pArray != NULL)
	{
		free(pArray);
		pArray = NULL;
	}
}

void test02()
{
	//创建在栈区
	int* pArray[5];

	for (int i = 0; i < 5; i++)
	{
		pArray[i] = malloc(4);
		*(pArray[i]) = 10 * i;
	}
	printArray(pArray, 5);
}

int main()
{
	//test01();
	test02();
	return 0;
}
2 二级指针做形参输出特性
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
//输出特性,内存又被调函数分配,主调函数释放
void outValue(int **p)
{
	int* temp = (int* )malloc(sizeof(int) * 10);
	for (int i = 0; i < 10; i++)
	{
		*(temp+i) = i + 1;
	}
	*p = temp;
}

void test01()
{
	int* p = NULL;
	outValue(&p);
	for (int i = 0; i < 10; i++)
	{
		printf("%d ", *(p + i));
	}
	if (p != NULL)
	{
		free(p);
		p = NULL;
	}

}

int main()
{
	test01();
	return 0;
}
案例:用二级指针的输入输出特性完成文件读写
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<string.h>
#include<stdlib.h>
//二级指针读写文件

int getFileline(FILE* fp)//读取文件行数
{
	if (fp == NULL)
		return -1;

	int readNum = 0;

	char buffer[1024] = { 0 };

	while (fgets(buffer, 1024, fp) != NULL)
	{
		++readNum;
	}	
	return readNum;
}
 
void fileValue(FILE* fp, char** arrFile,int len)//获取文件内容
{
	if (fp == NULL)
		return;

	if (arrFile == NULL)
		return;

	if (len <= 0)
		return;

	char buffer[1024] = { 0 };
	int i = 0;
	while (fgets(buffer, 1024, fp) != NULL) 
	{
		int nowLines = strlen(buffer) + 1;
		arrFile[i] = malloc(sizeof(char) * 1024);
		strcpy(arrFile[i], buffer);
		++i;
		memset(buffer, 0, 1024);
	}
	
}

void ptintFilevalue(char** arrFile,int fileLines)
{
	for (int i = 0; i < fileLines; i++)
	{
		printf("%s", arrFile[i]);

		//释放
		if (arrFile[i] != NULL)
		{
			free(arrFile[i]);
			arrFile[i] = NULL;
		}
	}
}

void test01()
{
	FILE* fp = fopen("a.txt", "r");
	if (fp == NULL)
		return -1;

	//获取文件行数 
	//注:在调用获取文件行数的代码的时候,在传入fp后对文件内容进行读取,但是同时fp指针的指向也会发
	//生变化,因此在下一个函数中调用fp的时候,此时fp已经指向文件末尾了,因此之后的代码中所用到的fp
	//都是已经指向文件末尾的文件指针,因此没有效果。
	int fileLines = 10;
	fileLines = getFileline(fp);
	fseek(fp, 0, SEEK_SET);//重新定位文件指针
	char** arrFile = malloc(sizeof(char*) * fileLines);

	//获取文件内容
	fileValue(fp, arrFile, fileLines);

	//关闭文件
	fclose(fp);
	fp = NULL;

	//输出文件内容
	ptintFilevalue(arrFile, fileLines);

	//释放
	if (arrFile != NULL)
	{
		free(arrFile);
		arrFile = NULL;
	}
}

int main()
{
	test01();
	return 0;
}
3.多级指针:有与二级指针类似的性质,注意*符号的运算以及解引用时对应的值。

5.位运算

	可以使用C对变量中的个别位进行操作。C提供位的逻辑运算符和移位运算符。
5.1 位运算符
	1.位逻辑运算符:
		4个位运算符用于整型数据,包括char.将这些位运算符成为位运算的原因是它们对每位进行
	操作,而不影响左右两侧的位。请不要将这些运算符与常规的逻辑运算符(&& 、||和!)相混淆,
	常规的位的逻辑运算符对整个值进行操作。
	2.移位运算符号
	
5.1.1 按位取反~
//按位取反操作~
void test01()
{
	int num = 2;//010,取反后为101,101是一个负数,因此在计算机中的存储是取反+1(110),以补码的形式存在,因此是111
	printf("取反:%d\n", ~num);
}
5.2.2 位与: &
	二进制运算符&通过对两个操作数逐位进行比较产生一个新值。对于每个位,只有两个操作
数的对应位都是1时结果才为1。
//位与操作 &
void test02()
{
	int num = 762;
	if ((num & 1) == 0)
		printf("偶数!");
	else
		printf("奇数!");
	num &= 0;//清零操作
}
5.1.3 位或: |
	二进制运算符|通过对两个操作数逐位进行比较产生一个新值。对于每个位,如果其中任
意操作数中对应的位为1,那么结果位就为1.
void test03()
{
	int num1 = 5;//0101
	int num2 = 3;//0011

	printf("%d\n", num1 | num2);//0111
}
5.1.4 位异或: 
	二进制运算符^对两个操作数逐位进行比较。对于每个位,如果操作数中的对应位有一个
是1(但不是都是1),那么结果是1.如果都是0或者都是1,则结果位0.
//位异或操作 ^ 两位结果不相等 则位0 反之为1
void test04()
{
	//A^B = C \C^B = A \C^A = B
	int num1 = 5;
	int num2 = 9;
	num1 = num1 ^ num2;//C = A ^ B
	num2 = num1 ^ num2;//B~ = C ^ B
	num1 = num1 ^ num2;//A~ = C ^ B~
	printf("%d\n", num1);
	printf("%d\n", num2);
}
5.1.5 移位运算符:左移右移
注:
	左移:空余位补零。
	右移:对于unsigned类型,使用0填充左端空出的位。对于有符号类型,结果依赖于机器。
空出的位可能用0填充,或者使用符号(最左端)位的副本填充。
//移位运算符 左移一位相当于*2 右移一位相当于/2
void test05()
{
	int num = 10;
	//注意的是:移位运算符并不会改变数字本身
	printf("%d\n", num << 2);// *4
	printf("%d\n", num >> 1);// /2
}
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值