指针的概念

指针入门 ******

 int i = 123;
       //一般计算机中用16进制数来表示一个内存地址 
       printf("%#x\n",&i); 
       //int* int类型的指针变量  pointer指针  指针变量只能用来保存内存地址
       //用取地址符&i 把变量i的地址取出来 用指针变量pointer 保存了起来
       //此时我们可以说 指针pointer指向了 i的地址 
       int* pointer = &i;   
       printf("pointer的地址 = %#x\n",pointer);
       printf("*pointer的值%d\n",*pointer);
       *pointer = 456;//修改pointer的值
       printf("i的值是%d\n",i);
       system("pause"); 

由于pointer存的是i的内存地址,多以对pointer的操作就是对变量i的操作*pointer在等号左边就是赋值操作,在等号右边是取值操作

java zhong 两个值的交换操作
![IJUK6LYQGDJ_2]~D10%X0.png](http://upload-images.jianshu.io/upload_images/2648920-33ec6258097a0db3.png?imageMogr2/auto-orient/strip%7CimageView2/2/w/1240)

  • 指针常见错误
    • 声明了指针变量后 未初始化直接通过*p 进行赋值操作 运行时会报错
        • 未赋值的指针称为野指针
    • 指针类型错误 如int* p 指向了double类型的地址, 通过指针进行读取操作时,读取值会出错
#include<stdio.h>    
#include<stdlib.h>    
/**
*/
main(){  
         //野指针   指针使用之前要初始化 赋给它一个自己程序中声明的变量的地址
         //指针使用的时候要注意 int类型的指针要指向int类型的内存地址, double类型的指针要指向double类型的地址 ....
          //如果乱指会出bug 
         int i; 
         double d = 3.1415;
       int* pointer = &d;
       printf("pointer的值=%#x\n",pointer);
       printf("*pointer = %d\n",*pointer);
       system("pause"); 
       } 

指针的练习

Paste_Image.png
  • 值传递和引用传递(交换两个数的值)
    • 引用传递本质是把地址传递过去

    • 所有传递其实本质都是值传递,引用传递其实也是传递一个值,但是这个值是一个内存地址

        void swap(int* p, int* p2){
            int temp = *p;
            *p = *p2;
            *p2 = temp; 
        }
        main(){
            int i = 123;
            int j = 456;
            //将i, j的地址传递过去
            swap(&i,&j);
            printf("i = %d, j = %d", i, j);
        }
      
Paste_Image.png
  • 返回多个值
    • 把地址作为参数传入函数中,当函数执行完毕时,参数的值就已经被修改了
#include<stdio.h>    
#include<stdlib.h>    
/**
"*" 的几个含义   int*  声明一个int类型的指针变量
            x * y  乘法运算
            int* pointer;
            *pointer; 取出指针变量pointer 中保存的内存地址对应的内存中的值 
*/
 function(int* pointer, int* pointer2){
     *pointer *= 2;
     *pointer2 *=2;
    }
main(){    
      int i =1;
      int j = 2;
      //char c;
      function(&i,&j);
      printf("i = %d,j = %d\n",i,j);
       system("pause"); 
       } 

多级指针

  • int* p; int 类型的一级指针 int** p2; int 类型的二级指针

  • 二级指针变量只能保存一级指针变量的地址

  • 有几个* 就是几级指针 int*** 三级指针

  • 通过int类型三级指针 操作int类型变量的值 ***p

          int i = 123;
          //int类型一级指针 
          int* p = &i;
          //int 类型 二级指针 二级指针只能保存一级指针的地址 
          int** p2 = &p;
          //int 类型 三级指针  三级指针只能保存二级指针的地址 
          int*** p3 = &p2;
          //通过p3 取出 i的值
          printf("***p3 = %d\n", ***p3);
    
  • 多级指针案例 取出子函数中临时变量的地址

Paste_Image.png
#include<stdio.h>    
#include<stdlib.h>    
/**
多级指针 数星星  有几个星就是几级指针 取值通过三级指针拿到最初的变量的值 ***point3 
*/
main(){    
      int i = 123;
      //int类型的一级指针 
      int* pointer = &i;
      //int类型的二级指针 二级指针只能保存一级指针的地址 
      int** pointer2 = &pointer; 
      //int类型的三级指针 
      int*** pointer3 = &pointer2; 
      printf("***pointer3 = %d\n",***pointer3);
       system("pause"); 
       } 

数组和指针的关系

  • 数组占用的内存空间是连续的
  • 数组变量保存的是第0个元素地址,也就是首地址
  • *(p + 1):指针位移一个单位,一个单位是多少个字节,取决于指针的类型
#include<stdio.h>    
#include<stdlib.h>    
/**
数组实际上就是一块连续的内存空间 
*/
main(){
         
  // char array[] = {'a','b','c','d','\0'};
   int array[] = {1,2,3,4};
   printf("array[0]的地址%#x\n",&array[0]);
   printf("array[1]的地址%#x\n",&array[1]);
   printf("array[2]的地址%#x\n",&array[2]);
   printf("array[3]的地址%#x\n",&array[3]);
   printf("array的地址%#x\n",&array);
   //数组变量名的地址实际上是第一个元素的地址
   char* pointer = &array;
    //int* pointer = &array;
    char array2[] =  "hello from c"
//c语言当中的char类型的数组就是c语言当中的字符串,现在*pointer存的是数组的首地址,printf("%s\n",pointer2);是字符串的输出,所以从char数组的首地址开始输出字符串
   char* pointer2="hello from c";
   //printf("%s\n",pointer2);
   /*
   printf("*(pointer+0)=%c\n",*(pointer+0));
   printf("*(pointer+0)=%c\n",*(pointer+1));
   printf("*(pointer+0)=%c\n",*(pointer+2));
   printf("*(pointer+0)=%c\n",*(pointer+3));
   */
   printf("*(pointer+0)=%d\n",*(pointer+0));
   printf("*(pointer+1)=%d\n",*(pointer+1));
   printf("*(pointer+2)=%d\n",*(pointer+2));
   printf("*(pointer+3)=%d\n",*(pointer+3));
    
       system("pause"); 
       } 

指针的长度

  • 不管变量的类型是什么,它的内存地址的长度一定是相同的
  • 类型不同只决定变量占用的内存空间不同
  • 32位环境下,内存地址长度都是4个字节,所以指针变量长度只需4个字节即可
  • 区分指针类型是为了指针位移运算方便
#include<stdio.h>    
#include<stdlib.h>    
/**
32位操作系统地址总线是32位   4个字节的变量来保存32位操作系统的内存地址 1byte 8位  4*8=32 
32位操作系统 指针变量占4个字节
64位操作系统 指针变量占8个字节 
*/
main(){    
      int* pointer;
      double* pointerD; 
      printf("int类型的指针变量占%d个字节\n",sizeof(pointer));
      printf("double类型的指针变量占%d个字节\n",sizeof(pointerD));
       system("pause"); 
       } 

#include<stdio.h>    
#include<stdlib.h>    
/**
main函数获取子函数中临时变量的地址 
*/
function(int** pointer){
   int i = 123;
    *pointer = &i;  
    printf("i的地址%#x\n",&i);    
          }

main(){    
      int* pointer1;
      function(&pointer1);
      printf("pointer1的值%#x\n",pointer1);
       system("pause"); 
       } 

Paste_Image.png

堆栈概念 静态内存分配 动态内存分配

  • 栈内存
    • 系统自动分配
    • 系统自动销毁
    • 连续的内存区域
    • 向低地址扩展
    • 大小固定
    • 栈上分配的内存称为静态内存
  • 静态内存分配
  • 子函数执行完,子函数中的所有局部变量都会被销毁,内存释放,但内存地址不可能被销毁,只是地址上的值没了



#include<stdio.h>    
#include<stdlib.h>    
/**
栈内存 系统统一分配统一回收  
静态内存分配 栈内存大小固定的 内存地址是连续的 
*/
int* getData(){
     int array[] ={1,2,3,4,5};
     printf("%#x\n",&array);
     return &array;
     }
int* getData2(){
     int array[] ={5,4,3,2,1};
     printf("%#x\n",&array);
     return &array;
     }

main(){    
     int* pointer = getData();
     getData2();
     printf("%d,%d,%d\n",*(pointer+0),*(pointer+1),*(pointer+2));
     printf("%d,%d,%d\n",*(pointer+0),*(pointer+1),*(pointer+2));
     printf("%#x\n",pointer);
       system("pause"); 
       } 
  • 堆内存
    • 程序员手动分配
      • java:new
      • c:malloc
    • 空间不连续
    • 大小取决于系统的虚拟内存
    • C:程序员手动回收free
    • java:自动回收
    • 堆上分配的内存称为动态内存
#include<stdio.h>    
#include<stdlib.h>    
/**
java new对象就会申请一块堆内存
c   malloc memory allocation 内存分配 
c的堆内存 程序员手动申请手动释放  malloc
free 
申请一块堆内存 动态内存分配 
堆内存 不连续的 
堆内存大小不固定 取决机器的状态 
*/
main(){ 
        //malloc 接收的参数 申请内存大小 返回一个内存地址值 申请到的也是一块连续的内存空间   
      int* pointer = malloc(sizeof(int)*5);
      *(pointer+0) = 1;
      *(pointer+1) = 2;
      *(pointer+2) = 3;
      *(pointer+3) = 4;
      *(pointer+4) = 5;
      //C for 循环 循环的临时变量i 要先声明再使用 
      int i;
      for(i = 0;i<5;i++){
              printf("第%d个元素的值= %d\n",i,*(pointer+i));
              }
      free(pointer);
      printf("第一个元素的值%d\n",*(pointer+0));
       system("pause"); 
       } 

#学生管理系统#
#include<stdio.h>    
#include<stdlib.h>    
/**
保存班级人数
申请一块堆内存保存学生的学号
来了几个插班生
扩展一下堆内存
保存插班生的学号 
realloc re- 
*/
main(){ 
       printf("请输入班级的人数:");
       int count;
       scanf("%d",&count);
       //申请一块堆内存
       int* pointer = malloc(sizeof(int)*count);
       int i;
       for(i = 0;i<count;i++){
             printf("请输入第%d个学生的学号:",i+1);
             scanf("%d", pointer+i);
             }  
       for(i = 0;i<count;i++){
             printf("第%d个学生的学号是:%d\n",i+1,*(pointer+i));  
             } 
       printf("请输入插班生的人数:");
       //声明一个变量increment用来保存 插班生的人数 
       int increment;
       //接受用户的输入 
       scanf("%d",&increment);
       //重新申请一块足够大的内存 
       //如果 malloc申请到的内存后面还有足够的空间 realloc会在malloc申请的内存空间后继续申请足够大的内存空间
       //如果 malloc申请到的内存后面没有足够的空间 realloc会找到一块足够大的堆内存 并且把 malloc申请到的内存中的值复制过来 
      pointer = realloc(pointer,sizeof(int)*(count+increment));
      for(i = count;i<count+increment;i++){
             printf("请输入第%d个学生的学号:",i+1);
             scanf("%d", pointer+i);
            }
      for(i = count;i<count+increment;i++){
            printf("第%d个学生的学号是:%d\n",i+1,*(pointer+i));  
            }
       system("pause"); 
       } 

结构体

  • 结构体中的属性长度会被自动补齐,这是为了方便指针位移运算
  • 结构体中不能定义函数,可以定义函数指针
  • 程序运行时,函数也是保存在内存中的,也有一个地址
  • 结构体中只能定义变量
  • 函数指针其实也是变量,它是指针变量
  • 函数指针的定义 返回值类型(*变量名)(接收的参数);
  • 函数指针的赋值: 函数指针只能指向跟它返回值和接收的参数相同的函数
#include<stdio.h>    
#include<stdlib.h>    
/**
c结构体 类似java的class  struct来声明c的结构体 
结构体的大小大于等于结构体中每一变量的占字节数的和
 结构体的大小是最大的那个变量所占字节数的整数倍 
 C结构体中不能定义函数  
 
 函数指针的定义   返回值(*函数指针变量名字)(返回值); 
 -> 间接引用运算符   
*/
void study(){
           printf("good good study!\n");
           }
typedef struct Student{
      int age;  //8
      int score;  // 4
      char sex;   //1
      void(*studypointer)();
      } stud;
main(){    
 stud stu = {18,100,'f'};
 stu.studypointer = &study;
 stu.studypointer();
 struct Student* stuPointer = &stu;//结构体指针
 printf("*stuPointer.age = %d\n",(*stuPointer).age);
 (*stuPointer).sex ='m';
 printf("stu.sex = %c\n",stu.sex);
 printf("stuPointer->age = %d",stuPointer->age);
 //printf("stu.age = %hd\n",stu.age);
 //printf("stu.score = %d\n",stu.score);
 //printf("stu.sex = %c\n",stu.sex);
// printf("结构体student占%d个字节\n",sizeof(stu));
       system("pause"); 
       } 

联合体

  • 长度等于联合体中定义的变量当中最长的那个
  • 联合体只能保存一个变量的值
  • 联合体共用同一块内存
#include<stdio.h>    
#include<stdlib.h>    
/**
联合体占字节数取决于 其中成员 占内存空间最大的那一个 
*/
union u{
      int num; //4
      double d; //8
      }
main(){    
   union u u1;
   u1.num = 123;
   u1.d = 123.456;
   printf("union占%d个字节\n",sizeof(u1));
   printf("u1.num = %d\n",u1.num);
       system("pause"); 
       } 

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

推荐阅读更多精彩内容

  • 指针是C语言中广泛使用的一种数据类型。 运用指针编程是C语言最主要的风格之一。利用指针变量可以表示各种数据结构; ...
    朱森阅读 3,440评论 3 44
  • 1.语言中变量的实质 要理解C指针,我认为一定要理解C中“变量”的存储实质, 所以我就从“变量”这个东西开始讲起吧...
    金巴多阅读 1,768评论 0 9
  • 如何访问、如何引用、如何存储???? 问题:1、如何访问变量?通过变量名称来访问变量2、如何访问指针变量?通过指针...
    全無阅读 745评论 0 4
  • 前言:指针是 C语言一个重要概念,也是C 语言的一个重要特色。使程序简洁、紧凑、高效。指针乃是C之精华。 数据在内...
    潇湘候晨雪阅读 763评论 0 0
  • 制定目标是为了更好的指导自己的行动,而有效的行动才是成长的关键,它决定着我们能成为一个什么样的人。因此,制定目标是...
    剑侠火羽阅读 298评论 0 2