C-指针

指针:

  • 解决代码块与代码块之间的数据传递
  • 一个变量的地址称为该变量的指针

指针变量:

  • 用来存放另一个变量的地址的变量
  • 指针变量的类型由指向的那个变量的类型决定
  • 定义指针变量的时候必须赋初值,如果暂时没有初值就赋值NULL(0),没有被初始化的指针被称为失控指针(野指针)
  • 内存地址 0 有特别重要的意义,它表明该指针不指向一个可访问的内存位置
  • 指针变量只能存地址
  • 指针变量本身永远只占据8个字节的内存空间(64位系统)

*&

  • *用于定义指针变量,标识该变量是一个指针变量
  • *除了定义指针变量外,都是访问指针变量中可用地址的值
  • &是取一个变量的地址

一.指针的算术运算

C 指针是一个用数值表示的地址。因此,您可以对指针执行算术运算

我们喜欢使用指针代替数组,因为变量指针可以递增,而数组不能递增,数组可以看成一个指针常量

数组名并不是一个变量,没有分配内存空间,指针变量是有内存空间

定义一个数组,系统会分配内存空间,可以存值

定义一个指针变量,只为变量本身分配分配8个字节内存空间,不会为他分配可以存值的内存空间,无法存值

1.递增一个指针(递减一个指针同理)

//递增变量指针,以便顺序访问数组中的每一个元素
#include <stdio.h>
 
const int MAX = 3;
 
int main (){
   int  var[] = {10, 100, 200};
   int  i, *ptr;
 
   /* 指针中的数组地址 */
   ptr = var;
   for ( i = 0; i < MAX; i++){
 
      printf("存储地址:var[%d] = %x\n", i, ptr );
      printf("存储值:var[%d] = %d\n", i, *ptr );
 
      /* 移动到下一个位置 */
      ptr++;
   }
   return 0;
}

//运行结果
存储地址:var[0] = bf882b30
存储值:var[0] = 10
存储地址:of var[1] = bf882b34
存储值: var[1] = 100
存储地址:of var[2] = bf882b38
存储值:var[2] = 200

2.指针的比较

  • 指针可以用关系运算符进行比较,如 ==、< 和 >。

  • 如果 p1 和 p2 指向两个相关的变量,比如同一个数组中的不同元素,则可对 p1 和 p2 进行大小比较。

//只要变量指针所指向的地址小于或等于
//数组的最后一个元素的地址 &var[MAX - 1]
//则把变量指针进行递增
#include <stdio.h>
 
const int MAX = 3;
 
int main (){
   int  var[] = {10, 100, 200};
   int  i, *ptr;
 
   /* 指针中第一个元素的地址 */
   ptr = var;
   i = 0;
   while ( ptr <= &var[MAX - 1] ) {
 
      printf("Address of var[%d] = %x\n", i, ptr );
      printf("Value of var[%d] = %d\n", i, *ptr );
 
      /* 指向上一个位置 */
      ptr++;
      i++;
   }
   return 0;
}

//运行结果
Address of var[0] = bfdbcb20
Value of var[0] = 10
Address of var[1] = bfdbcb24
Value of var[1] = 100
Address of var[2] = bfdbcb28
Value of var[2] = 200

二.指针数组

int *ptr[MAX];把 ptr 声明为一个数组,由 MAX 个整数指针组成。因此,ptr 中的每个元素,都是一个指向 int 值的指针

#include <stdio.h>
 
const int MAX = 3;
 
int main (){
   int  var[] = {10, 100, 200};
   int i, *ptr[MAX];
 
   for ( i = 0; i < MAX; i++){

      ptr[i] = &var[i]; /* 赋值为整数的地址 */
   }
   for ( i = 0; i < MAX; i++) {

      printf("Value of var[%d] = %d\n", i, *ptr[i] );
   }
   return 0;
}

//运行结果
Value of var[0] = 10
Value of var[1] = 100
Value of var[2] = 200

指针的一些复杂说明:

三.指向指针的指针

  • 指向指针的指针int **变量名;是一种多级间接寻址的形式,或者说是一个指针链。

  • 通常,一个指针包含一个变量的地址。当我们定义一个指向指针的指针时,第一个指针包含了第二个指针的地址,第二个指针指向包含实际值的位置。

//当一个目标值被一个指针间接指向到另一个指针时
//访问这个值需要使用两个星号运算符
#include <stdio.h>
 
int main (){
   int  var;
   int  *ptr;
   int  **pptr;

   var = 3000;

   /* 获取 var 的地址 */
   ptr = &var;

   /* 使用运算符 & 获取 ptr 的地址 */
   pptr = &ptr;

   /* 使用 pptr 获取值 */
   printf("Value of var = %d\n", var );
   printf("Value available at *ptr = %d\n", *ptr );
   printf("Value available at **pptr = %d\n", **pptr);

   return 0;
}

//运行结果
Value of var = 3000
Value available at *ptr = 3000
Value available at **pptr = 3000

四.传递指针给函数

C 语言允许您传递指针给函数,只需要简单地声明函数参数为指针类型即可。

#include <stdio.h>
 
/* 函数声明 */
double getAverage(int *arr, int size);
 
int main (){
   /* 带有 5 个元素的整型数组  */
   int balance[5] = {1000, 2, 3, 17, 50};
   double avg;
 
   /* 传递一个指向数组的指针作为参数 */
   avg = getAverage( balance, 5 ) ;
 
   /* 输出返回值  */
   printf("Average value is: %f\n", avg );
    
   return 0;
}

double getAverage(int *arr, int size){
  int    i, sum = 0;       
  double avg;          
 
  for (i = 0; i < size; ++i)
  {
    sum += arr[i];
  }
 
  avg = (double)sum / size;
 
  return avg;
}

//运行结果
Average value is: 214.40000

五.从函数返回指针

  • C 不支持在调用函数时返回局部变量的地址,除非定义局部变量为 static 变量。

  • 因为局部变量是存储在内存的栈区内,当函数调用结束后,局部变量所占的内存地址便被释放了,因此当其函数执行完毕后,函数内的变量便不再拥有那个内存地址,所以不能返回其指针。

  • 除非将其变量定义为 static 变量,static 变量的值存放在内存中的静态数据区,不会随着函数执行的结束而被清除,故能返回其地址。

//生成 10 个随机数,并使用表示指针的数组名(即第一个数组元素的地址)来返回它们
#include <stdio.h>
#include <time.h>
#include <stdlib.h> 
 
/* 要生成和返回随机数的函数 */
int * getRandom( ){
   static int  r[10];
   int i;
 
   /* 设置种子 */
   srand( (unsigned)time( NULL ) );
   for ( i = 0; i < 10; ++i){
      r[i] = rand();
      printf("%d\n", r[i] );
   }
 
   return r;
}


 
/* 要调用上面定义函数的主函数 */
int main (){
   /* 一个指向整数的指针 */
   int *p;
   int i;
 
   p = getRandom();
   for ( i = 0; i < 10; i++ ){
       printf("*(p + [%d]) : %d\n", i, *(p + i) );
   }
 
   return 0;
}
  • 计算机并不能产生真正的随机数,而是已经编写好的一些无规则排列的数字存储在电脑里

  • 把这些数字划分为若干相等的N份,并为每份加上一个编号用srand()函数获取这个编号

  • 然后rand()就按顺序获取这些数字,当srand()的参数值固定的时候,rand()获得的数也是固定的

  • 所以一般srand的参数用time(NULL),因为系统的时间一直在变,所以rand()获得的数也就一直在变,相当于是随机数了。

六.函数指针

https://www.jianshu.com/writer#/notebooks/29146076/notes/41287791/preview

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

推荐阅读更多精彩内容