文档章节

C 杂谈之 指针与数组

mickelfeng
 mickelfeng
发布于 2017/08/22 13:47
字数 2327
阅读 21
收藏 0

 思维导图

 介绍

1> 指针定义:指针是保存变量地址的变量。

2> 本文重点

         >> 指针与数组之间的关系

         >> 操纵指针的规则

3> 指针优点

         >> 表达某个计算的唯一途径

         >> 代码更高效,更紧凑

4> 指针缺点:难以理解,但是用好了,代码会非常清晰。

5> 将指针、数组和地址的算术运算集成在一起是C语言的一大优点。

 指针与地址

1> 内存组织方式

内存组织

     (1) 内存是一个个单元组成的,每一个内存单元中存放一个字节(8位)的二进制信息。

     (2) 机器中的内存单元是有序排列的。

     (3) 机器给各个内存单元规定不同地址来管理内存。这样,CPU通过地址来识别不同的内存单元,正确的对内存单元进行操作。

2> 指针与变量的关系(P:是指针变量,C:内存对象)

  >>> P:保存C:中的单元首地址——这里的地址不是物理地址,而是经过地址映射后的虚拟地址,即逻辑地址。

  >>> P:为指向C:的指针

 3>理解指针

   >>>  指针占用的内存空间大小: 32位系统占用4byte,64为8byte。

机器配置:

打印指针大小:

   >>>  指针就是地址——我们可以把指针认为是用来存放地址的数据类型。不能把指针简简单单的当成一个整型数,虽然地址的值是一个整型数据。

   >>>  指针是有类型的,但是这个类型不是给指针分配内存的,而是用来寻址的。

 指针与函数参数

1.普通参数:C语言通过传值方式将值传递给被调用函数。

   >> 会把变量的值复制一份给被调用函数。

   >> 复制:会把变量的值赋值给一个新的变量(参数)——变量和新的变量必须有相同的存储容量。

   >> 被调用函数并不能修改主调程序中的变量值,因为被调用函数使用的是一个复制过来的内存单元。

 

2.指针参数: 本质上跟普通参数传递是相同的,也进行了变量复制,但是传过去的值是地址。 被调用函数通过地址能够访问和修改主调程序中变量的值。

3.参数在内存消耗

  普通参数:取决于申明类型。char:1个字节;short:2个字节;long:8个字节

  指针参数:指针变量里存储的是地址(一般是4个字节——32位),永远是一个固定长度,不管是什么类型的指针。——除非处理器变化不是32位。

4.double *dp, atof(char *)  这里的dp是指针变量,而atof是函数

 指针与数组

1.指针操作数组快于下标操作数组

2.数组的空间分配.如int a[10];——会在空间分配出40个相邻的内存单元来(10*4)。

3.指针操作数组

int *pa;

pa = &a[0];

 4.指针移动

int *pa;
int a[10];
pa = &a[0];

pa+1将指向下一个元素a[1]:

 >> 内存中的变化:"指针加1"会根据指针指定的类型int移动4个内存单元,其实本身并没有移动,只是pa+1等于第5个内存单元地址——“指针加1”中的1的大小是取决于pa的类型int的,指针类型决定指针跨内存单元的步长。

>> pa+1 等于是指向第5个内存单元——a[1]的第一个内存单元。

 5.规则:

   >> &a[i]和a+i含义相同,相互使用。a+i是a之后第i个元素地址。

   >> 数组名代表数组第一个元素的地址。

 地址运算符

1. 指针初始化:0或表示地址的表达式。

2. “指针加1”中的“1”的大小根据数据类型的长度按比例缩放。如果int类型占4个字节的存储空间,对应的1按4倍计算。

验证:

 >>> 若指向char类型的指针p的内存地址是0x000000,那么p+1后的地址是0x000001。

验证过程如下:

运行结果:

>>> 若指向int 类型的指针p的内存地址是0x000000,那么p+1后的地址是0x000004。

运行结果:

3.指向不同数组的元素的指针之间的算术或比较运算都没有定义。

4.指针相减:如果p和q指向相同数组中的元素,且p<q,那么q-p+1就是p和q之间的元素(包括p和q)

代码验证:

运行结果:

 流程变化:q-p=16 => 16/4=4 (按照int型所占内存单元等比例缩放) => 4 + 1 = 5;

 总结

这次写关于c语言方面指针,是因为这两天看php内核文件的时候,由于C方面的欠缺,所以看着很吃力。所以想再复习下C语言。

为什么从指针入手呢?可能是因为指针在C语言中是比较难的。所以先把最难的啃下来。

本来是想一次性写完,可是指针这方面内容太多,所以决定分几批写。

我在C语言方面还是很薄弱,如果文章中有错误,希望高手们指点下。

我知道博客园C方面高手非常多,我在C方面属于菜鸟级别的,没有任何开发经验,所以希望高手们能多指点下!

 

 思维导图

 

 介绍

前接上文C 杂谈之 指针与数组 (一),接续往下谈指针和数组。

 指针与数组  ——承接上文进行扩展

你知道X = Y,在编译运行过程中,是什么样吗?

 字符指针与函数

1> 字符串是一个以'\0'结尾的字符数组。

看一个例子:printf接受的是一个指向字符数组第一个字符的指针。

这个例子与下面两个代码是一个道理.

2> 几个常用字符函数的编写。

 1>>> strcat(s,t)函数,把t指向的字符复制到s指向的字符后面?——注意'\0'

#include <stdio.h>
#include <assert.h>

/*  strcat(ps, t): Copy the charactor pointed 
 *  by t  append to the character pointed by s  
 */
void *strcat(char *ps, char *t){
    char *addr = ps;
    assert((ps != NULL) && (t != NULL));
    while(*ps){  /*  The s point to the last character   */
        ps++;
    }

    while(*ps++ = *t++){ /*  Copy t append to the s*/
    }

    return addr;
}

int main(){
    char s[5] =  "AB";
    char *t = "E";
    printf("%s\n", strcat(s, t));
    return 0;
}

注意:在strcat里的两个指针ps和t,方法结束后,这两个函数都指向'\0'后面,因为ps++操作是"先取结果,后自增"
内存变化:

金玉岚

 2>>> 函数strend(s,t):字符串t出现在字符串s的尾部,返回1,否则返回0。

int strlen(char *p){
    int iLen = 0;
    while(*p){
        iLen++;
        p++;
    }   

    return iLen;
}

/*  strend:find t in s  */
int strend(char *s, char *t){
    int sLen = strlen(s);
    int tLen = strlen(t);

    if(tLen > sLen) return 0;

    while(*s)
        s++;
    
    while(*t)
        t++;

    for(;tLen--;){
        if(*--t != *--s) return 0;
    }   

    return 1;
}

int main(){
    char *s = "Hell Wold , Chuanshanjia";
    char *t = "Chuanshanjia";

    printf("%d\n", strend(s, t));
    return 0;
}

 3>>> strncpy(s,t,n) 将t中前n个字符复制到s中。

strncpy(s,t,n)
#include <stdio.h>

int strlen(char *p){
    int i = 0;
    while(*p){
        p++;
        i++;
    }   

    return i;
}
/*  t中最多前n个字符复制到s中   */
char *strncpy(char *s, char *t, int n){ 
    char *addr = s;
    if(!strlen(s) || !n) return 0;

    int tLen = strlen(t);
    if(!tLen) return 0;

    if(tLen < n)
        n = tLen;

    // Move the pointer s to the last
    while(*++s) ;

    while(n--){
        *s++ = *t++;
    }   

    return addr;

}
int main(){
    char s[20] = "Hell World ";
    char *t = "Chuanshanjia";

    printf("%s\n", strncpy(s, t, 2222));
    return 0;
}

 命令行参数

1.第一个参数(常用argc表示)(:运行时命令行参数数目;第二个参数(常用argv表示)是一个指向字符串数组的指针。

2.C语言规定,argv[0],表示启动程序的名称。

3.实例

运行结果:

 内存分配:

 

解释:

>> argv是一个指向指针数组的指针。

所以接受参数也可以写成:

结合上图,我们可以这样理解:从里向外看

 

 复杂声明

 1.阅读——从右向左规则。

>> 规则符号:

-----------------------------------------------------------

* 读作"指向...的指针"

[] 读作"...的数组"

() 读作"返回...的函数"

-----------------------------------------------------------

下面两个示例:

int *f() ; // f: 返回指向int型的指针

>>步骤:

1)找标识符f:读作"f是..."

2)向右看,发现"()"读作"f是返回...的函数"

3)向右看没有什么,向左看,发现*,读作"f是返回指向...的指针的函数"

4)继续向左看,发现int,读作"f是返回指向int型的指针的函数"

 

int (*pf)(); // pf是一个指针——指向返回值为int型的函数

1)标识符pf,读作“pf是...”

2)向右看,发现),向左看,发现*,读作 "pf是指向...的指针"

3)向右看,发现"()",读作“pf是指向返回...的函数的指针"

4)向右看,没有,向左看发现int,读作"pf是指向返回int型的函数的指针"

 总结

我最近着重看C,是因为我想深入了解一下PHP内核语言和服务器模块开发。现在的C语言,能够让我更深入的了解计算机内部。

参考文献:《C程序设计语言》

本文转载自:http://www.cnblogs.com/baochuan/archive/2012/03/26/2414062.html

mickelfeng

mickelfeng

粉丝 237
博文 2784
码字总数 604219
作品 0
成都
高级程序员
私信 提问
指针——C语言的灵魂

为什么说C指针是C语言的灵魂? 来自读者对C和指针的解说 他可以直接访问硬件,这是灵活性和效率的体现,程序离硬件越近自然效率越高,当然运用不当也可导致效率低下 难掌握及太危险,如果对指...

生气的散人
2013/03/25
1K
5
C语言/C++编程学习之指针和数组的深入理解

C语言是面向过程的,而C++是面向对象的 C和C++的区别: C是一个结构化语言,它的重点在于算法和数据结构。C程序的设计首要考虑的是如何通过一个过程,对输入(或环境条件)进行运算处理得到...

小辰带你看世界
2018/05/14
0
0
C/C++ 更加安全的库--Checked C

微软开源了Checked C,旨在对C和C++增加边界检查的研究项目。 Checked C允许程序员在C/C++中编写“确保边界检查”的代码。为了实现这个功能Checked C增加了新的指针和数组类型,它们可以在编...

匿名
2016/06/23
7K
4
C语言字符串指针和字符数组的区别

用字符数组和字符指针变量都可实现字符串的存储和运算。但是两者是有区别的。在使用时应注意以下几个问题: 1. 字符串指针变量本身是一个变量,用于存放字符串的首地址。而字符串本身是存放在...

psaux0
2014/04/25
1
0
C/C++没有数组

在其它高级语言里,不管是定义(声明)还是引用,a[i]或a[3]都是一个整体。在C/C++里,却是一个表达式:a[i]是运算符[]连接两个实体a和i。 说C/C++并没有数组,有以下几条理由。 理由一:C里没...

loongchao
2012/05/21
1K
17

没有更多内容

加载失败,请刷新页面

加载更多

只需一步,在Spring Boot中统一Restful API返回值格式与统一处理异常

统一返回值 在前后端分离大行其道的今天,有一个统一的返回值格式不仅能使我们的接口看起来更漂亮,而且还可以使前端可以统一处理很多东西,避免很多问题的产生。 比较通用的返回值格式如下:...

晓月寒丶
昨天
59
0
区块链应用到供应链上的好处和实际案例

区块链可以解决供应链中的很多问题,例如记录以及追踪产品。那么使用区块链应用到各产品供应链上到底有什么好处?猎头悬赏平台解优人才网小编给大家做个简单的分享: 使用区块链的最突出的优...

猎头悬赏平台
昨天
28
0
全世界到底有多少软件开发人员?

埃文斯数据公司(Evans Data Corporation) 2019 最新的统计数据(原文)显示,2018 年全球共有 2300 万软件开发人员,预计到 2019 年底这个数字将达到 2640万,到 2023 年达到 2770万。 而来自...

红薯
昨天
65
0
Go 语言基础—— 通道(channel)

通过通信来共享内存(Java是通过共享内存来通信的) 定义 func service() string {time.Sleep(time.Millisecond * 50)return "Done"}func AsyncService() chan string {retCh := mak......

刘一草
昨天
58
0
Apache Flink 零基础入门(一):基础概念解析

Apache Flink 的定义、架构及原理 Apache Flink 是一个分布式大数据处理引擎,可对有限数据流和无限数据流进行有状态或无状态的计算,能够部署在各种集群环境,对各种规模大小的数据进行快速...

Vincent-Duan
昨天
60
0

没有更多内容

加载失败,请刷新页面

加载更多

返回顶部
顶部