详解C语言-二级指针三种内存模型

二级指针相对于一级指针,显得更难,难在于指针和数组的混合,定义不同类型的二级指针,在使用的时候有着很大的区别

第一种内存模型char *arr[]

若有如下定义

char *arr[] = {"abc", "def", "ghi"};

这种模型为二级指针的第一种内存模型,在理解的时候应该这样理解:定义了一个指针数组(char * []),数组的每个元素都是一个地址。
在使用的时候,若要使用中间量操作元素,那么此时中间量应该定义为

char *tmp = NULL;

如果要打印这个数组,那么可以使用以下函数

int printAarray(char **pArray, int num)
{
	int i = 0;
	if (pArray == NULL)
	{
		return -1;
	}
	for (i = 0; i < num; i++)
	{
		printf("%s \n", pArray[i]);
	}
	return 0;
}

第二种内存模型char arr[][]

若有如下定义

char arr[3][5] = {"abc", "def", "ghi"};

这种模型为二级指针的第二种内存模型,在理解的时候应该这样理解:定义了一个二维数组,有3个(5个char)空间的存储变量。

在使用的时候,若要使用中间量操作元素,那么此时中间量应该定义为

char tmp[5] = { 0 };

如果要打印这个数组,那么可以使用以下函数

nt printAarray(char pArray[][5], int num)
{
	int i = 0;
	if (pArray == NULL)
	{
		return -1;
	}
	for (i = 0; i < num; i++)
	{
		printf("%s \n", pArray[i]);
	}
	return 0;
}

第三种内存模型char **arr

若有如下定义

char **arr = (char *)malloc(100 * sizeof(char *));//char arr[400]
arr[0] = (char *)malloc(100 * sizeof(char));//char buf[100]
arr[1] = (char *)malloc(100 * sizeof(char));
arr[2] = (char *)malloc(100 * sizeof(char));
strcpy(arr[0], "abc");
strcpy(arr[1], "def");
strcpy(arr[2], "ghi");
···
for(int i = 0; i < 3; i++)
  if(arr[i] != NULL)
    free(arr[i]);
free(arr);

这种模型为二级指针的第二种内存模型,在理解的时候应该这样理解:定义了一个二级指针,二级指针就是指向指针的指针,其实就是开辟了100个指针空间,存放了100个地址。这种写法是第一种的简化写法

在使用的时候,若要使用中间量操作元素,那么此时中间量应该定义为

char *tmp = NULL

如果要打印这个数组,那么可以使用以下函数

{
	int i = 0;
	if (pArray == NULL)
	{
		return -1;
	}
	for (i = 0; i < num; i++)
	{
		printf("%s \n", pArray[i]);
	}
	return 0;
}

例子

把第一种内存模型的数据排序,运算结果放到第三种内存模型中

#include "stdio.h"
#include "string.h"
#include "stdlib.h"

char **SortArrayAndGen3Mem(const char ** const myArray1, int num, char *str, int *myNum)
{
	char **p = NULL;
		p= (char **)malloc(num*sizeof(char *));
	if (myArray1==NULL || str==NULL|| myNum==NULL)
	{
		printf("传入参数错误\n");
		p = NULL;
		goto END;
	}
	*myNum = num;
	for (int i = 0; i < num;i++)
	{
		p[i] = NULL;
		p[i] = (char)malloc(50 * sizeof(char));
		memset(p[i], 0, sizeof(p[i]));
		if (p[i]==NULL)
		{
			printf("内存分配错误!\n");
			goto END;
		}
		strcpy(p[i], myArray1[i]);
	}
	char *tmp;
	for (int i = 0; i < num; i++)
	{
		for (int j = i + 1; j < num; j++)
		{
			if (strcmp(p[i],p[j])>0)
			{
				char *tmp = p[i];
				p[i] = p[j];
				p[j] = tmp;
			}
		}
	}
	for (int i = 0; i < num; i++)
	{
		printf("%s \n", myArray1[i]);
	}

END:
	return p;
}

//释放内存函数

void main()
{
	int i = 0;
	char **myArray3 = NULL;
	int num3 = 0;
	//第一种内存模型
	char *myArray[] = {"bbbbb", "aaaaa", "cccccc"};
	char *myp = "111111111111";

	myArray3 = SortArrayAndGen3Mem(myArray, 3, myp, &num3);

	for (i=0; i<num3; i++)
	{
		printf("%s \n", myArray3[i]);
	}

	system("pause");
}
#include "stdio.h"
#include "stdlib.h"
#include "string.h"

char **SortArrayAndGet3Mem(const char* const myArray1,int num,char *str,int *myNum);
int getArray(char ***newp,int num) ;
int freeArray(char ***newpfree,int num);
int sortTArray(char *p, int num);

void main()
{
	char **myArray3=NULL;
	int num3=0;
	char *myArray[]={"bbbb","aaa","cccc"};
	char *myp="111111111";
	myArray3=SortArrayAndGet3Mem(myArray,3,myp,&num3);
	system("pause");
}

char **SortArrayAndGet3Mem(const char** const myArray1,int num,char *str,int *myNum)
{
	int ret=0;
	char **p=NULL;
	int i=0;
	char **p1=NULL;
	p1=(char **)myArray1;
	ret=getArray(&p,num +1);
	for (i=0;i<num;i++)
	{
		strcpy(p[i],p1[i]);
	}
	strcpy(p[i], str);
	ret=sortTArray(p,num +1);
	for (i=0;i<num +1;i++)
	{
		printf("%s\n",p[i]);
	}
	ret=freeArray(&p,num +1);
	*myNum = num +1;
	return p;
}

int getArray(char ***newp,int num)
{
	int i=0;
	int ret=0;
	char **tmp = NULL;
	tmp = (char **)malloc(num*sizeof(char *));
	for (i=0;i<num;i++)
	{
		tmp[i]=(char*)malloc(sizeof(char)*100);
	}
	*newp = tmp; //
	return 0;
}

//
int freeArray(char ***newpfree,int num)
{
	char **p=NULL;
	int i=0;
	int ret=0;
	p=*newpfree;
	for (i=0;i<num;i++)
	{
		free(p[i]);
	}
	free(p);
	*newpfree = NULL; //
	return ret;
}

//int sortTArray(char ***Arraystr, int num)
int sortTArray(char **Arraystr, int num)
{
	int i , j = 0;
	for (i=0; i<num; i++)
	{
		for (j=i+1; j<num; j++)
		{
			if (strcmp((Arraystr)[i],(Arraystr)[j])>0)
			{
				char tmp[100];
				strcpy(tmp,(Arraystr)[i]);
				strcpy((Arraystr)[i],(Arraystr)[j]);
				strcpy((Arraystr)[j],tmp);
			}
		}
	}
	for (i=0;i<num;i++)
	{
		printf("%s\n",(Arraystr)[i]);
	}
	return 0;
}

以上就是详解C语言-二级指针三种内存模型的详细内容,更多关于C语言-二级指针三种内存模型的资料请关注我们其它相关文章!

(0)

相关推荐

  • iOS通过逆向理解Block的内存模型

    前言 正常情况下,通过分析界面以及 class-dump 出来头文件就能对某个功能的实现猜个八九不离十.但是 Block 这种特殊的类型在头文件中是看不出它的声明的,一些有 Block 回调的方法名 dump 出来是类似这样的: - (void)FM_GetSubscribeList:(long long)arg1 pageSize:(long long)arg2 callBack:(CDUnknownBlockType)arg3; 因为这种回调看不到它的方法签名,我们无法知道这个 Block

  • javascript 内存模型实例详解

    本文实例讲述了javascript 内存模型.分享给大家供大家参考,具体如下: 我对于 JavaScript 的内存模型一直都比较困惑,很想了解在操作变量的时候,JS 是如何工作的.如果你和我有同样的困惑,希望这篇文章能给你一些启发. 译文,喜欢原文的可以直接拉到底部 当我们声明变量.初始化变量.更改变量值的时候,到底会发生什么?JavaScript 是如何实现这些基本的功能?最重要的是,我们如何才能理解这些基础知识? 本文将覆盖以下 4 个方面: JavaScript 原始数据类型的变量声明和

  • Java8内存模型PermGen Metaspace实例解析

    一.JVM 内存模型 根据 JVM 规范,JVM 内存共分为虚拟机栈.堆.方法区.程序计数器.本地方法栈五个部分. 1.虚拟机栈:每个线程有一个私有的栈,随着线程的创建而创建.栈里面存着的是一种叫"栈帧"的东西,每个方法会创建一个栈帧,栈帧中存放了局部变量表(基本数据类型和对象引用).操作数栈.方法出口等信息.栈的大小可以固定也可以动态扩展.当栈调用深度大于JVM所允许的范围,会抛出StackOverflowError的错误,不过这个深度范围不是一个恒定的值,我们通过下面这段程序可以测

  • 详解C语言中的内存四区模型及结构体对内存的使用

    内存四区 1.代码区 代码区code,程序被操作系统加载到内存的时候,所有的可执行代码都加载到代码区,也叫代码段,这块内存是不可以在运行期间修改的. 2.静态区 所有的全局变量以及程序中的静态变量都存储到静态区. 3.栈区 栈stack是一种先进后出的内存结构,所有的自动变量,函数的形参都是由编译器自动放出栈中,当一个自动变量超出其作用域时,自动从栈中弹出.对于自动变量,什么时候入栈,什么时候出栈,是不需要程序控制的,由C语言编译器.实现栈不会很大,一般都是以K为单位的. 当栈空间以满,但还往栈

  • 详解C语言-二级指针三种内存模型

    二级指针相对于一级指针,显得更难,难在于指针和数组的混合,定义不同类型的二级指针,在使用的时候有着很大的区别 第一种内存模型char *arr[] 若有如下定义 char *arr[] = {"abc", "def", "ghi"}; 这种模型为二级指针的第一种内存模型,在理解的时候应该这样理解:定义了一个指针数组(char * []),数组的每个元素都是一个地址. 在使用的时候,若要使用中间量操作元素,那么此时中间量应该定义为 char *tm

  • 详解vue 模版组件的三种用法

    本文介绍了详解vue 模版组件的三种用法,分享给大家,具体如下: 第一种 //首先,别忘了引入vue.js <div id="user_name_01"></div> <script src="../node_modules/vue/dist/vue.js"></script> <script> var User_01 = Vue.extend({// 创建可复用的构造器 template: '<p&

  • 详解Android 检测权限的三种写法

    本文介绍了详解Android 检测权限的三种写法,小编觉得挺不错的,现在分享给大家,也给大家做个参考.一起跟随小编过来看看吧 权限检测生效条件: targetSdkVersion 以及 compileSdkVersion 升级到 23 及以上 运行 Android 系统 6.0 及以上 三种检测权限写法: public static boolean checkPermission1(Context context, String[] permissions) { PackageManager p

  • 详解Python 实现 ZeroMQ 的三种基本工作模式

    简介 引用官方说法:ZMQ(以下 ZeroMQ 简称 ZMQ)是一个简单好用的传输层,像框架一样的一个 socket library,他使得 Socket 编程更加简单.简洁和性能更高. 是一个消息处理队列库,可在多个线程.内核和主机盒之间弹性伸缩. ZMQ 的明确目标是"成为标准网络协议栈的一部分,之后进入 Linux 内核".现在还未看到它们的成功.但是,它无疑是极具前景的.并且是人们更加需要的"传统" BSD 套接字之上的一 层封装.ZMQ 让编写高性能网络应

  • 详解python安装matplotlib库三种失败情况

    (可能只有最后一句命令有用,可能全篇都没用) (小白方法,可能只适用于本人情况) 安装matplotlib时,出现的三种失败情况 1.read timed out 一开始我在pycharm终端使用pip install matplotlib时,出现的是下图所示情况,大致情况是安装时间太长,所以当时我用了清华镜像,将原来的命令改成了pip install -i https://mirrors.ustc.edu.cn/pypi/web/simple/ matplotlib,速度是上来了,但是还是安装

  • 详解Springboot下载Excel的三种方式

    汇总一下浏览器下载和代码本地下载实现的3种方式. (其实一般都是在代码生成excel,然后上传到oss,然后传链接给前台,但是我好像没有实现过直接点击就能在浏览器下载的功能,所以这次一起汇总一下3种实现方式.)

  • 详解SpringBoot禁用Swagger的三种方式

    目录 摘要 方法 禁用方法1: 禁用方法2: 禁用方法3: 摘要 在生产环境下,我们需要关闭swagger配置,避免暴露接口的这种危险行为. 方法 禁用方法1: 使用注解 @Value() 推荐使用 package com.dc.config; import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty; import org.springframework.context.annotation.Be

  • 详解Spring获取配置的三种方式

    目录 前言 Spring中获取配置的三种方式 通过@Value动态获取单个配置 通过@ConfigurationProperties+前缀方式批量获取 通过Environment动态获取单个配置 总结 前言 最近在写框架时遇到需要根据特定配置(可能不存在)加载 bean 的需求,所以就学习了下 Spring 中如何获取配置的几种方式. Spring 中获取配置的三种方式 通过 @Value 方式动态获取单个配置 通过 @ConfigurationProperties + 前缀方式批量获取配置 通

  • 详解mysql数据去重的三种方式

    目录 一.背景 二.数据去重三种方法使用 1.​通过MySQL DISTINCT:去重(过滤重复数据) 2.group by 3.row_number窗口函数 三.总结 一.背景 最近在和系统模块做数据联调,其中有一个需求是将两个角色下的相关数据​对比后将最新的数据返回出去,于是就想到了去重,再次做一个总结. 二.数据去重三种方法使用 1.​通过MySQL DISTINCT:去重(过滤重复数据) ​ 1.1.在使用 mysql SELECT 语句查询数据的时候返回的是所有匹配的行. SELECT

  • 详解Spring依赖注入的三种方式以及优缺点

    目录 0.概述 1.属性注入 1.1 优点分析 1.2 缺点分析 2.Setter 注入 优缺点分析 3.构造方法注入 优点分析 总结 0.概述 在 Spring 中实现依赖注入的常见方式有以下 3 种: 属性注入(Field Injection): Setter 注入(Setter Injection): 构造方法注入(Constructor Injection). 它们的具体使用和优缺点分析如下. 1.属性注入 属性注入是我们最熟悉,也是日常开发中使用最多的一种注入方式,它的实现代码如下:

随机推荐