深入理解C语言变量和内存
- 格式:docx
- 大小:24.33 KB
- 文档页数:7
深入理解C语言技术的使用原理C语言作为一种广泛应用的编程语言,深入理解其使用原理对于程序员来说至关重要。
本文将从不同角度探讨C语言技术的使用原理,帮助读者更好地掌握和应用这门语言。
一、C语言的基本原理C语言的基本原理是通过编写代码来实现计算机程序的功能。
C语言以其简洁、高效的特点而备受程序员的喜爱。
理解C语言的基本原理,需要掌握其基本语法、数据类型、运算符和控制结构等。
1.基本语法:C语言的基本语法包括变量声明、函数定义、语句和表达式等。
变量声明用于定义变量的类型和名称,函数定义用于定义函数的名称、参数和返回值类型。
语句是一组执行特定任务的代码,而表达式则用于计算值。
2.数据类型:C语言提供了多种数据类型,包括整型、浮点型、字符型和指针等。
不同的数据类型适用于不同的场景,程序员需要根据实际需求选择合适的数据类型。
3.运算符:C语言提供了多种运算符,包括算术运算符、关系运算符、逻辑运算符和位运算符等。
运算符用于执行特定的计算或比较操作,帮助程序员实现复杂的逻辑。
4.控制结构:C语言提供了多种控制结构,包括顺序结构、选择结构和循环结构等。
控制结构用于控制程序的执行流程,实现条件判断和循环操作。
二、C语言的内存管理原理C语言的内存管理是其使用原理中的重要部分。
理解C语言的内存管理原理,有助于程序员优化内存使用,提高程序的性能和稳定性。
1.栈和堆:C语言中的变量可以存储在栈或堆中。
栈是一种后进先出的数据结构,用于存储局部变量和函数调用信息。
堆是一种动态分配的内存区域,用于存储动态分配的变量和数据结构。
2.内存分配和释放:C语言提供了malloc()和free()函数用于动态分配和释放内存。
程序员需要手动管理动态分配的内存,确保及时释放不再使用的内存,以避免内存泄漏和内存溢出等问题。
3.指针和引用:C语言中的指针和引用是内存管理的关键概念。
指针是存储内存地址的变量,可以通过指针访问和修改内存中的数据。
引用是对变量的别名,可以用于简化代码和提高效率。
大一c程序设计基础知识点C程序设计是大一学生学习的一门重要课程,掌握好基础知识点对于进一步学习和应用编程语言至关重要。
本文将介绍大一C 程序设计的基础知识点,帮助读者深入理解和掌握C语言编程。
一、数据类型与变量在C语言中,数据类型是指变量所能存储的数据的类型。
常见的数据类型包括整型、浮点型、字符型和指针型等。
变量用于存储数据,并通过标识符来进行访问和操作。
1. 整型:包括int、short、long和char等,用于存储整数类型的数据。
2. 浮点型:包括float和double等,用于存储浮点数类型的数据。
3. 字符型:用于存储单个字符的数据,采用char类型。
4. 指针型:用于存储变量的地址,采用指针类型。
二、运算符与表达式在C语言中,运算符用于对数据进行运算操作,而表达式则由运算符和操作数组成。
1. 算术运算符:包括加(+)、减(-)、乘(*)、除(/)和取模(%)等,用于完成加减乘除等数学运算。
2. 关系运算符:包括大于(>)、小于(<)、等于(==)、大于等于(>=)、小于等于(<=)和不等于(!=)等,用于比较两个数据之间的大小关系。
3. 逻辑运算符:包括与(&&)、或(||)和非(!)等,用于完成逻辑运算。
4. 赋值运算符:包括赋值(=)、加赋值(+=)、减赋值(-=)、乘赋值(*=)和除赋值(/=)等,用于将值赋给变量。
5. 条件运算符:包括三目运算符(?:),用于根据条件选择不同的值。
三、控制语句与循环结构控制语句和循环结构是C语言程序中常用的结构,用于控制程序的执行流程和决策。
1. 条件语句:包括if语句和switch语句,用于根据条件选择执行不同的语句块。
2. 循环结构:包括for循环、while循环和do-while循环,用于重复执行一段代码块。
四、函数与库函数函数是C语言中的重要概念,用于封装可重复使用的代码块。
库函数是C语言提供的一些常用函数,可直接调用并使用。
c语言实验心得体会在学习C语言的过程中,我参与了多个实验项目,通过实际操作和实验结果的分析,我对C语言的特点、应用和一些常见问题有了更深入的理解和体会。
以下是我对这些实验项目的心得体会:1. 实验项目一:基本语法和数据类型在这个实验中,我学习了C语言的基本语法和数据类型。
通过编写简单的程序,我掌握了变量的定义和使用、常量的使用、运算符的使用以及输入输出函数的应用。
我发现C语言的语法相对简洁明了,易于理解和学习。
同时,我也了解到不同的数据类型在内存中所占用的空间大小以及其取值范围的限制。
2. 实验项目二:控制语句和循环结构在这个实验中,我学习了C语言中的控制语句和循环结构。
通过编写程序,我掌握了条件语句(if-else语句、switch语句)和循环语句(for循环、while循环、do-while循环)的使用。
我发现控制语句和循环结构可以帮助我们实现程序的灵活控制和流程控制,提高程序的效率和可读性。
3. 实验项目三:数组和字符串在这个实验中,我学习了C语言中数组和字符串的使用。
通过编写程序,我掌握了数组的定义和初始化、数组元素的访问和修改、多维数组的使用以及字符串的输入输出和处理。
我发现数组和字符串在实际编程中非常常见,掌握了它们的使用可以提高程序的处理能力和效率。
4. 实验项目四:函数和指针在这个实验中,我学习了C语言中函数和指针的使用。
通过编写程序,我掌握了函数的定义和调用、函数的参数传递和返回值、递归函数的编写以及指针的定义和使用。
我发现函数和指针是C语言中非常重要的概念,掌握了它们可以提高程序的模块化和灵活性。
5. 实验项目五:文件操作在这个实验中,我学习了C语言中的文件操作。
通过编写程序,我掌握了文件的打开和关闭、文件的读写操作以及文件指针的使用。
我发现文件操作在实际应用中非常常见,掌握了文件操作可以实现程序与外部文件的数据交互,提高程序的扩展性和灵活性。
通过这些实验项目,我不仅学会了C语言的基本语法和常用功能,还培养了自己的编程思维和解决问题的能力。
标题:深度解析C语言数据类型缩写及含义在计算机编程的世界中,数据类型是非常重要的概念。
在C语言中,数据类型的缩写及含义更是程序员们必须熟练掌握的知识点之一。
本文将深度解析C语言中常见的数据类型缩写及其含义,帮助读者更深入地理解这一重要主题。
1. 数据类型的概念在C语言中,数据类型用来声明变量的类型,指定变量可以存储的数据类型及所占用的内存大小。
C语言中的数据类型包括基本数据类型和派生数据类型。
基本数据类型包括整型、浮点型、字符型和空类型,而派生数据类型包括数组、指针、结构体和共用体等。
2. 基本数据类型2.1 int:整型在C语言中,int代表整型数据类型,通常用于声明整数变量。
int类型在不同的系统中所占用的内存大小可能会有所不同,但通常情况下,int类型占用4个字节的内存空间。
2.2 float:单精度浮点型float代表单精度浮点型数据类型,用于声明具有小数部分的变量。
float类型通常占用4个字节的内存空间,用于存储小数,精度约为6位有效数字。
2.3 double:双精度浮点型double代表双精度浮点型数据类型,用于声明双精度小数变量。
double类型通常占用8个字节的内存空间,精度约为15位有效数字。
2.4 char:字符类型char代表字符数据类型,用于存储单个字符的变量。
char类型通常占用1个字节的内存空间。
2.5 void:空类型void代表空类型,用于表示没有类型。
通常用于函数的返回值或指针的类型。
以上是C语言中常见的基本数据类型的缩写及含义。
掌握这些基本数据类型对于程序员来说非常重要,它们是构建任何C语言程序的基础。
3. 派生数据类型3.1 数组:一组相同数据类型的集合数组是C语言中一组相同数据类型的集合,可以存储固定大小的元素。
3.2 指针:存储变量位置区域的变量指针是C语言中非常重要的概念,它用来存储变量的内存位置区域。
指针可以指向任何数据类型的变量,它可以极大地提高程序的灵活性和效率。
学习C语言的必备知识点C语言是一门广泛应用于软件开发和系统编程的高级编程语言。
学习C语言需要掌握一些必备的知识点,才能更好地理解和应用该语言。
本文将介绍C语言学习的必备知识点,帮助读者系统地学习和掌握C语言。
一、数据类型C语言提供了多种数据类型,包括整型、浮点型、字符型和指针等。
了解不同数据类型的特点和使用方法是学习C语言的基础。
教材中会对这些数据类型进行详细的讲解和示例,并提供相应的练习题供学生练习。
二、变量与常量在C语言中,变量用于存储和表示数据,而常量则是不可改变的数据。
学习C语言需要了解如何声明和定义变量,以及如何使用常量。
这些知识点通常包括变量的命名规则、作用域、声明方式和初始化等。
三、运算符C语言提供了丰富的运算符,用于进行各种数学和逻辑运算。
学习C语言需要熟悉不同类型的运算符,如算术运算符、赋值运算符、比较运算符和逻辑运算符等。
学生需要掌握这些运算符的使用方法和优先级。
四、控制语句控制语句用于控制程序的执行流程,包括条件语句、循环语句和跳转语句等。
学习C语言需要了解不同控制语句的语法和用法,以及它们在程序中的应用场景。
通过掌握控制语句,可以编写出更加灵活和复杂的程序。
五、数组和字符串数组和字符串是C语言中常用的数据结构。
学习C语言需要了解如何声明和使用数组,以及如何进行各种数组操作。
此外,还需要了解如何使用字符串和字符串处理函数,如字符串的拼接、比较和复制等。
这些知识点对于处理文本和数据是非常重要的。
六、函数和指针函数是C语言中的重要组成部分,它封装了一些特定的功能,并可以被多次调用。
学习C语言需要了解如何声明和定义函数,以及函数的参数传递和返回值等。
指针是C语言中的另一个重要概念,它提供了对内存地址的直接访问。
学生需要了解如何声明和使用指针,以及指针和数组、指针和函数之间的关系。
七、文件操作C语言提供了一些文件操作函数,可以对文件进行读写操作。
学习C语言需要了解如何打开和关闭文件,以及如何读写文件的内容。
c语言三种基本数据类型C语言是一种广泛应用于计算机系统开发中的语言,也是很多程序员入门学习的第一门编程语言,而C语言中的基本数据类型也是程序员必须深入掌握的基础知识之一。
下面我们就来围绕C语言中的三种基本数据类型进行详细讲解。
第一步:什么是数据类型在具体讲解C语言中三种基本数据类型之前,我们需要先了解什么是数据类型。
简单来说,数据类型是指程序中的数据所具有的特性,包括数据类型的取值范围、内存存储方式、占用字节数等。
在C语言中,每个变量都需要声明其数据类型,这样才能在程序中正确地对其进行操作,而且类型不匹配的错误也是很常见的错误之一。
第二步:三种基本数据类型C语言中的基本数据类型分为三类:整型、实型和字符型。
下面分别进行详细阐述。
1. 整型整型是指不带小数点的普通整数,包括有符号和无符号两种类型。
其中,有符号整型的取值范围为-2^31~2^31-1,即-2147483648~2147483647,占用的字节数为4。
而无符号整型的取值范围为0~2^32-1,即0~4294967295,同样也是占用4个字节。
在实际应用中,有符号整型比无符号整型更加常用,因为它可以表示正负值。
2. 实型实型是指带小数点的数值,包括单精度和双精度两种类型。
其中,单精度实型的取值范围为3.4E-38~3.4E38,占用的字节数为4;双精度实型的取值范围为1.7E-308~1.7E308,占用的字节数为8。
一般情况下,双精度实型更加精确,但是也需要占用更多的内存空间。
3. 字符型字符型实际上就是整型,只不过它的取值范围是0~255,即0x00~0xFF。
其中,单引号括起来的字符被称为字符常量,可以直接赋值给字符型变量。
例如:char c = 'A'; c 的值为65。
在C语言中,字符型变量也可以进行算术运算,但是其实质还是一个整型。
第三步:应用场景不同的数据类型适用于不同的场景。
例如,在进行科学计算或者涉及到精确计算时,应该使用实型或双精度实型变量;而在处理计数或索引等整数时,则应该使用整型变量。
C语言基础知识点一、概述C语言是一种通用的、高级的程序设计语言,由Dennis M. Ritchie在20世纪70年代初开发出来。
C语言的设计目标是提供一种能够通过简洁的语法实现高效的编程功能的编程语言。
C语言是一种程序员友好的语言,它提供了许多底层的功能,同时也允许程序员以高级的方式使用这些功能。
二、基本语法1. 数据类型C语言提供了几种基本的数据类型,包括整型、浮点型、字符型等。
使用合适的数据类型是编写高效代码的关键。
2. 变量和常量变量用于存储和操作数据,常量是固定的数据值。
C语言要求在使用变量之前必须先声明,并且可以为变量指定初值。
常量在声明时就必须被赋值。
3. 运算符C语言提供了一系列运算符,用于实现各种不同的操作。
常见的运算符有算术运算符、关系运算符、逻辑运算符等。
4. 控制流程控制流程用于控制程序的执行顺序,包括条件语句和循环语句。
条件语句根据条件的真假执行不同的代码块,循环语句重复执行相同的代码块。
三、数组与指针1. 数组数组是一种用于存储多个相同类型数据的数据结构。
在C语言中,数组的声明方式为类型数组名[数组长度],使用下标访问数组元素。
2. 指针指针是一种特殊的变量类型,它存储了一个变量的内存地址。
使用指针可以进行间接访问和修改变量的值。
3. 数组和指针的关系在C语言中,数组名可以看作是一个指向数组首元素的指针。
通过指针可以实现对数组的灵活操作。
四、函数和库1. 函数函数是一种可重复使用的代码块,用于执行特定的任务。
函数包括函数声明和函数定义两部分。
函数可以接收参数,并且可以返回一个值。
2. 标准库函数C语言提供了丰富的标准库函数,用于实现各种常用操作。
标准库函数包括字符串处理、数学计算、文件操作等。
3. 自定义库函数除了使用标准库函数,C语言还允许程序员自定义库函数。
自定义库函数可以提高代码的重用性和可读性。
五、内存管理1. 堆和栈C语言中的变量可以存储在栈上或堆上。
栈上的变量由编译器自动分配和释放,而堆上的变量需要手动管理。
深入理解C语言技术的使用原理与机制C语言作为一种广泛应用于编程领域的高级语言,其使用原理和机制是每个程序员都应该深入理解的。
本文将探讨C语言的一些重要原理和机制,帮助读者更好地理解和应用C语言技术。
一、编译与链接C语言的源代码需要通过编译器将其转换为机器语言,以便计算机能够理解和执行。
编译过程主要分为预处理、编译、汇编和链接四个阶段。
预处理阶段通过处理源代码中的宏定义、条件编译和头文件引用等,生成经过宏展开和头文件替换的中间代码。
编译阶段将中间代码翻译为汇编代码,即将C语言的语法结构转换为汇编语言的指令。
汇编阶段将汇编代码转换为机器语言的二进制指令。
链接阶段将编译后的多个目标文件和库文件合并为最终可执行文件。
了解编译与链接的过程可以帮助程序员更好地理解C语言程序的执行流程和优化方法。
二、内存管理C语言在内存管理方面相对较为底层,程序员需要手动管理内存的分配和释放。
动态内存分配是C语言中常用的内存管理机制,主要通过malloc和free函数实现。
malloc函数用于在堆内存中分配指定大小的内存空间,并返回指向该空间的指针。
程序员需要负责在使用完毕后调用free函数释放已分配的内存,以避免内存泄漏。
理解内存管理的原理和机制对于编写高效、健壮的C语言程序至关重要。
合理地分配和释放内存,可以避免内存溢出和野指针等问题,提高程序的性能和稳定性。
三、指针与引用指针是C语言中的重要概念,它保存了变量的内存地址。
通过指针,程序员可以直接访问和修改内存中的数据,实现高效的数据操作。
C语言中的引用是指通过指针访问变量的方式。
引用可以简化对变量的操作,提高代码的可读性和可维护性。
通过引用,程序员可以直接修改变量的值,而无需通过指针解引用。
理解指针和引用的原理和机制,可以帮助程序员更好地利用C语言的特性,编写出高效、灵活的代码。
四、结构体与联合体结构体是C语言中用来组织多个不同类型数据的一种数据结构。
通过结构体,程序员可以将多个相关的数据组合在一起,形成一个更为复杂的数据类型。
深入理解函数的内存管理与资源释放在计算机编程中,函数是一种重要的代码组织和复用方式。
函数的内存管理和资源释放是编程过程中必须关注的重要问题。
本文将深入探讨函数的内存管理和资源释放的原理和技巧,帮助编程工程师更好地理解和应用。
一、内存管理的基本原理在函数中,内存管理主要涉及到两个方面:动态内存分配和静态内存分配。
动态内存分配是指在程序运行时根据需要分配内存空间,而静态内存分配是指在编译时确定内存分配的大小。
1. 动态内存分配动态内存分配是通过一些特定的函数来完成的,如C语言中的malloc()和C++中的new操作符。
在函数中使用动态内存分配时,需要注意以下几点:- 内存泄漏:动态分配的内存在使用完毕后需要手动释放,否则会导致内存泄漏。
内存泄漏会消耗系统资源,严重时可能导致程序崩溃。
- 内存越界:动态分配的内存空间应该严格控制在合适的范围内,避免发生内存越界的问题。
内存越界可能导致程序异常终止或者数据损坏。
- 内存重复释放:动态分配的内存只能释放一次,重复释放会导致程序崩溃。
因此,在释放内存之后,应该将指针置为NULL,以避免重复释放的问题。
2. 静态内存分配静态内存分配是在编译时确定内存分配的大小,通常使用栈来管理。
在函数中使用静态内存分配时,需要注意以下几点:- 局部变量的生命周期:局部变量在函数调用时分配内存,在函数返回时释放内存。
因此,在函数中使用静态内存分配时,需要确保变量的生命周期与函数调用的关系。
- 栈溢出:静态内存分配的大小通常是有限的,如果在函数中使用过多的局部变量,可能导致栈溢出的问题。
栈溢出会导致程序崩溃或者数据损坏。
二、资源释放的技巧除了内存管理外,函数中还涉及到其他资源的释放,如文件句柄、数据库连接等。
以下是一些常用的资源释放技巧:1. RAII(Resource Acquisition Is Initialization):RAII是一种资源管理的技术,通过在对象的构造函数中获取资源,在析构函数中释放资源,从而确保资源的正确释放。
c中的引用变量-概述说明以及解释1.引言1.1 概述引用变量是C语言中一个重要的概念,它允许程序员创建一个别名或者称为引用来访问另一个变量的值。
在C语言中,普通变量是存储数据的位置,而引用变量是存储另一个变量地址的位置。
通过引用变量,程序员可以更加灵活地操作数据,同时也提高了代码的可读性和可维护性。
本文将介绍引用变量的概念、用法、优势和注意事项,总结引用变量在C语言中的重要性,探讨引用变量在实际应用中的作用,并展望未来引用变量在C语言中的发展前景。
通过深入了解引用变量,可以帮助读者更好地理解C语言的编程思想和技术应用,从而提升自己的编程能力。
1.2 文章结构:本文将首先介绍引用变量的概念,并解释它在C语言中的具体用法。
接着,将探讨引用变量相较于普通变量的优势,以及在使用引用变量时需要注意的事项。
在结论部分,将总结引用变量在C语言中的重要性,探讨其在实际应用中的价值,并展望引用变量在未来的发展前景。
通过本文的阐述,读者将能更深入地理解引用变量在C语言中的作用和意义,提升对于此概念的认识和运用能力。
1.3 目的:在本文中,我们的目的是探讨C语言中引用变量的概念、用法、优势和注意事项。
通过深入分析引用变量在C语言中的应用,以及总结引用变量的重要性,我们希望读者能够更加深入地理解引用变量,并在实际编程中更加灵活地运用它们。
通过本文的阐述,读者可以更好地掌握引用变量的技术要点,提高自己在C语言编程中的水平,从而更好地应对各种编程挑战。
同时,我们也希望引发读者对引用变量在未来发展中的应用和可能性的思考,为C语言编程的未来发展做出贡献。
2.正文2.1 什么是引用变量引用变量是C语言中一种特殊的变量类型,它允许开发人员创建一个别名或者代表另一个变量的变量。
通过引用变量,我们可以直接访问并修改另一个变量的值,而不需要使用额外的指针或者副本。
引用变量在C语言中类似于指针,但是与指针不同的是,引用变量必须在声明时初始化,并且不可以再次改变其引用的对象。
深入理解C语言变量和内存1、基本数据类型变量名和内存的关系:int i;scanf_s("%d", &i);int i;,在这一句就为i分配了内存(但尚未对这块内存进行初始化),所以可以通过&i直接使用这块内存。
赋值就更不用说啦,i = 3;。
变量名i,是为方便编程人员使用,是这块内存的别名,指代到块内存,对编程人员i代表这块内存中存储的值(实际上是i指到这个内存,然后取值)。
通常我们都是通过变量名来使用已知的内存的。
i代表取(这块内存中存储的)值,而&i代表取(这块内存的)址。
程序本身是不为i这个变量名分配空间的。
在最终的机器代码中,是不会出现变量名的,这一点在分析反汇编语言时可以看出(命令:dumpbin /disasm xx.obj >xx_disasm.asm 可以查看反汇编语言)。
那么编译器是如何处理变量名的呢,变量名会存储在符号表中,并将符号表中的索引对应到实际物理空间(地址)上去,当调用这个变量时,查找符号表就可以找到对应的地址并取值了。
2、不同类型变量的变量名和内存间的关系:上面分析的是基本数据类型(如int、char等)的变量名。
C中除了变量名之外,还有函数名、常量名、指针名、数组名、结构名等。
和变量名不同,这些标识符都是直接对应着地址的。
基本数据类型的变量,和地址的对应关系需要取址符&才能得到地址,而其余的这些,名字本身就对应着地址。
例如char *pc = “se”;,就是将字符串常量”se”的首地址(位于常量存储区)赋值给了字符指针pc。
这也就解释了为什么不需要为pc分配地址就可以为其赋值,而不会遇到类似下面代码所带来的野指针问题:int *pi;*pi = 1;int *pi句,是为pi分配空间,而不是开辟pi所指向的空间。
2.1 C语言中的常量:C对常量是怎么处理的呢?比如上面的i = 3;中的常量3,存储常量3的地址并不是随机分配的,是在程序中的数据段中(.data?这个我也还不是很确定,希望知道的前辈们给个指导),也就是程序本身并不为3分配内存,而是直接写入指令。
3是数字常量,对于字符常量和字符串常量,又分别是怎么处理的呢?字符常量和数字常量是一样的处理方式,都是类似汇编中的立即数,直接写入指令;而字符串常量,则是存储在常量存储区,可以使用&(“string”)取得具体地址。
也就是字符串常量名字本身指代着地址,只是不能直接操作(和int i中的i相同)。
2.2 C语言的变量名c中的数据类型除常量之外大致有5种:基本数据类型:short、int、float、double、char:对各基本数据类型的变量名及其声明时的处理方式都是一样的,声明时即分配内存,并使用变量名直接操作这段内存;使用取地址符号&取得地址的数字表示,至于声明时要不要做初始化,要看是不是全局变量或者 static变量了。
这类变量名指向一个地址空间,但不能直接当做地址使用,而是通过取址符&操作其地址。
2.3 构造数据类型:数组、结构、联合:1) 数组数组在声明时,即分配了空间:int a[5];一旦声明a[5],相当于有a、a[0]、a[1]、a[2]、a[3]、a[4]这6个变量名。
a[i]的指代方式和普通的变量名int i相同,指到一个对应的内存空间;关键是变量名a,本身就可以做地址用。
我们知道a是数组名,但a并不代表整个数组的地址,而是指向数组首元素的地址(虽然在数值上是相同的,下面会有详细解释),所以可以有 int *p = a;。
那么&a又怎么解释呢?对于int i而言,i代表一个空间,&i表示i所代表的空间地址;那么&a应该也是表示a所代表的地址了,也就是整个数组的地址。
a、&a和&a[0]同代表地址,且由于数组是顺序存储,所以a、&a和&a[0]所表示的地址在数据上是相同的,但是实际的指代意义却是不同的:a是个int*类型的数据,相当于&(*a),是指向数组首元素的地址;&a指代整个数组,是个int(*)[]类型的数据,是指针数组的地址;&a[0]则是仅指代一个存储int的空间,是int*类型的数据。
也就是数组名,本身可以作为地址使用,指代该结构的首元素的地址。
2) 结构结构在声明的时候,就分配了空间。
结构体和数组不同,结构体类型的变量名并不能直接当作地址使用,这一点和基本数据类型相同。
需要对结构体名使用取址符&才能进行地址操作,并且取址所得到地址代表的是指向结构体的指针,只是在数据上和结构体中的首元素地址相同。
对于结构体中的各个元素,其名称的指代关系和其数据类型相同,并不因为是结构体的元素而受到影响。
具体见下面代码:struct stu{int age;char sex;char* name;int score[5];};int main(){int i;struct stu st1; //st1是结构体stu类型printf("%d\n", &st1); //&st1是 stu*类型printf("%d\n", &st1.age); //&st1.age是 int*类型,st1.age 就是个int型,名字指向地址,但不能直接作地址printf("%d\n", &st1.sex); //&st1.sex是 char*类型,名字解析同上printf("%d\n", &); //&是char**类型,是char*类型printf("%d\n", st1.score); // st1.score是个数组类型,名字代表数组中首元素的地址return 0;}3) 联合联合是特殊的结构体,为节省空间,在其各元素依次存储,各元素的首地址均相对变量的基地址偏移为0,具体各变量名的分析和结构体同。
2.4 指针类型声明一个指针类型 int *p;,则是为存储指针p分配空间,而并不会为p所指向的内存做任何动作,这就是野指针的原因。
如下代码,p就是一个未指向任何已知内存的指针,为*p赋值,自然会出现错误:int *p;*p = 1;指针中,char 是个很特殊的指针。
一般的指针,仅指向一个所定义类型的内存,而char 则可以指向一个字符串,之所以可以实现这个功能是字符串结尾符’\0’的存在标识了字符串的结束。
如下的代码,就是将pc指向了“string”所指代的常量存储区地址。
char *pc = “string”;这也是char *pc = “string”合法,而int *p =1不合法的原因:”string”本身即代表了它的存储地址,而整型常量1仅仅是个操作数,并不是地址,如果希望使用数据为指针(指向的地址)赋值,可以使用一个强制转换 int*p = (int*)1,只是这样如果不加以检查的话,写出来的代码会存在安全隐患。
因此,不管指针变量是全局的还是局部的、静态的还是非静态的,都应该在声明它的同时进行初始化,要么赋予一个有效的地址,要么赋予NULL。
另外,声明一个指针,只是在栈区为指针本身的存储分配了地址,而不限制指针所指向的内存到底是在栈区、还是在堆区、还是在常量存储区。
这也就造成了函数调用返回值会因实现不同而有不同意义,是函数调用结束后返回值有效性不同的原因。
2.5 空类型C中有void关键字,但其实C中是并没有空类型的。
比如我们不能做如下定义:void a;因为C、C++是静态类型的语言,定义变量就会分配内存。
然而,不同类型的变量所占内存不同,如果定义一个任意类型的变量,就无法为其分配内存。
所以,C、C++中没有任意类型的变量。
但是定义void p;是合法的,void 所定义的p表示以指针,所指向的类型未定。
因为void *p;声明是为指针p分配了空间,无论指针指向什么类型,存储指针所需的空间的固定的,所以不存在因为所需空间大小而无法为p分配空间的问题。
但void p的使用也是很受限制的,由于不知道其指向的数据类型,所以是不能对p进行自增操作的;void的主要作用有两点,一个是限制函数的返回值,一个是限制函数的参数类型;void 则常用于指针的类型转换。
如下代码:int *pi;float *pf;如果想将pi指向pf所指向的内存空间,就必须进行类型转换:pi = (int *)pf;。
而如果是将pi换成void *p,就不需要转换,可以直接为指针赋值。
这样的直接赋值,只能是将一个已知类型的指针赋值给void *p,而不能是将void *p未加强制转换地赋值给一个已知类型的指针,如:void *p;int *pi;float *pf;p = pf; // pf = p;就是非法的,不能将 "void *" 类型的值分配到 "float *" 类型的实体p = pi;但需要注意的是,即使进行了转换,p仍然是个void*类型的指针,不能对其进行sizeof(p)等涉及所指类型的操作,同样地p也不能直接用于具体数据类型的操作。
如下面的代码中*p = 1.73; 和printf(“%f”, *p)都是非法的:void *p;float *pf;p = pf;*p = 1.73; //*pf = 1.73;合法printf("%f", *p); //printf("%f", *pf); 合法这样说来,void *的意义何在呢?可以使用强制类型转换使用void *p作为中介,见下面的代码:float *pf;void *p;float f=1.6;p = (void*)&f;pf = (float*)p;这样,float pf就指向了float f所在的地址,但注意p依然不能直接使用。
这个例子,只是为我们展示了void 有这样的功能,但平常代码中很少这样无意义地转换,更多地是将void *作为函数参数,这样就可以接受任意类型的指针了,典型的如内存操作函数memcpy和memset的函数,其原型分别为:void * memcpy(void *dest, const void *src, size_t len);void * memset ( void * buffer, int c, size_t num );也可以编写自己的将void 作为函数参数的函数,由于char是C中最小长度的变量,其它任何变量的长度都是它的整数倍。
可以使用char作为中转,详见下面的函数实现:void swap(void *pvData1, void *pvData2, int iDataSize){unsigned char *pcData1 = NULL;unsigned char *pcData2 = NULL;unsigned char ucTmp1;pcData1 = (unsigned char *)pvData1;pcData2 = (unsigned char *)pvData2;do{ucTmp1 = *pcData1;*pcData1 = *pcData2;*pcData2 = ucTmp1;pcData1++;pcData2++;} while (--iDataSize > 0);}int main(){float fa = 1.23, fb = 2.32;float *f1=&fa, *f2=&fb;int iDataSize = sizeof(float)/sizeof(char);swap(f1, f2, iDataSize);return 0;}NULLC中对NULL的预定义有两个:#define NULL 0#define NULL ((void *)0)并且标准C规定,在初始化、赋值或比较时,如果一边是变量或指针类型的表达式,则编译器可以确定另一边的常数0为空指针,并生成正确的空指针值。