`

总结之《征服C指针》

 
阅读更多

对于接触过c语言,而没有理解指针以及内存布局的人来说,《征服C指针》是不错的选择。

 

这本书中的补充内容也值得阅读,通过和java,c++等一些语言比较,来体会c语言的魅力。

 

第一章  从基础开始

 

几乎所有的处理程序中,所谓的“指针类型的值”,实际是指内存的地址。

 

p28 的补充值得看,主要讲了NULL, 0,'\0'的区别,不要使用NULL来结束字符串,一般都用'\0'

 

p49 补充,c语言是不做数组下标越界检查的 

 

要点: 1.变量不一定按照声明的顺序保存在内存中。

       

       2.对变量使用&运算符,可以取得该变量的地址。这个地址成为指向该变量的指针。

 

       3.指针变量hoge_p保存了指向其他变量的地址的情况下,可以说“hoge_p指向hoge”。

 

       4.对指针变量运用*运算符,就等同于它指向的变量。如果hoge_p指向hoge, *hoge_p就等同于hoge。

 

       5.对指针加N,指针前进“当前指针指向的数据类型的长度*N”

 

       6.p[i]是*(p+i)的简便写法。

 

       7.在C中是不能将数组作为函数参数进行传递的。但是,你可以通过传递指向初始元素的指针来达到将数组作为参数进行传递的目的。

 

第二章  虚拟内存

这一章对于操作系统内存管理薄弱的人来说,看看有益

一个程序用两个窗口来跑,相当于是两个进程,两个进程之间相互独立互不影响,但是在打印变量的内存地址时却是同一个地址。why?

原因是输出指针的时候,打印输出的并不是物理内存地址本身。

 

当今操作系统都会给每一个进程分配独立的“虚拟地址空间”。这和C语言没有关系,而是操作系统和cpu协同工作的结果。正是因为操作系统和cpu努力地为每一个进程分配独立的地址空间,所以就算我们制造了一个bug,破坏了某个内存区域,顶多会使得当前程序趴窝,不影响其他进程。

 

当然,真正保存内存数据的还是物理内存。操作系统负责将物理内存分配给虚拟地址空间,同时还会对每一个内存区域设定“只读”或者“可读写”等属性。

 

通常,因为程序的执行代码是只读的,所以有时候会和其他进程共享物理内存。另外,当我们启动了几个笨重的应用程序而使内存出现不足时,操作系统把物理内存中还没有被引用的部分倒腾出来,保存到硬盘上。当程序再次需要引用这个区域的数据的时候,再从磁盘写回到内存。这个操作是在操作系统的后台进行的,对于应用程序来说,压根儿不知道背后发生的事。这是硬盘“咔嗒咔嗒”响,机器就慢了下来。

 

之所以能够这样,多亏了虚拟地址。正式因为避免了让应用程序直接面对物理内存的地址,操作系统才能够顺利地对内存区域进行重新配置。

 

要点:

C中有三种内存领域的寿命

1.静态变量的寿命从程序运行时开始,到程序关闭时结束。

2.自动变量的寿命到声明该变量的语句块执行结束为止。

3.通过malloc()分配的领域的寿命到调用free()为止。

 

将函数自身和字符串常量汇总配置在一个只读内存区域。执行时程序是只读的,在同一份程序被同时启动多次的时候,通过在物理地址上共享程序

能够节约物理内存。此外,由于硬盘上已经存放了可执行程序,就算内存不足,也不需要将程序交换到虚拟内存,相反可以将程序直接从内存中销毁。

 

char *s = "abc";

s[0] = 'd';

这个字符串常量是配置在只读内存区域的,所以该写法s[0]='d' 是不行的。

 

静态变量总是在虚拟地址空间上占有固定的区域。

 

各个目标代码之间通过链接器链接处理生成可执行程序  .o文件即符号表(可重定位文件),就是根据符号表的内容对函数,变量进行重定位链接。比如函数声明在一个a.h文件中,

定义在a.cpp文件中,而调用在b.cpp文件中,这时需要用链接器将函数的定义链接到b.cpp。

 

在声明自动变量的函数执行结束后,自动变量就不能被使用了。所以自动变量重复使用内存区域,自动变量的地址是不一定的。

 

C语言中,在现有被分配的内存区域之上以“堆积”的方式,为新的函数调用分配内存区域。在函数返回的时候,会释放这部分内存区域供下一次

函数调用。

 

 

C语言函数调用的实现:

1.在调用方,参数从后往前按顺序被堆积在栈中。这就为可变长参数提供了基础,可变长参数永远都可以在内存中寻找到第一个参数。

2.和函数调用关联的返回信息也被堆积在栈中。所谓的返回地址,是指函数处理完毕后应该返回的地址。正因为返回地址被堆积在栈中,所以无论函数从什么地方

被调用,它都能返回到调用点的下一个处理。

3.跳转到作为被调用对象的函数地址。

4.栈为当前函数所使用的自动变量增长提供所需大小的内存区域。

5.在函数的执行过程中,为了进行复杂的表达式运算,有时候会将计算过程中的值放在栈中。

6.一旦函数调用结束,局部变量占用的内存区域就被释放,并且使用返回信息返回到原来的地址。

7.从栈中出去调用方的参数。

 

p70的补充 一旦函数执行结束,自动变量的内存区域就会被释放。

 

assert(条件表达式)  若条件表达式的结果为真,什么也不会发生;若为假,则会输出相关信息并且强制终止程序。 

 

利用malloc来进行动态内存分配

p = malloc(size);

free(p);

并且可以通过任意的顺序释放的记忆区域,称为堆。

malloc的返回值的类型为 void*

 

系统调用brk()就是通过设定这个内存区域的末尾地址,来伸缩内存空间的函数的。

 

调用函数的时候,栈会向地址较小的一方伸长。多次调用malloc()时,会调用一次brk(),内存区域会向地址较大的一方伸长。

 

要点:

1.malloc不是系统调用

 

malloc()遍历链表寻找空的块,如果发现尺寸大小能够满足使用的块,就分割出来将其变成使用中的块,并且向应用程序返回紧邻管理区域

的后面区域的地址。

free()将管理区域的标记改写成“空块”,顺便也将上下空的块合并成一个块,这样可以防止块的碎片化。

free()之后,对应的内存区域是不会立刻返还给操作系统的。

 

calloc()使用和malloc()相同的方式分配nmemb*size大小的内存区域,并且将该区域清零返回。也就是和一下代码有同等效果

p = malloc(nmemb * size);

memset(p, 0, nmemb * size);

就算我们使用了calloc(),在释放内存的时候也请使用free()。

 

还有一个realloc()

realloc(void *ptr, size_t size);

如果通过ptr传递的区域后面有足够大小的空闲空间,就直接实施内存区域扩展。但是,如果后面的区域没有足够多的空闲空间,就分配其他新的

空间,然后将内容复制过去,而原来的部分会被操作系统自动回收。

 

另外,注意内存布局的对齐,和字节排序  大端存储和小端存储。

 

 第三章

主要着重讲解了指针类型和数组类型,以及多维数组(其实在C中,是没有多维数组的,因为在内存中的存储是一维的)

 

解读C的声明 const修饰符是重点 也是面试里面的基础

const char *str  或  char const *str

str = NULL;//  OK     只读的是str所指的对象

*str = 'a';//  not OK

 

char * const str      只读的是str自身

str = NULL;//  not OK

*str = 'a';//  OK

 

const char * const str

str = NULL;//  not OK

*str = 'a';//  not OK

 

另外注意结构体所用const的修饰符,在结构体上用const,结构体中的元素仍然可以修改,除非给结构体中的元素也加上const修饰。

 

要点:

    1.只有在声明函数形参的情况下,int a[]和int *a才具有相同的意义。

    2.extern的声明,意味着“使在某处声明的对象能够在当前的地方使用”,因此它不是定义   extern int a;

 

字符串常量

char *str = "abc";

"abc"就是普通的"char的数组",在表达式中被解释成"指向char的指针",然后被赋给str。

 

第四章  

注意数组和指针的常用方法

可变长数组  和 p165 java数组的联系。 java的数组是保存在堆中的(因为声明int[] hoge = new int[10]),但不能改变长度,他没有类似于realloc()这样的函数。

 

可变长结构体

 

第五章 

 

实践,推荐读者认真将这一章的两个案例 分别实现  有助于理解

 

分享到:
评论

相关推荐

    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语言指针...

    C语言指针总结

    指针是C语言中最为核心的概念之一,它提供了一种引用内存地址的方式,允许程序员通过地址直接操作内存中的数据。虽然指针功能强大,但同时也是许多初学者的噩梦,因为它们的理解和使用容易出错。本文将通过细致的...

    C语言指针练习填空和阅读程序题

    C语言指针练习填空和阅读程序题 本资源主要涵盖了C语言指针的相关知识点,包括指针的基本概念、指针运算、指针与数组的关系、指针与字符串的关系等。通过本资源的学习,可以帮助读者更好地理解和掌握C语言指针的...

    C语言指针详解.zip

    c语言指针详解 c语言指针详解 c语言指针详解 c语言指针详解 c语言指针详解 c语言指针详解 c语言指针详解 c语言指针详解 c语言指针详解 c语言指针详解 c语言指针详解 c语言指针详解 c语言指针详解 c语言指针详解 ...

    《C语言指针经验总结》PDF

    C语言中的指针是其强大特性的核心之一,它允许程序员直接操作内存,实现高效的数据处理和灵活的程序设计。这份资料通过实例和经验分享,帮助读者深化对指针的理解,提升编程能力。 首先,C语言指针的基本概念是理解...

    C语言指针知识点总结.pdf

    掌握指针的知识是学习C语言不可或缺的一部分,本文将总结C语言中关于指针的知识点。 首先,指针的声明和初始化。在C语言中,指针的声明需要使用星号(*)操作符,如`int *p;`表示声明了一个可以指向int类型的指针变量...

    c语言指针习题及答案

    - 使用指针 s 指向字符串常量是正确的字符串赋值方法之一。 **10. 字符串处理** - **题目解释**:这道题考查了字符串处理的基本方法。 - **答案**:C)字符 ‘c’ 的地址 - **扩展知识点**: - `s += 2;` 使得 s...

    C语言指针函数和函数指针详细介绍.

    C语言指针函数和函数指针详细介绍 C语言中指针函数和函数指针是两个不同的概念,但它们之间存在着紧密的联系。本文将对C语言中的指针函数和函数指针进行详细的介绍。 一、指针函数 指针函数是指返回值为指针的...

    c语言指针学习笔记

    C语言中的指针是一种基础而强大的功能,它允许直接访问内存地址,从而实现对变量的高效处理和数据操作。本文将介绍C语言指针的基本概念、定义、初始化、运算以及与一维数组的关系。 首先,我们要理解内存地址的概念...

    彻底搞定C语言指针————

    "彻底搞定C语言指针" C语言指针是C语言中一个非常重要的概念,但它却是初学者最容易迷惑和混淆的部分。要真正搞定C语言指针,需要深入理解C语言变量的存储实质和内存空间的概念。 1. 变量的存储实质 内存空间可以...

    深入理解C语言指针的奥秘.doc

    深入理解C语言指针深入理解C语言指针深入理解C语言指针

    C语言指针数组函数笔记

    "C语言指针数组函数笔记" ...本笔记总结了C语言中的指针和数组相关知识点,涵盖了变量、指针变量、指针运算符、数组和指针数组函数等内容。通过阅读本笔记,读者可以更好地理解和应用C语言中的指针和数组。

    C语言指针课程PPT

    【C语言指针课程PPT】讲解了C语言中核心的指针概念,它是C语言高效编程的关键。指针允许程序直接访问内存地址,增强了代码的灵活性和性能。以下是关于指针的详细知识点: 1. **变量与内存地址**: - 当在C语言中...

    C语言指针的运用

    ### C语言指针的运用详解 #### 指针的概念及基本定义 在C语言中,指针是一种非常重要的数据类型,它存储的是其他变量或数据结构的内存地址。掌握指针的使用对于深入理解C语言乃至其他编程语言至关重要。本文将基于...

    精选C语言指针资料大全

    C语言中的指针是其强大的特性之一,也是学习C语言时的一大难点。"精选C语言指针资料大全"集合了多种资源,旨在帮助初学者和深入研究者更好地理解和掌握这一核心概念。以下是对这些资源中可能包含的知识点的详细解释...

    c语言:我眼中的指针(教你彻底认识指针)

    使用指针可以进行动态内存分配,这是C语言中最常用的技术之一。通过 `malloc()` 和 `calloc()` 函数可以分配内存,并通过指针指向这块内存区域。 #### 九、指针的高级用法 除了基本的应用外,指针还有许多高级用法...

Global site tag (gtag.js) - Google Analytics