通过字符串逆序学习二级指针的三种内存模型
####################################################
#####################################################
#######################################################
########################################
第一种内存模型:
- #define _CRT_SECURE_NO_WARNINGS
- #include <stdio.h>
- #include <stdlib.h>
- #include <string.h>
- //与void print_str(char* arr[],int n)等价
- void print_str1(char** arr,int n){
- int i=0;
- for(i=0;i<n;i++){
- printf("%s ",arr[i]);
- }
- }
- void sort_str1(char** arr,int n){
- int i,j;
- char* t=NULL;
- for(i=0;i<n-1;i++){
- for(j=i;j<n;j++){
- if(strcmp(arr[i],arr[j])>0){ //交换的是数组元素的值,也就是交换指针的指向
- t=arr[i];
- arr[i]=arr[j];
- arr[j]=t;
- }
- }
- }
- }
- int main()
- {
- char* arr[]={"aaaaa","ddd","cccc","bbbb","bdkfjsl"};
- int n=sizeof(arr)/sizeof(arr[0]);
- int i=0;
- print_str1(arr,n);
- puts("###################");
- sort_str1(arr,n);
- print_str1(arr,n);
- puts("#####################");
- return 0;
- }
########################################################
##########################################################
########################################################
##########################################################
第二种内存模型
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//与void print_arr(char [][10],int n)
void print_arr(char (*arr)[10],int n){
int i;
for(i=0;i<n;i++){
printf("%s ",*(arr+i));
}
}
void sort_arr(char (*arr)[10],int n){
int i,j;
char t[10];
for(i=0;i<n-1;i++){
for(j=i;j<n;j++){
if(strcmp(*(arr+i),*(arr+j))>0){
strcpy(t,*(arr+i));
strcpy(*(arr+i),*(arr+j));
strcpy(*(arr+j),t);
}
}
}
}
int main()
{
char arr[3][10]={"sdfsdf","adgsd","nfdfs"};
print_arr(arr,3);
sort_arr(arr,3);
puts("#####################");
print_arr(arr,3);
puts("#####################");
return 0;
}
####################################################
####################################################
######################################################
#######################################################
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char **getMem(int num)
{
char ** p2 = NULL;
int i = 0;
p2 = (char**)malloc(sizeof(char*)*num);//malloc的结果作为一个数组名赋值给其他变量,类型转换时转换为数组名对应的类型
//如果把malloc的内存空间看做一个数组,里面的元素类型就是sizeof的参数类型,其结果就是比数组元素多一级的指针。
if(p2 == NULL)
return NULL;
for(i= 0;i<num;i++){
p2[i] = (char*)malloc(100);
if(NULL == p2[i])
return NULL;
sprintf(p2[i],"%d%d%d",i+1,i+1,i+1);
}
return p2;
}
/*要避免二级指针成为野指针,在被调函数里释放内存的时候就需要使用三级指针*/
int freeMem(char *** p,int num)
{
int i = 0;
if(p == NULL)
return -3;
for(i = 0;i < num;i++){
//printf("%d:%d\n",i+1,(int)(*p)[i]);
if((*p)[i] != NULL){//先根据指针变量自身的地址使用间接访问操作得到指针的实际指向,再使用下标操作得到具体元素
free((*p)[i]);
(*p)[i] = NULL;
//printf("%d:%d\n",i+1,(int)(*p)[i]);
}
else
return -1;
}
if((*p)!= NULL){//先分配的内存后释放
//printf("P:%d\n",(int)(*p));
free((*p));
(*p) = NULL;
//printf("P:%d\n",(int)(*p));
}
else
return -2;
return 0;
}
int sortArray3(char ** array,int num)
{
int i = 0,j=0;
char *tmp = NULL;
if(array == NULL)
return -1;
for(i=0;i<num;i++){
for(j=i+1;j<num;j++){
if(strcmp(array[i],array[j]) < 0){//交换的是数组元素的值,也就是交换指针的指向
tmp = array[i];
array[i] = array[j];
array[j] = tmp;
}
}
}
return 0;
}
void printfArray3(char **array,int num)
{
int i = 0;
if(array == NULL)
return;
for(i=0;i< num;i++){
printf("%s\n",*(array+i));//可见自己在堆空间申请一个指针数组,
//再给指针数组的每个元素单独赋值的模型和第一种模型的指针步长一样
}
}
int main(void)
{
//自己在堆空间分配内存
int num = 5;
char ** strArray = getMem(num);
printf("排序之前\n");
printfArray3(strArray,num);
sortArray3(strArray,num);
printf("排序之后\n");
printfArray3(strArray,num);
//printf("str:%d\n",(int)strArray);
freeMem(&strArray,num);
//printf("str:%d\n",(int)strArray);
printf("Hello World!\n");
return 0;
}
指针:指向一定内存空间,其值得大小等于该空间的地址的一类特殊的变量,系统会为这个指针在临时区开辟固定大小的内存。
二级指针可以看成是存放一级指针变量的地址的变量,二级指针有三种内存模型,以字符型二级指针为例,char *pointer[30]为第一种内存模型,编译器会自动将[]退化为指针,其实质是char **pointer,其用法是char *pointer[30]={"hello","world","how","interesting"};’
char pointer[30][40]为第二种内存模型的表示方法,其用法是char pointer[30][40]={“www”,"aaaa","dfdafd"};高级维数的大小必须限定,这样系统才可以知道指针移动一个单位所移动的内存的大小;char **pointer是第三种内存模型,这种内存空间是开发者自主开辟的空间,也需要开发者来释放,开辟的内存空间在堆上。
下面我讲展现具体的代码来整理二级指针的三种内存模型的关系和使用,此代码实现的功能是将第一种和第二种内存空间里面的数据拷贝到堆空间,即二级指针的第三种内存模型所指代的空间里面,再将内容排序后输出字符串的个数和排序后的第三种内存空间中的内容。
思路:
1)主函数建立三种内存空间模型
2)主调函数分配内存
3)被调函数使用主调函数分配的内存空间,对数据进行排序操作
4)释放内存
具体代码如下:
#define _CRT_SECURE_NO_WARNINGS
#include<stdio.h>
#include<stdlib.h>
#include<string.h>
int getarray(char **p, int num1, char(*p2)[40], int num2, char ***p3, int *num3)
{
//首先判断主调函数传过来的内存是否为空,为空则不能操作
int ret = 0;
char **temp = NULL;
char *temparray = NULL;
int num = 0;
int i = 0;
int j = 0;
if (p == NULL || p2 == NULL || p3 == NULL || num3 == NULL)
{
ret = -1;
printf("func err p==NULL||p2==NULL||p3==NULL||num3==NULL,%d", ret);
return ret;
}
num = num1 + num2;
temp = (char **)malloc(num*sizeof(char *));
if (temp == NULL)
{
ret = -1;
return ret;
}
for (i = 0; i<num1; i++)
{
temp[i] = (char *)malloc(strlen(p[i]) + 1);
if (temp[i] == NULL)
{
printf("invalid");
}
strcpy(temp[i], p[i]);
}
for (j = 0; j<num2; j++, i++)
{
temp[i] = (char *)malloc(strlen(p2[j]) + 1);
if (temp[i] == NULL)
{
printf("invalid");
}
strcpy(temp[i], p2[j]);
}
for (i = 0; i<num; i++)
{
for (j = i + 1; j<num; j++)
{
if (strcmp(temp[i], temp[j])>0)
{
temparray = temp[i];
temp[i] = temp[j];
temp[j] = temparray;
}
}
}
*p3 = temp;
*num3 = num;
return ret;
}
//释放内存
int getArray3_Free2(char ***p3, int p3num)
{
int i;
char **tmp = NULL;
if (p3 == NULL)
{
return -1;
}
tmp = *p3;
for (i = 0; i<p3num; i++)
{
if (tmp[i] != NULL)
{
free(tmp[i]);
}
}
free(tmp);
*p3 = NULL; //通过间接赋值,去间接的修改实参的值,成0
}
void main()
{
//建立三种内存模型
char *p1[] = { "hello", "world", "my", "god" };
char p2[30][40] = { "www", "sss", "dddfdf" };
char **p3 = NULL;
int rv;
int i, num = 0;
rv = getarray(p1,3, p2, 3, &p3, &num);
if (rv != 0)
{
printf("no valid outputs");
return rv;
}
for (i = 0; i < num; i++)
{
printf("%s\n", p3[i]);
}
getArray3_Free2(&p3, num);
system("pause");
//return 0;
}