不允许向NULL和非法地址拷贝内存
void test(){
char *p = NULL;
//给p指向的内存区域拷贝内容
strcpy(p, "1111"); //error
char *q = 0x1122;
//给q指向的内存区域拷贝内容
strcpy(q, "2222"); //error
}
malloc
后也free
了,但是指针没有置空
→
\rightarrow
→ 相当于没有给指针赋变量地址空指针可以释放
→
\rightarrow
→ 可以多次free
操作
野指针不可以释放
→
\rightarrow
→ 不可以
可以获得结构体某成员的首地址距离当前结构体首地址的偏移量
#include
offsetof(结构体,属性)
输入特性 → \rightarrow → 在主调函数中分配内存,将内存的指针赋给被调函数,可以运行
void fun(char *p)
{
// 给p指向的内存区域拷贝内容
strcpy(p, "abcddsgsd");
}
void test(void)
{
// 输入
// 主调函数分配内存
char buf[100] = { 0 };
fun(buf);
printf("buf = %s\n", buf);
}
malloc
生成的内存输出特性 → \rightarrow → 在被调函数中分配内存,此时主调函数的指针应该比被调函数的形参指针低一级
void fun(char **p, int *len)
{
// 被调函数的形参指针高一级
char *tmp = (char *)malloc(100);
if (tmp == NULL)
{
return;
}
strcpy(tmp, "adlsgjldsk");
// 间接赋值
*p = tmp;
*len = strlen(tmp);
}
void test(void)
{
// 输出
// 被调用函数分配内存,地址传递
char *p = NULL;
int len = 0;
fun(&p, &len);
if (p != NULL)
{
printf("p = %s, len = %d\n", p, len);
}
char str6[] = "hello\012world";
printf("%s\n", str6);
printf("sizeof str6:%d\n", sizeof(str6));
printf("strlen str6:%d\n", strlen(str6));
输出的结果是:
hello
world
12
11
原因:\012
对应ASCII码是换行符,是具有实际意义的字符,因此在显示字符串的时候换行了;字符串长度算他一个。
// 拷贝方法1————采用下标索引的方式
void copy_string01(char* dest, char* source ){
for (int i = 0; source[i] != '\0';i++){
dest[i] = source[i];
}
}
// 拷贝方法2————采用指针解引用的方式
void copy_string02(char* dest, char* source){
while (*source != '\0'){
*dest = *source;
source++;
dest++;
}
}
// 拷贝方法3————采用运算符优先级顺序,本质和拷贝方法2相同
void copy_string03(char* dest, char* source){
//判断*dest是否为0,0则退出循环
while (*dest++ = *source++){}
}
void reverse_string(char* str){
if (str == NULL){
return;
}
int begin = 0;
// 字符串长度减1才是我们的结尾
int end = strlen(str) - 1;
while (begin < end){
//交换两个字符元素
char temp = str[begin];
str[begin] = str[end];
str[end] = temp;
begin++;
end--;
}
}
// 也可以用指针解引用
// while循环的条件是对指针进行比较
void test(){
char str[] = "abcdefghijklmn";
printf("str:%s\n", str);
reverse_string(str);
printf("str:%s\n", str);
}
可以利用sprintf
对字符串进行格式化
sprintf(目标字符串(char数组), "格式",占位参数(不止一个));
calloc
和malloc
一样都是在堆区分配内存
不同点:
calloc
会将分配的内存初始化为0realloc
重新在堆区分配内存realloc
机制:原有空间后序有足够大的空闲空间,那么直接在原有空间后继续开辟内存,返回原有空间的首地址;没有足够大空闲空间,重新分配一个足够大的空间,并且将原有空间的内容拷贝到新空间下,释放原有空间,将新空间的首地址返回将已知的字符串通过格式化匹配出有效信息
贪婪性指的是能匹配到就多匹配一些
贪婪性的具体案例
格式 | 作用 |
---|---|
%*s或%*d | 跳过数据 |
%[width]s | 读指定宽度的数据 |
%[a-z] | 匹配a到z中任意字符(尽可能多的匹配) |
%[aBc] | 匹配a、B、c中一员,贪婪性 |
%[^a] | 匹配非a的任意字符,贪婪性 |
%[^a-z] | 表示读取除a-z以外的所有字符 |
值传递形式调用函数需要拷贝数据,可能会占据更多的内存
通过地址传递,占用的内存更少一些(对于结构体而言)
const
用来修饰函数中的形参,防止误操作,在函数内部再更改形参的数据时,会报错
void test(){
char buf[3] = "abc";
// 没有存'\0'
printf("buf:%s\n",buf);
}
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(p);
// error
}
//被调函数,由参数n确定分配多少个元素内存
void allocate_space(int **arr,int n){
//堆上分配n个int类型元素内存
int *temp = (int *)malloc(sizeof(int)* n);
if (NULL == temp){
return;
}
//给内存初始化值
int *pTemp = temp;
for (int i = 0; i < n;i ++){
//temp[i] = i + 100;
*pTemp = i + 100;
pTemp++;
}
//指针间接赋值
*arr = temp;
}
//打印数组
void print_array(int *arr,int n){
for (int i = 0; i < n;i ++){
printf("%d ",arr[i]);
}
printf("\n");
}
//二级指针输出特性(由被调函数分配内存)
void test(){
int *arr = NULL;
int n = 10;
//给arr指针间接赋值
allocate_space(&arr,n);
//输出arr指向数组的内存
print_array(arr, n);
//释放arr所指向内存空间的值
if (arr != NULL){
free(arr);
arr = NULL;
}
}
//打印数组
void print_array(int **arr,int n){
for (int i = 0; i < n;i ++){
printf("%d ",*(arr[i]));
}
printf("\n");
}
//二级指针输入特性(由主调函数分配内存)
void test(){
int a1 = 10;
int a2 = 20;
int a3 = 30;
int a4 = 40;
int a5 = 50;
int n = 5;
int** arr = (int **)malloc(sizeof(int *) * n);
arr[0] = &a1;
arr[1] = &a2;
arr[2] = &a3;
arr[3] = &a4;
arr[4] = &a5;
print_array(arr,n);
free(arr);
arr = NULL;
}
每左移/右移一位,相当于乘以/除以2的位次方
右移运算符>>将其左侧的操作数的值每位向右移动,移动的位数由其右侧的操作数指定。
丢弃移出左侧操作数有段的位。
对于unsigned类型,使用0填充左端空出的位。
对于有符号类型,结果依赖于机器。空出的位可能用0填充,或者使用符号(最左端)位的副本填充。
一维数组本质并不是一个指针
有两种特殊情况:(1)对数组名称进行sizeof
;(2)对数组名称取地址 ,获取的指针步长是整个数组长度
除了两种特殊情况外,都是指向数组中首元素的地址的指针
指针的指向不可以修改
提高可读性,可写成void test(int arr[])
,退化
typedef int(ARRAY_TYPE)[5];
typedef int(*ARRAY_TYPE)[5];
int(*pArr)[5] = &arr;
sizeof
统计整个二维数组长度;int(*p2)[3][3] = &arr;
;void printArray( int p[][3] , int row, int col)
void printArray(int p[3][3], int row, int col)
// 可读性高
void printArray( int(*p)[3] , int row ,int col)
int (*p)[10];
int * p[10];