第一章. 指针基础知识

1. 内存地址和内存空间

学习指针的相关知识,首先需要了解下内存。我们通常所说的内存,往往指的是内存空间。其实内存是由内存地址和内存空间共同组成的,且内存地址和内存空间是一一对应的。

内存地址是一个编号,代表一个内存空间的位置。
内存空间是存储数据的空间,真正保存数据的地方。
在计算机中存储器的容量是以字节为基本单位的。也就是说一个内存地址代表一个字节(8bit)的存储空间。

内存地址对应内存空间.png

有个非常形象的比喻:
内存就像小区房子一样,内存地址代表房子的门牌号,内存空间是房子内居住的空间。
已经被出售了的,代表空间被申请占用了;
已经办理入住的,代表空间被数据写入;
正在出售的,代表此空间空闲;

2. 指针相关表示方法

  • 2.1 指针,指向某空间的标记,比如:

    char *charPointer —> charPointer是指向 char 类型的指针。char 内存中占用一个字节内存空间,charPointer指向了这个字节的内存地址

    int *intPointer —> intPointer是指向 int 类型的指针。int 内存中占用四个字节内存空间,ntPointer指向了这个四个字节中首字节的内存地址。

  • 2.2 取地址
    符号 &,可以帮助我们获取相关内存中的地址。
    指针就是先申请内存空间,然后把指向这个数据内存的首地址存入申请的内存空间。
    所以指针必须初始化才有意义。

 int a = 1;

 int *d ; //申请一个可以保存 int 类型内存地址的指针
 d = &a;// 把 a 的地址赋值给指针

 printf("%d \n", a); // log结果:1
 printf("%p \n", &a); //log结果:0x7ffeefbff59c 
 printf("%lu \n", sizeof(a)); //log结果:4

 printf("%p \n", d); //log结果:0x7ffeefbff59c
 printf("%lu \n", sizeof(d)); //log结果:8
  • 2.3 解引用
    我们已经知道指针的内存空间中保存了相关的数据,那么怎么来使用这个数据呢?这里需要的就是解引用,也就是间接访问。
    需要注意的是:
    NULL 指针 :什么都没有指向的指针(默认 NULL = 0)
 int a = 1;
 int *d ; 
 d = &a;

printf("%d \n", a); // log结果:1

*d = 5;  //这里就是解引用(间接访问) :* 这个 * 是解引用指针
printf("%d \n", a); // log结果:5

3. 指针的相关运算

通过取地址,指针,解引用……相关的表示,我们衍射出很多相关的运算

  • 3.1 通过指针操作相关的变量
 int a = 12;
 int *d = &a;// 创建指针 指向a的地址
        
*d = 10 - *d;//  这里其实就修改了a变量

 printf("%d \n",a); // log 结果:-2
//先取地址 然后解引用
 *&a = 25;// 这行等价于 a = 25;
 printf("%d \n",a);// log 结果:25
 printf("%p \n",&a);// 取a 的地址::0x7ffeefbff59c
 //对这个地址数值进行操作
 *(int *)0x7ffeefbff59c = 20; // (int *)0x7ffeefbff59c ->代表指针常量,这个是把内存地址强转成一个指针

 printf("%d \n",a);//打印结果 :a = 20;
  • 3.2 多级指针
    多级指针是指,把一个变量的地址赋值给一个指针,然后把这个指针的地址又赋值给新的指针……

    多级指针的解引用,也是一层层通过相关的地址找到最终变量,然后才能对变量进行相关操作

 int a = 12;
 int *b ;
 b = &a;

 int **c;//指向指针的指针 :指向指针的地址
 c = &b;
        
/* 解引用: **
第一个* 指向b 的内存地址,得到指针b
第二个* 指向a 的内存地址,得到变量a
*/
  **c = 25;

  printf("%d \n",a);//打印结果 :a = 25;
  • 3.3 练习指针的++,--
char c1,c2,c3;
char *cp;
//定义初始化函数
void setup() {
     c1 = 'a';
     c2 = 'f';
     c3 = 'c';
  
   cp = &c1;
}

int main(int argc, const char * argv[]) {

 setup();
 printf("%c : %c : %c \n",c1,c2,c3);//a : f : c 
 printf("%p : %p : %p \n",&c1,&c2,&c3);//0x100001030 : 0x100001031 : 0x100001032 
 printf("%p : %p \n",&c1,cp);//获取 c1 cp 地址:0x100001030 : 0x100001030
 printf("%p \n",&cp);//指针的地址:0x100001038
 printf("%c \n",*cp);//指针指向的地址:a
 printf("%c \n",*cp + 1);//指针指向的地址:b ;原因:a的asc值97 ,97+1 = 98 (b的asc值)
 printf("%p : %p \n",cp + 1,&c2);//指针指向的地址:0x100001031 : 0x100001031 
 printf("%c \n",*(cp + 1));//指针指向的地址:f : 原因:指针指向的内存地址 + 1,指向了下一个byte的内存
 printf("%p : %p \n",++cp,&c2);//0x100001031 : 0x100001031

// 练习 // 结果:
  setup();
  printf("%c \n",*cp);//a
  printf("%c \n",++*cp);//b 
        
  setup();
  printf("%c \n",*cp++);//a
        
  setup();
  printf("%c \n",*(cp + 1));//f

  setup();
  printf("%c \n",++*cp++);//b

  setup();
  printf("%c \n",++*++cp);//g

}

4. 指针与字符串

字符串指针->指向的是字符串第一个字符的内存地址;
字符串都是以"\0"结尾;

计算字符串长度的demo:

// 计算字符串长度
int my_strlen(char *string){
    int length = 0; 
    while (*string++ != '\0') {
        length++;
    }
    return length;
}

int main(int argc, const char * argv[]) {

        char *name = "bill gates";  //指向字符串:指向的是第一个字符;
        printf("%s \n",name);//bill gates 

        unsigned long length = strlen(name);  // 字符长度 c系统自带函数
        printf("%lu \n",length);//10
     
        //自定义函数
        int myLength = my_strlen(name);
        printf("%d \n",myLength);//10
}

查找字符串中的某个字符demo

//查找字符串
int find_char(char **strings,char word,int count){ 
    char *string ;
    char character;
    int  num = 0;
    while ((string = *strings++) && num++ < count) {
        while ((character = *string++ ) != '\0') {
            if ( character == word ){
                return 1;
            }else{
                printf("继续查找……%c \n",character);
            }
        }
    }
    return 0;
}
int main(int argc, const char * argv[]) {

        char *s0 = "zero", s1 = "first", s2 = "second",s3 = "third",*s4 = " ";
     
        int total = 5;
        char *strs[total];
        strs[0] = s0;
        strs[1] = s1;
        strs[2] = s2;
        strs[3] = s3;
        strs[4] = s4;
    
        char word = 'a';    //查找词
        
        if ( find_char(strs, word,total) ){
            printf("find_char :%c \n",word);
        }else{
            printf("unfind_char :%c \n",word);
        }
}

5. 指针的运算常在数组中使用

算数运算:指针 +(-) 整数 ,指针 - 指针(只限于指向同一数组的指针)
单独的两个指针进行 加减乘除 是没有意义的

关系运算(只限于指向同一数组的指针): >, >=, <, <=, !=, ==

// 遍历数组
void logArray(char arr[],int count){
    for(int i = 0 ;i < count ; i++){
        printf("%d : %c \n",i,arr[i]);
    }
}
int main(int argc, const char * argv[]) {
   char *cp;
   int total = 5;
   char characters[total];
 /*cp < &characters[total];
  指针的逻辑比较
*/ 
    for (cp = & characters[0]; cp < &characters[total]; cp++) {
       *cp = 'a';
    }
        
    logArray(characters, total);
        
     char * cBegin = &characters[0];
     char * cEnd = &characters[total];
        
      for (cp = cEnd; cp >= cBegin; cp--) {
            *cp = 'b';
      }
        
     logArray(characters, total);

 /*long count = cEnd -cBegin;
 指针的加减,判断数组中元素间隔的距离
*/ 
      long count = cEnd -cBegin;
      printf("array count : %ld \n",count);
}

6. 指针和函数

  • 6.1 函数的返回值可以是指针
int* find_intValue(int arr[] ,int arr_count ,int value ){
    
    for (int i = 0 ; i<arr_count; i++) {
        if (arr[i] == value){
            return &arr[i];
        }
    }
    return  NULL;
}
int main(int argc, const char * argv[]) {
//  数组中查找指定元素,找到返回元素指针,否则返回 NUL
        int total = 5;
        int arr[total];
        for(int i = 0 ;i < total ; i++){
            arr[i] = i;
        }
        
        int *result = find_intValue(arr, total, 3);
        if (result != NULL) {
            printf("find Value \n");
        }else{
            
            printf("can not find Value \n");
        }
}
  • 6.2 函数的参数也可以是指针
// 数据交换
void swap_0(int a ,int b){
    int temp = a;
    a = b;
    b = temp;
}
void swap_1(int *a ,int *b){
    int temp = *a;
    *a = *b;
    *b = temp;
}
int main(int argc, const char * argv[]) {
   //交换
        int m = 10;
        int n = 20;
        
// 传值 操作,并不能完成数据的交换 
//参数把数值拷贝一份,函数内部进行了交换,不会影响到外部;
        printf("swap_0交换前 m= %d : n= %d \n",m,n);
        swap_0(m, n);
        printf("swap_0交换后 m= %d : n= %d \n",m,n);
// 传址 操作,才能完成数据的交换
//参数把地址拷贝一份,函数内部根据地址获取变量进行了交换,所以在内存中数据发生了交换
        printf("swap_1交换前 m= %d : n= %d \n",m,n);
        swap_1(&m, &n);
        printf("swap_1交换后 m= %d : n= %d \n",m,n); 

/*log结果:传值操作和传址操作是明显不同的
swap_0交换前 m= 10 : n= 20 
swap_0交换后 m= 10 : n= 20 
swap_1交换前 m= 10 : n= 20 
swap_1交换后 m= 20 : n= 10 
*/
}
©著作权归作者所有,转载或内容合作请联系作者
  • 序言:七十年代末,一起剥皮案震惊了整个滨河市,随后出现的几起案子,更是在滨河造成了极大的恐慌,老刑警刘岩,带你破解...
    沈念sama阅读 216,324评论 6 498
  • 序言:滨河连续发生了三起死亡事件,死亡现场离奇诡异,居然都是意外死亡,警方通过查阅死者的电脑和手机,发现死者居然都...
    沈念sama阅读 92,356评论 3 392
  • 文/潘晓璐 我一进店门,熙熙楼的掌柜王于贵愁眉苦脸地迎上来,“玉大人,你说我怎么就摊上这事。” “怎么了?”我有些...
    开封第一讲书人阅读 162,328评论 0 353
  • 文/不坏的土叔 我叫张陵,是天一观的道长。 经常有香客问我,道长,这世上最难降的妖魔是什么? 我笑而不...
    开封第一讲书人阅读 58,147评论 1 292
  • 正文 为了忘掉前任,我火速办了婚礼,结果婚礼上,老公的妹妹穿的比我还像新娘。我一直安慰自己,他们只是感情好,可当我...
    茶点故事阅读 67,160评论 6 388
  • 文/花漫 我一把揭开白布。 她就那样静静地躺着,像睡着了一般。 火红的嫁衣衬着肌肤如雪。 梳的纹丝不乱的头发上,一...
    开封第一讲书人阅读 51,115评论 1 296
  • 那天,我揣着相机与录音,去河边找鬼。 笑死,一个胖子当着我的面吹牛,可吹牛的内容都是我干的。 我是一名探鬼主播,决...
    沈念sama阅读 40,025评论 3 417
  • 文/苍兰香墨 我猛地睁开眼,长吁一口气:“原来是场噩梦啊……” “哼!你这毒妇竟也来了?” 一声冷哼从身侧响起,我...
    开封第一讲书人阅读 38,867评论 0 274
  • 序言:老挝万荣一对情侣失踪,失踪者是张志新(化名)和其女友刘颖,没想到半个月后,有当地人在树林里发现了一具尸体,经...
    沈念sama阅读 45,307评论 1 310
  • 正文 独居荒郊野岭守林人离奇死亡,尸身上长有42处带血的脓包…… 初始之章·张勋 以下内容为张勋视角 年9月15日...
    茶点故事阅读 37,528评论 2 332
  • 正文 我和宋清朗相恋三年,在试婚纱的时候发现自己被绿了。 大学时的朋友给我发了我未婚夫和他白月光在一起吃饭的照片。...
    茶点故事阅读 39,688评论 1 348
  • 序言:一个原本活蹦乱跳的男人离奇死亡,死状恐怖,灵堂内的尸体忽然破棺而出,到底是诈尸还是另有隐情,我是刑警宁泽,带...
    沈念sama阅读 35,409评论 5 343
  • 正文 年R本政府宣布,位于F岛的核电站,受9级特大地震影响,放射性物质发生泄漏。R本人自食恶果不足惜,却给世界环境...
    茶点故事阅读 41,001评论 3 325
  • 文/蒙蒙 一、第九天 我趴在偏房一处隐蔽的房顶上张望。 院中可真热闹,春花似锦、人声如沸。这庄子的主人今日做“春日...
    开封第一讲书人阅读 31,657评论 0 22
  • 文/苍兰香墨 我抬头看了看天上的太阳。三九已至,却和暖如春,着一层夹袄步出监牢的瞬间,已是汗流浃背。 一阵脚步声响...
    开封第一讲书人阅读 32,811评论 1 268
  • 我被黑心中介骗来泰国打工, 没想到刚下飞机就差点儿被人妖公主榨干…… 1. 我叫王不留,地道东北人。 一个月前我还...
    沈念sama阅读 47,685评论 2 368
  • 正文 我出身青楼,却偏偏与公主长得像,于是被迫代替她去往敌国和亲。 传闻我的和亲对象是个残疾皇子,可洞房花烛夜当晚...
    茶点故事阅读 44,573评论 2 353

推荐阅读更多精彩内容

  • 指针是C语言中广泛使用的一种数据类型。 运用指针编程是C语言最主要的风格之一。利用指针变量可以表示各种数据结构; ...
    朱森阅读 3,440评论 3 44
  • C语言是面向过程的,而C++是面向对象的 C和C++的区别: C是一个结构化语言,它的重点在于算法和数据结构。C程...
    小辰带你看世界阅读 942评论 0 6
  • 1. 变量 不同类型的变量在内存中占据不同的字节空间。 内存中存储数据的最小基本单位是字节,每一个字节都有一个内存...
    C语言学习阅读 1,282评论 0 4
  • Swift1> Swift和OC的区别1.1> Swift没有地址/指针的概念1.2> 泛型1.3> 类型严谨 对...
    cosWriter阅读 11,096评论 1 32
  • 前言:复杂类型说明 要了解指针,多多少少会出现一些比较复杂的类型,所以我先介绍一下如何完全理解一个复杂类型,要理解...
    有理想有暴富的小青年阅读 586评论 0 4