c语言(五)

c语言(五)

静态分配内存

在程序编译或运行过程中,按事先规定大小分配内存空间的分配方式。int a [10]
必须事先知道所需空间的大小。

分配在栈区或全局变量区,一般以数组的形式。

按计划分配。

动态分配内存

在程序运行过程中,根据需要大小自由分配所需空间。
按需分配。
分配在堆区,一般使用特定的函数进行分配。

动态分配函数

头文件#include<stdlib.h>

malloc 函数

函数原型: void *malloc(unsigned int size);

在内存的动态存储区(堆区)中分配一块长度为size 字节的连续区域,用来存放类型说明符指定的类型。
函数原型返回void*指针,使用时必须做相应的强制类型转换,函数的返回值:返回申请的内存的首地址(申请成功),返回NULL(申请失败)

在调用malloc 之后,一定要判断一下,是否申请内存成功。

如果多次malloc 申请的内存,第1 次和第2 次申请的内存不一定是连续的

最后使用free函数释放指针变量指向的内存

#include<stdio.h>
#include<stdlib.h>
int main()
{
	int* p,i;
	p = (int *)malloc(20); //开辟20个字节
	if (p==NULL)
	{
		printf("开辟内存失败\n");
		return 0;
	}
	printf("p的值%s\n", p);
	memset(p,0,20); //如果分配的内存空间内容不确定,一般使用memset 初始化。
	printf("p的值%s\n", p);
	for (i = 0; i < 5; i++)   //int类型一个元素占4个字节
	{
		p[i] =i;
		printf("p[%d]=%d\n", i, p[i]);
	}
	free(p);
	return 0;
}

free 函数释放内存函数

一块动态申请的内存只能free 一次,不能多次free

calloc 函数

函数定义:void * calloc(size_t nmemb,size_t size);

char *p=(char *)calloc(3,100);堆中申请了3 块,每块大小为100 个字节,即300 个字节连续的区域。

size_t 实际是无符号整型,它是在头文件中,用typedef 定义出来的。在内存的堆中,申请nmemb 块,每块的大小为size 个字节的连续区域。函数的返回值:返回申请的内存的首地址(申请成功),返回NULL(申请失败)

malloc 申请的内存,内存中存放的内容是随机的,不确定的,而calloc 函数申请的内存中的内
容为0

#include<stdio.h>
#include<stdlib.h>
int main()
{
	int* p,i;
	p = (int *)calloc(1,20); //开辟1块20个字节
	if (p==NULL)
	{
		printf("开辟内存失败\n");
		return 0;
	}
	printf("p的值%s\n", p);
	memset(p,0,20); //如果分配的内存空间内容不确定,一般使用memset 初始化。
	printf("p的值%s\n", p);
	for (i = 0; i < 5; i++)   //int类型一个元素占4个字节
	{
		p[i] =i;
		printf("p[%d]=%d\n", i, p[i]);
	}
	free(p);
	return 0;
}

realloc 函数(重新申请内存)

malloc 和calloc 函数,单次申请的内存是连续的,两次申请的两块内存不一定连续。

malloc 或者calloc 申请了一块内存,在原先内存的基础上挨着继续申请内存,或者释放后边的一部分内存

函数的定义:void* realloc(void *s,unsigned int newsize);

在原先s 指向的内存基础上重新申请内存,新的内存的大小为new_size 个字节,如果原先内存后面有足够大的空间,就追加,如果后边的内存不够用,则relloc 函数会在堆区找一个newsize 个字节大小的内存申请,将原先内存中的内容拷贝过来,然后释放原先的内存,最后返回新内存的地址。

char *p;
p=(char *)malloc(100)
p=(char *)realloc(p,50);//重新申请内存,大小为50 个字节.100 个字节的后50 个字节的存储空间就被释放了

malloc calloc relloc 动态申请的内存,只有在free 或程序结束的时候才释放。

内存泄露

申请的内存,首地址丢了,找不着了,没法使用了,也没法释放了,这块内存就被泄露了。

char *p;
p=(char *)malloc(100);//申请100个字节的内存,p指向这100个内存
p="hello world";//p 指向别的地方了,原来申请的100个字节的内存还存在,但找不到了。
p=(char *)malloc(10);//申请10个字节的内存,p指向这10个内存
p=(char *)malloc(100);//又申请100个字节的内存,p指向这100个内存,原来10个内存就找不到了

解决办法,p在指向别的地方之前,用free函数释放掉。

所以申请的内存,一定不要把首地址给丢了,在不用的时候一定要释放内存。

字符串处理函数

#include <string.h>              头文件
#pragma warning(disable:4996)    在c 文件开始处写上这句话,即告诉编译器忽略4996 警
告,strcpy、scanf 等一些不安全的标准c 库函数在vs 中可以用了。

strlen

函数定义:size_t strlen(const char *s);

测字符指针s 指向的字符串中字符的个数,不包括’\0’,返回值:字符串中字符个数

#include<stdio.h>
#include<string.h>
int main()
{
	char a[] = "caicai";
	printf("sizeof:%d\n",sizeof a);
	printf("字符串长度:%d",strlen(a));//caicai是6个字节,加上字符串结束标志\0是7
	return 0;
}

strcpy

函数定义:char *strcpy(char *dest, const char *src);

拷贝src 指向的字符串到dest 指针指向的内存中,’\0’也会拷贝,函数的返回值:目的内存的地址

在使用此函数的时候,必须保证dest 指向的内存空间足够大,否则会出现内存污染。

#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996)
int main()
{
	char a[] = "hellow a shu";
	printf("sizeof%d,%s\n", sizeof a, a);
	strcpy(a, "nihao");
	printf("sizeof%d,%s\n",sizeof a,a);//拷贝‘\0’
	int i;
	for (i = 0; i < 13; i++)
	{
		printf("%c* ",a[i]);
	}
	return 0;
}

strncpy

char *strncpy(char *dest, const char *src, size_t n);

将src 指向的字符串前n 个字节,拷贝到dest 指向的内存中,返回值:目的内存的首地址

strncpy 不拷贝‘\0’

如果n 大于src 指向的字符串中的字符个数,则在dest 后面填充n-strlen(src)个’\0’

#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996)
int main()
{
	char a[] = "hellow.a.shu";
	printf("sizeof%d,%s\n", sizeof a, a);
	strncpy(a, "nihao",7);
	printf("sizeof%d,%s\n",sizeof a,a);
	int i;
	for (i = 0; i < 13; i++)
	{
		printf(" *%c* ",a[i]);   //第6,第7,第13个字节的字符值是空的,即都是’\0’
	}
	return 0;
}

strcat

char *strcat(char *dest, const char *src);

strcat 函数追加src 字符串到dest 指向的字符串的后面。追加的时候会追加’\0’,保证dest 指向的内存空间足够大。追加字符串的时候会追加’\0’

#include <stdio.h>
#include <string.h>
#pragma warning(disable:4996)
int main()
{
	char a[30] = "cai\0caicaicai";
	char* p = "hello";
	strcat(a, p);  //p有6个字节,一定要保证a剩余字节足够大
	printf("%s\n", a);
	return 0;
}

strncat

char *strncat(char *dest, const char *src, size_t n);

追加src 指向的字符串的前n 个字符,到dest 指向的字符串的后面。注意如果n 大于src 的字符个数,则只将src 字符串追加到dest 指向的字符串的后面,追加的时候会追加’\0’

#include <stdio.h>
#include <string.h>
#pragma warning(disable:4996)
int main()
{
	char a[30] = "cai\0caicaicai";
	char* p = "ha";
	strncat(a, p,5);  
	printf("%s\n", a);
	return 0;
}

strcmp与strncmp

int strcmp(const char *s1, const char *s2);

比较s1 和s2 指向的字符串的大小,
比较的方法:逐个字符去比较ascII 码,一旦比较出大小返回。
如果所有字符都一样,则返回0

返回值:

如果s1 指向的字符串大于s2 指向的字符串返回1
如果s1 指向的字符串小于s2 指向的字符串返回-1
如果相等的话返回0

int strncmp(const char *s1, const char *s2, size_t n);

比较s1 和s2 指向的字符串中的前n 个字符

#include <stdio.h>
#include <string.h>
int main()
{
	char a[] = "hello cai";
	char *b = "hello shu";
	if (strcmp(a, b) == 0)  //
		printf("a==b\n");
	else if (strcmp(a, b) > 0)
		printf("a>b\n");
	else
		printf("a<b\n");
	if (strncmp(a, b, 5) == 0)  //比较前5个字符都是hello
		printf("a==b\n");
	else if (strncmp(a, b, 5) > 0)
		printf("a>b\n");
	else
		printf("a<b\n");
	return 0;
}

strchr

char *strchr(const char *s, int c);

在字符指针s 指向的字符串中,找ascii 码为c 的字符,是首次匹配,如果过说s 指向的字符串中有多个ASCII 为c 的字符,则找的是第1 个字符.
返回值:找到了返回找到的字符的地址,找不到返回NULL,

char *strrchr(const char *s, int c);

末次匹配
在s 指向的字符串中,找最后一次出现的ASCII 为c 的字符,

返回值;找到了,末次匹配的字符的地址。找不到,返回NULL

#include<stdio.h>
#include<string.h>
#pragma warning(disable:4996)
int main()
{
	char* p = "caicaicai";
	char* q;
	q = strchr(p, 'i');
	if (q == NULL)
	{
		printf("NULL\n");
		return 0;
	}
	printf("p:%p\n", p);
	printf("q:%p\n", q);
	printf("p-str=%d\n", q - p);//差了两个字节
	return 0;
}

strstr

char *strstr(const char *haystack, const char *needle);

在haystack 指向的字符串中查找needle 指向的字符串,也是首次匹配

返回值:找到了返回找到的字符的地址,找不到返回NULL,

#include <string.h>
#include <stdio.h>
int main()
{
	char str1[30] = "jfsdjklsd43$#$53jklj$#$4t5";
	char str2[20] = "$#$";
	char* result;
	result =(char *) strstr(str1, str2);
	printf("%s\n", result);
	printf("%p\n", result);
	printf("%p\n", str1);
	printf("%d\n", result - str1);
	return 0;
}

memset

void* memset(void *ptr,int value,size_t num);

memset 函数是将ptr 指向的内存空间的num 个字节全部赋值为value

ptr:指向任意类型的指针,即指向我们需要修改的内存
value:给ptr 指向的内存空间的赋的值。
num:确定将ptr 所指的内存中的num 个字节全都用value 代替

返回值;目的内存的首地址,即ptr 的值

#include <string.h>
#include <stdio.h>
#pragma warning(disable:4996)
int main()
{
	char result[] = "hello a shu";//char *result指向的字符串保存在字符常量区是不可被修改的
	printf("%s\n", result);
	memset(result, 'c', 6);
	printf("%s\n", result);
	return 0;
}

字符串转数值

atoi/atol/atof //字符串转换功能

int atoi(const char *nptr);

将nptr 指向的字符串转换成整数,返回

转换后的整数,此值由将输入字符作为数字解析而生成。如果该输入无法转换为该类型的值,则atoi
的返回值为0

long atol(const char *nptr);
double atof(const char *nptr);
#include <string.h>
#include <stdio.h>
#pragma warning(disable:4996)
int main()
{
	char result[] = "1234";
	int num,num1;
	num = atoi(result);
	num1 = atoi("qwer");
	printf("%d\n", num);
	printf("%d\n", num1);
	return 0;
}

strtok

char *strtok(char *str, const char *delim);

字符串切割,按照delim 指向的字符串中的字符,切割str 指向的字符串。其实就是在str 指向的字符串中发现了delim 字符串中的字符,就将其变成’\0’,调用一次strtok 只切割一次,切割一次之后,再去切割的时候strtok 的第一个参数传NULL,意思是接着上次切割的位置继续切。

如果str 字符串中出现了连续的几个delim 中的字符,则只将第一个字符变成’\0’

#include<string.h>
#include<stdio.h>
#pragma warning(disable:4996)
int main()
{
	char str[100] = "hello,,,a;;;shu";
	char* p= ",;";
	char* q[10];
	q[0] = strtok(str, p);
	printf("%s",q[0]);
	int i = 0, j;
	while (q[i] != NULL)   //切割完毕,回传NULL 
	{
		i++;
		q[i] = strtok(NULL, p);  //从上一次切割的位置继续切,,,,a将第一个,变成\0,下一次切割的时候,跳过,,从a开始切割。
	}
	for (j = 0; j < i; j++)
	{
		printf("q[%d]: %s\n", j, q[j]);
	}
	printf("%s\n", q[0]+6);//只将第一个字符变成’\0’,
	return 0;
}

sprintf与sscanf

int sprintf(char *buf, const char *format, …);

输出到buf 指定的内存区域

int sscanf(const char *buf,const char *format, …);

从buf 指定的内存区域中读入信息

#include<string.h>
#include<stdio.h>
#pragma warning(disable:4996)
int main()
{
	char p[100];
	sprintf(p,"%s;%d;%d","hello", 23, 34);
	printf("%s\n",p);
	int a, b, c;
	sscanf("2022:8:18", "%d:%d:%d",&a,&b,&c);
	printf("a:%d\n",a);
	printf("b:%d\n", b);
	printf("c:%d\n", c);
	return 0;
}

sscanf跳过数据:%*s 或%*d

#include<string.h>
#include<stdio.h>
#pragma warning(disable:4996)
int main()
{
	char buf[100];
	sscanf("hello world", "%*s %s", buf);//跳过hello ,然后隔一个空格获取字符串
	printf("%s\n", buf);
	return 0;
}

读指定宽度的数据:%[width]s

#include<string.h>
#include<stdio.h>
#pragma warning(disable:4996)
int main()
{
	char buf[100];
	sscanf("hello world", "%5s", buf);//从字符串中获取字符串,只要5个字节,存放在buf 中
	printf("%s\n", buf);
	return 0;
}

支持集合操作:只支持获取字符串

#include<stdio.h>
#pragma warning(disable:4996)
int main()
{
	char buf[100];
	sscanf("qweqewr123qwer123asf", "%[a-z]", buf);//从字符串中获取输入只要’a’和’z’之间的字符碰到不
	在范围内的,就终止了
		printf("%s\n", buf);//结果为qweqewr
}
%[aBc] 匹配a、B、c 中一员,贪婪性,碰到除了aBc就停止
%[^aFc] 匹配非a Fc 的任意字符,贪婪性,碰到aFc就停止
%[^a-z]表示读取除a-z 以外的所有字符
获取# @号之间的字符串abc#def@ghi

#include<stdio.h>
#pragma warning(disable:4996)
int main()
{
	char buf[20];
	sscanf("asdf#sdjd@djfkd", "%*[^#]%*[#]%[^@]", buf);//跳过非#的字符,跳过#,直到@
	printf("%s\n", buf);
}

const

修饰普通变量,代表只读的意思

const int a=100;//定义了一个只读变量a 值为100,后面就不能再给a 赋值了

const 修饰指针

const char *str意思是str 指向的内存的内容不能通过str 来修改,用来保护str 指向的内存的内容,但是str 的指向是可以改变的。

char * const str意思是str 是只读的变量,str 不能指向别的地方,但是str 指向的内存的内容,是有可能可以修改的。

const char * const strstr 不能指向别的地方,指向的内存的内容也不能通过str 去修改

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

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值