1.一级指针的典型用法
数组int a[10];
字符串
1.c语言中以0结尾的字符串
2.在c语言中没有字符串类型,通过字符数组来模拟字符串。
3.字符串的内存分配 堆上,栈上,全局区
C语言字符数组的初始化:
1.指定长度 char buf[100]={'a','b','c','d'} 初始化一个100个字符的字符串其中buf[4]--buf[99]为0;
2.不指定长度 char buf1[] = {'a','b','c','d'} buf1是一个数组,但是不是一个以0结尾的字符串。
3.使用字符串初始化 char buf3[] = “abcd”; buf3作为数组的话是5个字节,末尾有个\0;如果作为字符串的话是4个字节;求字符串长度使用strlen()函数;求数据类型大小使用sizeof();
数组也是一种数据类型的。char buf4[100]=“abcd”;buf4的大小就是100字节;buf4的长度就是4个字节 ;右边是字符串常量在全局区,左边是在栈内存中申请了100字节的内存,等号是将常量字符串烤呗到栈内存中。也就是说右边不能修改,但是这时左边就可以修改了。
通过数组的下标和定义一个指针,把数组的的首地址赋值给指针,指针++,这两种方式都能遍历数组。其实数组的本质也是指针,严格意义上述数组是一个常量指针,不能被赋值。
2.指针做函数参数
int checkstr(char * str1,char* str2){}
上述函数中可以明显的看出传两个地址进去,对内存的操作。
一般情况下需要对这两个指针进行接收,避免指针多次赋值后,再去操作形参指针的时候出问题。
应用场景:快速开发函数工具模型,把c作为工具模型去开发使用,这种思想很重要。
3.两头堵模型
4.字符串翻转
5.递归翻转字符串
重点理解参数入栈模型和函数嵌套返回调用流程
6.一级指针易错的地方
当指针作为参数的时候,判断的是指针变量而不是指针变量所指向的空间是否为NULL。
下表越界 char a[3] ="abc"; 这是错误的,要考虑\0;
不断修改指针变量的值,最终返回的时候或者释放这个指针的时候,要注意啦。
局部内存空间用完free掉了,不能向外抛出这个内存空间的地址,可以molloc一块内存空间去返回。
要注意运算符的优先级;
7.const在c语言中的定义
例如:const int a; 和int const a; 这两个所表达的意思是一样的,a不能被修改。但是如果给a取地址,赋值给一个指针,通过指针可以修改a的值。所以在c语言中const是个冒牌货。
const char* b; 和 char* const b;这两个所表达的意思是不一样的,第一个是修饰指针变量所指向的空间不能被修改,第二个时指针不能被修改。记住指针变量和指针所指向的空间是两个不同的概念。
const char* const b;则表达的意思就是两个都不能被修改。
8.二级指针做输出的模型
做形参输出模型,在函数内部申请内存,通过二级指针形参接受外部函数定义的两个一级指针的取地址,然后将这内存地址赋值给传进来的指针,这样就可以将内部申请的内存传递出去。当内存空间使用完后记得释放,并将指针赋值为NULL。二级指针在释放的时候可以防止野指针。但是一级指针传入一个方法中去使用,完后再函数内部释放掉的话,实参的一级指针就是也指针了。这点希望注意。
9.二级指针做函数参数、做输入的模型
9.1.指针数组:数组本身就是一个指针,指针的的数组就变成了一个二级指针了。
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
void printfarr(char** arr,int a)
{
int i = 0;
for (i = 0; i < a; i++)
{
//printf("%s \n", arr[i]);
printf("%s \n", *(arr + i));
}
}
void paixuarr(char** arr,int a)
{
int i = 0, j = 0;
char* temp = NULL;
for ( i = 0; i < a; i++)
{
for ( j = i; j < a; j++)
{
if (strcmp(arr[i], arr[j])>0)
{
char* temp = arr[i];
arr[i] = arr[j];
arr[j] = temp;
}
}
}
}
void main()
{
int a = 0;
int i = 0;
//二级指针的一种形式,数组本身就是一个指针,指针的的数组就变成了一个二级指针了。
char* arr[] = {"aaaa","bbbb","cccc","dddd"};
a = sizeof(arr) / sizeof(arr[0]);
//打印
printfarr(arr,a);
//排序,升序;
paixuarr(arr,a);
}
2.二维数组也是一个二级指针模型
char str[10][30] = {"aaaa","bbbb","cccc"};
这是一个字符的二维数组,10行30列;
str[0]的sizeof为30;也就是一行的大小。
str+1 就是指针调到第二行了,多维数组的本质
3.malloc申请内存的二级指针模型
char** sarr=NULL;
sarr=(char**)malloc(sizeof(char*)*num);
for (int i= 0; i < num; i++) {
sarr[i] = (char*)malloc(30);
sprintf(sarr[i],"%d%d%d",i+1,i+1,i+1);// 初始化内存空间
}
上面的sarr所指向的就是一个指针数据,所指向的内存空间的数据类型为char*;
sarr[i] 就是sarr所指向的空间所存放的数据地址。
案例如下:基本操作打印、排序、二级指针做函数参数做输入。
#include <stdint.h>
#include <stdio.h>
#include <stdlib.h>
void printfsarr(char** sarr,int num)
{
if(sarr==NULL)
{
return ;
}
//打印
for (int i = 0; i < num; ++i) {
printf("%s\n",sarr[i]);
}
}
void paixuarr(char** sarr,int num)
{
if(sarr==NULL)
{
return ;
}
for (int i = 0; i < num; ++i) {
for (int j = i+1; j < num; ++j) {
if(strcmp(sarr[i],sarr[j])>0)
{
char* temp=sarr[i];
sarr[i]=sarr[j];
sarr[j]=temp;
}
}
}
}
void freesarr(char** sarr ,int num)
{
if(sarr==NULL)
{
return ;
}
for (int i = 0; i < num; ++i) {
if(sarr[i]!=NULL)
{
free(sarr[i]);
sarr[i]=NULL;
}
}
if(sarr!=NULL)
{
free(sarr);
sarr=NULL;
}
}
void main()
{
int num=5;
char** sarr=NULL;
sarr=(char**)malloc(sizeof(char*)*num);
for (int i= 0; i < num; i++) {
sarr[i] = (char*)malloc(30);
sprintf(sarr[i],"%d%d%d",i+1,i+1,i+1);// 初始化内存空间
}
//打印
printfsarr(sarr,num);
//排序 这里只是将指针所指向的内存空间做了调换。也可将内存空间的内容做调换
paixuarr(sarr,num);
//释放内存
freesarr(sarr,num);
}
10.多级指针
一般的使用场景也是多级指针做函数参数,二级指针去地址传入多级指针的函数,然后做输出
注意,传入的多级指针要做判断是否为NULL;
可以这样,不管是几级指针统一理解成,指向一块内存空间,需要判断指向的内存空间是否为NULL就可以了。