动态申请函数
malloc、free、calloc、realloc
malloc 申请内存
free 释放空间
野指针问题防范
#include <stdio.h>
#include <stdlib.h>
// malloc 申请的内存,内存中存放的内容是随机的,不确定的;
// 而calloc函数申请的内存中的内容为0
char *fun()
{
// char ch[100] = "hello world";
// 静态全局区的空间只要开辟好,除非程序结束否则不会释放
// static char ch[100] = "hello world";
// 堆区开辟空间,手动申请手动释放,更加灵活
char *str = (char *)malloc(100 * sizeof(char));
str[0] = 'h';
str[1] = 'e';
str[2] = 'l';
str[3] = 'l';
str[4] = 'o';
str[5] = '\0';
// return ch;
return str;
}
int main(int argc, char *argv[])
{
char *p;
p = fun();
printf("p = %s\n",p); // p = hello
// 使用free函数释放空间
free(p);
// 防止野指针
p = NULL;
return 0;
}
realloc重新申请内存堆空间
#include <stdio.h>
#include <stdlib.h>
void test1()
{
char *p;
p = (char *) malloc(100);
printf("%p\n",p);
// 在100个字节后面追加50个字节
p = (char *)realloc(p,150); // p指向的内存的新的大小为150个字节
printf("%p\n",p);
}
void test2()
{
char *p;
p = (char *)malloc(100);
printf("%p\n",p);
// 想重新申请内存,新的大小为50个字节
// p指向的内存的新的大小为50个字节,100个字节的后50个字节的存储空间就被释放
p = (char*)realloc(p,50);
printf("%p\n",p);
}
int main(int argc, char *argv[])
{
test1();
test2();
return 0;
}
内存泄露
申请的内存,首地址丢了,找不到了,再也没法使用了,也没法释放了,这块内存就被泄露了。
#include <stdio.h>
int main()
{
char *p;
p = (char *)malloc(100);
// 接下来就可以使用p指向的内存了
p = "hello world"; // p指向别的地方了,保存字符串常量的首地址
// 从此再也找不到你申请的100个字节了。则动态申请的100个字节就被泄露了
return 0;
}
#include <stdio.h>
void fun()
{
char *p;
p = (char*)malloc(100);
// 接下来 可以用p指向的内存了
// ...
// free(p); // 这是解决内存泄露的方法
}
int main()
{
// 每调用一次 fun 泄露100个字节 因为fun函数没释放内存,也没返回内存地址,找不到这块堆区空间
fun();
fun();
return 0;
}
字符串处理函数
- 获取字符串长度函数
#include <stdio.h>
#include <string.h>
int main()
{
// 使用strlen函数获取字符串的长度
// strlen获取的字符串的长度遇到第一个\0结束
char s1[100] = "hel\0lo";
printf("s1_len = %d\n", strlen(s1)); // s1_len = 3
printf("si_size = %d\n", sizeof(s1)); // si_size = 100
char *s2 = "hello";
printf("s2_len = %d\n", strlen(s2)); // s2_len = 5
printf("s2_size = %d\n", sizeof(s2)); // s2_size = 4 32位系统里,不管指针变量是什么类型,都是占4个字节。
return 0;
}
- 字符串拷贝、追加、比较、查找、匹配函数
字符串拷贝
#include <stdio.h>
#include <string.h>
int main()
{
// 使用strcpy函数拷贝字符串
char s1[32] = "hello world";
char s2[32] = "abcdefg";
char *a;
a = strcpy(s1,s2); // 将s2字符串内容拷贝到s1 函数的返回值是目的内存的地址
// 注意:使用strcpy函数的时候 需要确保s1的内存空间大于等于s2的 否则会出现内存污染
printf("%s\n",a); // abcdefg
printf("s1 = %s\n", s1); // s1 = abcdefg
int i;
for(i=0;i < 32; i++)
{
printf("[%c] - %d\n", s1[i], s1[i]); // %c 输出字符 %d 输出字符的ascii值
// [a] - 97
// [b] - 98
// [c] - 99
// [d] - 100
// [e] - 101
// [f] - 102
// [g] - 103
// [
追加
#include <stdio.h>
#include <string.h>
int main()
{
// 使用strcat函数追加字符串
char s1[32] = "hello world";
char s2[32] = "abcdef";
// strcat是从s1的\0的位置开始追加,直到s2的第一个\0复制完毕后结束
strcat(s1, s2);
printf("s1 = %s\n", s1); // s1 = hello worldabcdef
return 0;
}
比较字符串内容是否一致
#include <stdio.h>
#include <string.h>
int main()
{
// 使用strcmp函数比较两个字符串的内容是否一致
// strcmp函数是逐个字符进行ascii值的比较, 返回值为1 说明s1>s2, 返回值为-1 说明s1<s2
char s1[] = "aell";
char s2[] = "g";
int ret = strcmp(s1, s2);
printf("%d\n", ret);
// 使用strncmp函数比较两个字符串的前n个字符内容是否一致
char s3[] = "hello";
char s4[] = "hella";
int ret1 = strncmp(s3, s4, 4); // 比较前4个字符 等于0说明是一致的
printf("%d\n", ret1);
return 0;
}
查找字符在字符串中的位置 查不到返回NULL
#include <stdio.h>
#include <string.h>
int main()
{
// 使用strchr函数在一个字符串中查找字符 从左边开始的找第一个匹配字符
char s[] = "hel6lo wor6ld";
// char *ret = strchr(s, '6'); // 这里使用字符或者ASCII码值都行
char *ret = strchr(s, 54);
if(ret == NULL)
{
printf("not found\n");
}
else {
printf("in %d\n", ret -s);
}
// 使用strrchr函数在一个字符串中查找字符 从右边开始的找第一个匹配字符
return 0;
}
字符串匹配函数 使用strstr函数在一个字符串中查找另一个字符串
#include <stdio.h>
#include <string.h>
int main()
{
// 字符串匹配函数 使用strstr函数在一个字符串中查找另一个字符串
char s[] = "1234:4567:666:789:666:7777";
// strstr查找的时候 查找的是第二个参数的第一个\0之前的内容 不包含第二个参数的\0
char *ret = strstr(s, "666");
printf("%p\n", s); // 0060FE81
printf("%p\n", ret); // 0060FE8B
printf("%d\n",ret - s); // 10
return 0;
}
- 字符串转换数值
使用atoi将数字型字符串转化为整形数据
#include <stdio.h>
#include <stdlib.h>
int main()
{
// 使用atoi将数字型字符串转化为整形数据
char s1[] = "7856";
int ret1 = atoi(s1);
printf("ret1 = %d\n", ret1); // ret1 = 7856
// 使用atof将浮点型的字符串转化为浮点型数据
char s2[] = "3.1415926";
double ret2 = atof(s2);
printf("ret2 = %lf\n", ret2); // ret2 = 3.141593
return 0;
}
- 字符串切割函数
#include <stdio.h>
#include <string.h>
int main()
{
// 使用strtok函数切割字符串
char s[] = "111:2222:3333333:44444:55555555555";
// char *s = "111:2222:3333333:44444:55555555555"; // 这里不能用char* 因为char *定义的字符串存储在字符常量区
char *ret;
// 第一次切割
ret = strtok(s, ":");
printf("ret = %s\n", ret); // ret = 111
// 后面所有的切割都要将strtok的第一个参数传NULL
while ( ( ret = strtok(NULL, ":") ) != NULL ) {
printf("ret00 = %s\n", ret);
}
// ret00 = 2222
// ret00 = 3333333
// ret00 = 44444
// ret00 = 55555555555
return 0;
}
- 格式化字符串操作函数
#include <stdio.h>
// sprintf和sscanf的基本用法
void test1()
{
char buf[20];
int a, b, c;
sprintf(buf, "%d:%d:%d", 2023, 10, 1);
printf("buf= %s\n", buf); // buf= 2023:10:1
sscanf("2023:10:1", "%d:%d:%d", &a, &b, &c);
printf("a=%d, b=%d, c=%d\n", a, b, c); // a=2023, b=10, c=1
}
// sscanf高级用法
void test2()
{
// 1、跳过数据:%*s 或者 %*d
char buf1[20];
sscanf("1234 5678", "%*d %s", buf1);
printf("%s\n", buf1); // 5678
// 2、读指定宽度的数据:%[width]s
char buf2[20];
sscanf("12345678", "%4s ", buf2);
printf("%s\n", buf2); // 1234
// 3、支持集合操作:只支持获取字符串
// %[a-z] 表示匹配a到z中任意字符(尽可能多的匹配)
// %[aBc] 匹配a、B、c中一员,贪婪性
// %[^aFc] 匹配非a、F、c的任意字符,贪婪性
// %[^a-z] 表示读取除a-z以外的所有字符
char buf3[20];
sscanf("agcd32DajfDdFF", "%[a-z]", buf3);
printf("%s\n", buf3); // agcd
}
int main()
{
test1();
test2();
return 0;
}
const
修饰普通变量 代表只读的意思
#include <stdio.h>
// const 修饰全局变量
// 此时全局变量只能使用但是不能修改
// 如果直接拿全局变量修改值,编译直接报错
// 如果使用全局变量的地址去修改值,运行时程序异常结束
const int a = 100;
void tes1()
{
printf("a = %d\n", a); // a = 100
// a = 666;
// printf("a = %d\n", a);
// int *p = &a;
// *p = 888;
// printf("a = %d\n", a);
}
// const修饰普通局部变量
// 可以读取变量的值
// 不能直接通过变量进行修改值,编译报错
// 可以通过变量的地址修改值
void test2()
{
const int b = 100;
printf("b = %d\n", b); // b = 100
// b = 666;
// printf("b = %d\n", b);
int *p = &b;
*p = 888;
printf("b = %d\n", b); // b = 888
}
// const修饰指针变量
// 1、如果const修饰指针变量的类型,无法通过指针变量修改地址里面的值
void test3()
{
int c = 100;
const int *p = &c;
printf("*p = %d\n", *p); // *p = 100
c = 666;
printf("*p = %d\n", *p); // *p = 666
// *p = 777;
// printf("*p = %d\n", *p);
int d = 888;
p = &d;
printf("*p = %d\n", *p); // *p = 888
}
// 2、如果const修饰指针变量,无法修改指针变量保存的地址
void test4()
{
int c = 100;
int * const p = &c;
printf("*p = %d\n", *p); // *p = 100
c = 666;
printf("*p = %d\n", *p); // *p = 666
*p = 777;
printf("*p = %d\n", *p); // *p = 777
int d = 888;
// p = &d;
// printf("*p = %d\n", *p);
}
int main()
{
tes1();
test2();
test3();
test4();
return 0;
}