C语言指针(1)

简介: C语言指针(1)

指针定义

1. 指针是一个值为内存地址的变量。

2. 指针本质上是地址,是计算机存放数据的空间。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
  int a = 1;
  printf("%p", &a);
  return 0;
}
//%p用来打印地址(16进制形式打印)。
//整形变量a占据4个字节,取出的是第一个字节的地址(较小的)。
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
  int pooh = 5;
  int* ptr = &pooh;
}
//ptr指向了pooh。
//ptr是变量,&pooh是常量。
//ptr的值是pooh的地址。

指针的声明

1. 指针使用之前需要声明。

int a;
int* pa=&a;
//int* 说明指针的类型
//int 说明指针指向变量的类型
//* 说明这是一个指针
//pa 说明了指针的名字

解引用操作

1. 指针类型决定了在进行解引用操作时访问的空间大小。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
  int a = 20;
  int* pa = &a;//创建指针变量pa来存放地址
  printf("%d", *pa);//*是解引用操作符,*pa==a
  return 0;
}

泛型指针

1. 可以接收任意类型的地址,但是不能进行加减运算和解引用操作。

2. 用于存放未知类型数据的地址。

3. 用于接收存储,不能对其进行操作。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
  int a = 20;
  void* pa = &a;
  return 0;
}

const 保护

const 修饰普通变量

1.  const表示常属性,普通变量被修饰后,就不能再被修改。

2.  普通变量被修饰后,可以通过对指针解引用的方式来修改。

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
  const int a = 20;//a变成了常变量
  a = 10;//这一步报错,a的内容不能改变
  return 0;
}


#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
  const int a = 20;
  int* pa = &a;
  *pa = 10;//通过解引用来修改常变量的值
  printf("%d", a);//10
  return 0;
}

const 修饰指针变量

const 如果放在 *  的左边:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
  const int a = 20;
    int b = 10;
  int const * pa = &a;
    //const放在*左边,修饰* pa,使得无法改变* pa(20),但可以改变指针指向的对象(&a改成&b)。
  *pa = 10;//报错
    pa = &b;//正确
  printf("%d", *pa);//10
  return 0;
}

const 如果放在 *  的右边:

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
int main()
{
  const int a = 20;
    int b = 10;
  int* const pa = &a;
    //const放在*右边,修饰pa,使得无法改变pa(&a),但可以改变*pa(20)。
  *pa = 10;//正确
    pa = &b;//报错
  printf("%d", a);//10
  return 0;
}

指针运算

1. 指针与整数之间的运算,实际上要看指针指向的数据类型。

2. 指针指向的数据类型决定了指针的步长。

指针与整数运算  

#include <stdio.h>
//指针+-整数
int main()
{
    int arr[10] = {1,2,3,4,5,6,7,8,9,10};
    int* p = &arr[0];
    int i = 0;
    int sz = sizeof(arr)/sizeof(arr[0]);
    for(i=0; i<sz; i++)
    {
        printf("%d ", *(p+i));//(p+i)这⾥就是指针+整数,实际上是地址运算。
    }
    return 0;
}

 指针与指针比较                                                                            

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
//地址之间进行比较
int main()
{
  int arr1[10] = { 0 };
  int* p = arr1;
  int sz = sizeof(arr1) / sizeof(arr1[0]);
  while (p < sz + arr1)//地址之间也能进行比较
  {
    printf("%d", *p);
    p++;
  }
  return 0;
}

野指针  

1. 未初始化的指针就是野指针,野指针可以指向任何地方,可能会造成非法访问内存地址。

2. 野指针不会直接引发错误,操作野指针指向的内存区域才会出问题。

3. 尽量避免野指针的形成。

int* p;//p未初始化,为野指针,指向任意值。

野指针成因

指针未初始化                                                                                                                    

#include <stdio.h>
int main()
{
  int* p;//局部变量指针p未初始化,默认为随机值,即生成野指针。
  *p = 20;//不能对野指针进行解引用赋值操作。
  return 0;
}


指针越界访问

#include <stdio.h>
int main()
{
  int arr[10] = { 0 };
  int* p = &arr[0];
  int i = 0;
  for (i = 0; i <= 11; i++)
  {
    *(p++) = i;//当指针指向的范围超出数组arr的范围时,p就是野指针,直接报错。
  }
  return 0;
}

指针释放后未置空  

int main()
{
  int *p = NULL;
  p = malloc(10 * sizeof(int));
  if (p==NULL)  //开辟内存失败
  {
    exit(1);
  }
    else  //成功开辟内存,可以操作内存。
    {
      free(p);//释放指针p指向的空间后,此时指针p任然存在,只不过指向了无效空间。
      p = NULL;//为了防止指针p形成野指针,就把其赋值NULL。
      return 0;
    }
}

空指针

1. 一个指针不指向任何数据,我们就称之为空指针,空指针用NULL表示。


2. 如果明确知道指针指向哪里,就直接赋值地址,如果不知道指针应该指向哪里,可以给指针赋值NULL.


3. NULL 是C语言中定义的⼀个标识符常量,值是0,地址也是0,这个地址是无法使用的,读写该地址会报错。所以在解引用之前,必须确保它不是一个NULL指针。


4. 我们常用的动态内存开辟函数,如malloc,calloc,realloc,如果它们开辟动态内存失败就会返回空指针,所以动态开辟函数后,都要判断是否开辟成功。

#include <stdio.h>//NULL是标准库里面的内容
int main()
{
  int num = 10;
  int* p1 = &num;
  int* p2 = NULL;
  return 0;
}
#include <stdio.h>
#include <stdlib.h>
int main()
{
    int num = 0;
    scanf("%d", &num);
    int arr[num] = {0};
    int* ptr = (int*)malloc(num*sizeof(int));//开辟一个(4*num)大小的空间
    if(NULL != ptr)//判断ptr指针是否为空
    {
        int i = 0;
        for(i=0; i<num; i++)
        {
            *(ptr+i) = 0;
        }
    }
    free(ptr);//释放ptr所指向的动态内存
    ptr = NULL;//避免重复释放
    return 0;
}

assert 断言

1. assert()用来判断程序是否符合指定条件,如果不符合,就报错并终止程序运行。


2. 需要引入<assert.h>头文件。


3. 如果已经确认程序没有问题,就不需要再做断言,可以在 #include 语句的前面,定义⼀个宏 NDEBUG ,那么assert()将不会发挥作用。

#define _CRT_SECURE_NO_WARNINGS
#include <assert.h>
int main()
{
  int a = 20;
  int* pa = &a;
  int* pb = NULL;
  assert(pb != NULL);//报错,退出程序
}
#define NDEBUG
#include <assert.h>

传值调用和传址调用

1. 传址调用,可以让函数和主调函数之间建立真正的联系,在函数内部可以修改主调函数中的变量。

2. 如果函数中只是需要主调函数中的变量值来实现计算,就可以采用传值调用;

3. 如果函数内部要修改主调函数中的变量的值,就需要传址调用。

传值调用

1. 实参传递给形参的时候,形参会单独创建⼀份临时空间来接收实参,对形参的修改不影响实参。

#include <stdio.h>
void Swap1(int x, int y)
{
  int tmp = x;
  x = y;
  y = tmp;
}
int main()
{
  int a = 0;
  int b = 0;
  scanf("%d %d", &a, &b);
  printf("交换前:a=%d b=%d\n", a, b);
  Swap1(a, b);
  printf("交换后:a=%d b=%d\n", a, b);
  return 0;
}
//没有实现效果

传址调用

1. 将main函数中将a和b的地址传递给Swap函数,Swap 函数里边通过地址,间接操作main函数中的a和b,达到交换的效果。

#include <stdio.h>
void Swap2(int* px, int* py)
{
  int tmp = 0;
  tmp = *px;
  *px = *py;
  *py = tmp;
}
int main()
{
  int a = 0;
  int b = 0;
  scanf("%d %d", &a, &b);
  printf("交换前:a=%d b=%d\n", a, b);
  Swap2(&a, &b);
  printf("交换后:a=%d b=%d\n", a, b);
  return 0;
}

致谢

 感谢您花时间阅读这篇文章!如果您对本文有任何疑问、建议或是想要分享您的看法,请不要犹豫,在评论区留下您的宝贵意见。每一次互动都是我前进的动力,您的支持是我最大的鼓励。期待与您的交流,让我们共同成长,探索技术世界的无限可能!

相关文章
|
2月前
|
C语言
【c语言】指针就该这么学(1)
本文详细介绍了C语言中的指针概念及其基本操作。首先通过生活中的例子解释了指针的概念,即内存地址。接着,文章逐步讲解了指针变量的定义、取地址操作符`&`、解引用操作符`*`、指针变量的大小以及不同类型的指针变量的意义。此外,还介绍了`const`修饰符在指针中的应用,指针的运算(包括指针加减整数、指针相减和指针的大小比较),以及野指针的概念和如何规避野指针。最后,通过具体的代码示例帮助读者更好地理解和掌握指针的使用方法。
52 0
|
15天前
|
存储 NoSQL 编译器
【C语言】指针的神秘探险:从入门到精通的奇幻之旅 !
指针是一个变量,它存储另一个变量的内存地址。换句话说,指针“指向”存储在内存中的某个数据。
69 3
【C语言】指针的神秘探险:从入门到精通的奇幻之旅 !
|
15天前
|
存储 编译器 C语言
【C语言】指针大小知多少 ?一场探寻C语言深处的冒险 !
在C语言中,指针的大小(即指针变量占用的内存大小)是由计算机的体系结构(例如32位还是64位)和编译器决定的。
43 9
|
15天前
|
安全 程序员 C语言
【C语言】指针的爱恨纠葛:常量指针vs指向常量的指针
在C语言中,“常量指针”和“指向常量的指针”是两个重要的指针概念。它们在控制指针的行为和数据的可修改性方面发挥着关键作用。理解这两个概念有助于编写更安全、有效的代码。本文将深入探讨这两个概念,包括定义、语法、实际应用、复杂示例、最佳实践以及常见问题。
40 7
|
26天前
|
存储 C语言
C语言如何使用结构体和指针来操作动态分配的内存
在C语言中,通过定义结构体并使用指向该结构体的指针,可以对动态分配的内存进行操作。首先利用 `malloc` 或 `calloc` 分配内存,然后通过指针访问和修改结构体成员,最后用 `free` 释放内存,实现资源的有效管理。
92 13
|
19天前
|
存储 程序员 编译器
C 语言数组与指针的深度剖析与应用
在C语言中,数组与指针是核心概念,二者既独立又紧密相连。数组是在连续内存中存储相同类型数据的结构,而指针则存储内存地址,二者结合可在数据处理、函数传参等方面发挥巨大作用。掌握它们的特性和关系,对于优化程序性能、灵活处理数据结构至关重要。
|
19天前
|
算法 C语言
C语言中的文件操作技巧,涵盖文件的打开与关闭、读取与写入、文件指针移动及注意事项
本文深入讲解了C语言中的文件操作技巧,涵盖文件的打开与关闭、读取与写入、文件指针移动及注意事项,通过实例演示了文件操作的基本流程,帮助读者掌握这一重要技能,提升程序开发能力。
60 3
|
20天前
|
存储 算法 程序员
C 语言指针详解 —— 内存操控的魔法棒
《C 语言指针详解》深入浅出地讲解了指针的概念、使用方法及其在内存操作中的重要作用,被誉为程序员手中的“内存操控魔法棒”。本书适合C语言初学者及希望深化理解指针机制的开发者阅读。
|
26天前
|
存储 C语言 开发者
C 语言指针与内存管理
C语言中的指针与内存管理是编程的核心概念。指针用于存储变量的内存地址,实现数据的间接访问和操作;内存管理涉及动态分配(如malloc、free函数)和释放内存,确保程序高效运行并避免内存泄漏。掌握这两者对于编写高质量的C语言程序至关重要。
49 11
|
19天前
|
程序员 C语言
C语言中的指针既强大又具挑战性,它像一把钥匙,开启程序世界的隐秘之门
C语言中的指针既强大又具挑战性,它像一把钥匙,开启程序世界的隐秘之门。本文深入探讨了指针的基本概念、声明方式、动态内存分配、函数参数传递、指针运算及与数组和函数的关系,强调了正确使用指针的重要性,并鼓励读者通过实践掌握这一关键技能。
33 1