初识指针&认识字符串

本文介绍了C语言中的指针概念,包括指针的定义、指针变量、通过指针访问和修改变量、指针算术运算以及NULL指针的使用。此外,还讲解了指针与数组的关系,如何通过指针操作数组,以及指针在函数中的应用,如传址调用。最后,简述了C语言中字符串的定义和常见操作,如strlen、strcpy等函数的使用。
摘要由CSDN通过智能技术生成

本人C语言云互助授课课件,第一节课,做的很细心,供大家学习指针进行参考👻👻👻

1.初识指针🧐

1.1指针是什么?😕

理解的前提:首先我们要知道计算机中的数据都是存放在存储器中,对于正在执行的程序,其指令和数据一般存放在内存上,在c语言(或者计算机中)不同类型的数据所占用的字节数不同。例如char型数据在内存中占1字节,int占4个字节(对于32位编译环境)。同时我们为了正确去访问这些数据,就必须对每个字节编号,类似门牌、身份证这种,每个字节对应的编号唯一。同理也就可以根据编号找到某个字节所存放的数据。

1个字节等于8位哈 1B = 8bit

所以什么是指针?指针也就是内存地址,通俗讲就是上面说的对于内存中字节的编号,也可以叫做是地址


🐾插入一条知识点:

  • 取地址运算符&:获得变量的地址

👀下面看一段代码:

#include <stdio.h>

int main ()
{
    int testIntValue = 8;
    char testCharValue = 'a';
    int *pointInt = NULL;              // 定义一个整型数据的指针变量
    char *pointChar = NULL;			// 定义一个字符型数据的指针变量

    pointInt = &testIntValue;    //取地址赋值给对应类型指针
    pointChar = &testCharValue;	 //同理

   printf("testIntValue 变量的地址: %p\n", pointInt);
   printf("testCharValue 变量的地址: %p\n", pointChar);
   return 0;
}

运行结果:

testIntValue 变量的地址: 000000000061FE0C
testCharValue 变量的地址: 000000000061FE0B

**注意:**😲

  • 要记住,上面的地址只是一个字节的编号。所以对于testIntValue这个变量的值8并不是都存在了其中。这里若int位4个字节,则数值8是一共要占4个字节,也就是四个地址。通俗理解住四间房
  • 我们把变量所占存储空间的首地址成为变量的地址,所以通过pointInt这个指针能访问到testIntValue变量所对应的值8
  • 其实变量名、函数名这些只是地址的一种助记符,是对数据存储空间的一种抽象。

1.2指针变量🏃‍♂️

既然指针就是内存地址,那么指针变量就是用来存放内存地址的变量。就像其他变量或常量一样,您必须在使用指针存储其他变量地址之前,对其进行声明。指针变量声明的一般形式为:

type *var_name;
  • type 类型关键字,即指针的基类型。代表指针变量要指向的变量的数据类型。
  • var_name 指针的变量名。
  • 这里*用来说明他是一个指针类型变量

1.3指针的基本操作😴

1.3.1 通过指针访问变量的值🙆‍♂️

前面提到过,指针变量存储的是变量的地址,通过指针访问变量的需要使用*运算符,即间接访问运算符(indirection operator)也叫解引用运算符。以下是一个例子:

#include <stdio.h>

int main()
{
    int var = 10;
    int *ptr = &var;   // ptr指向var变量的地址

    printf("var的值:%d\n", var);            // 输出10
    printf("*ptr的值:%d\n", *ptr);          // 输出10
    printf("ptr指针所指向地址的变量的值:%d\n", *ptr);  // 输出10
    printf("var变量的地址:%p\n", &var);     // 输出var的地址
    printf("ptr指针存储的地址:%p\n", ptr);  // 输出ptr所存储的地址

    return 0;
}

输出结果:

var的值:10
*ptr的值:10
ptr指针所指向地址的变量的值:10
var变量的地址:0x7ffcc2af3aa8
ptr指针存储的地址:0x7ffcc2af3aa8

可以看到,通过*ptr访问指针所指向的变量,也就是var的值,输出结果是10。注意,*ptr这种写法实际上是在使用指针变量ptr存储的地址去访问其所指向的变量var的值,而不是访问指针本身的值。

1.3.2 修改指针所指向的变量的值🎐

通过指针修改变量的值,也需要使用间接访问运算符。例如:

#include <stdio.h>

int main()
{
    int var = 10;
    int *ptr = &var;   // ptr指向var变量的地址

    printf("var的值:%d\n", var);       // 输出10
    *ptr = 20;                           // 使用指针修改var的值
    printf("var的值:%d\n", var);       // 输出20

    return 0;
}

输出结果:

var的值:10
var的值:20

1.3.3 指针的算术运算😋

指针在内存中也是以地址的形式存储,因此可以进行指针的算术运算。常见的指针运算有以下几种:

  • 指针加上一个整数:指针会向后移动多少个字节,移动的大小取决于指针所指向的变量的数据类型。例如,ptr+1会使指针ptr向后移动4个字节,因为在32位的机器上,一个int类型占4个字节。
  • 指针减去一个整数:同理,指针会向前移动多少个字节,移动的大小取决于指针所指向的变量的数据类型。
  • 两个指针相减:两个指针相减,得到的结果为它们之间相隔的元素个数,这里的元素个数也是取决于指针所指向的变量的数据类型。

需要注意的是,在指针运算中,不要访问非法的内存地址,否则会导致程序崩溃或出现其他问题。

下面看一个指针运算的例子:

#include <stdio.h>

int main ()
{
    int arr[] = {10, 20, 30, 40, 50};
    int *ptr1 = &arr[0], *ptr2 = &arr[4];
    int n;

    printf("ptr2 - ptr1 = %td\n", ptr2 - ptr1);  //输出为4,因为两个指针相差4个元素
    n = ptr2 - ptr1;   // n = 4;
    
    printf("*ptr1 = %d\n", *ptr1);   //输出10
    printf("*(ptr1+2) = %d\n", *(ptr1+2));  //输出30

    printf("*ptr2 = %d\n", *ptr2);   //输出50
    printf("*(ptr2-2) = %d\n", *(ptr2-2));  //输出30
    
    

    return 0;
}

输出结果:

ptr2 - ptr1 = 4
*ptr1 = 10
*(ptr1+2) = 30
*ptr2 = 50
*(ptr2-2) = 30

从输出结果中可以看出,ptr2 - ptr1的值为4,即ptr2ptr1之间相差4个元素;通过ptr1+2可以访问到arr[2]元素的值30,通过ptr2-2可以访问到arr[2]元素的值30。

指针运算可以灵活地访问数组元素,非常适合数组的遍历和访问。但需要注意的是,指针运算必须要保证不访问非法的内存地址,否则会导致程序出现错误。

1.3.4 NULL指针😫

即空指针。在变量声明的时候,如果没有确切的地址可以赋值,为指针变量赋一个 NULL 值是一个良好的编程习惯。

NULL 指针是一个定义在标准库中的值为零的常量。

#include <stdio.h>
 
int main ()
{
   int  *ptr = NULL;
 
   printf("ptr 的地址是 %p\n", ptr  );
 
   return 0;
}

运行结果:

ptr 的地址是 0x0

在大多数的操作系统上,程序不允许访问地址为 0 的内存,因为该内存是操作系统保留的。然而,内存地址 0 有特别重要的意义,它表明该指针不指向一个可访问的内存位置。但按照惯例,如果指针包含空值(零值),则假定它不指向任何东西。

如需检查一个空指针,您可以使用 if 语句,如下所示:

if(ptr)     /* 如果 p 非空,则完成 */
if(!ptr)    /* 如果 p 为空,则完成 */

1.3.4部分来自菜鸟教程 C指针节 C 中的 NULL 指针 板块

1.4指针和数组🤐

数组名实际上就是数组元素的首地址,因此可以将数组名赋值给指针变量。例如:

int arr[3] = {10, 100, 200};
int *ptr = arr;

在上述代码中,arr是一个整型数组,我们定义了一个指向整型数据的指针变量ptr。可以看出,我们将arr的地址赋值给了ptr,因此ptr现在指向数组arr的第一个元素。

可以通过使用数组名和指针变量来访问数组中的元素。例如:

printf("第一个元素的值是 %d\n", *ptr );
printf("第二个元素的值是 %d\n", *(ptr+1) );
printf("第三个元素的值是 %d\n", *(ptr+2) );

输出结果:

第一个元素的值是 10
第二个元素的值是 100
第三个元素的值是 200

再次提示这里使用了解引用运算符*,因为指针本身存储的是地址,需要通过解引用运算符*来访问指向的实际数据。同时,指针也可以进行算术运算,例如指向数组中的下一个元素,可以使用指针加1来实现。这就是上面代码中*(ptr+1)的意义。结合上面指针的算术运算理解

1.5指针和函数😥

指针还可以作为函数的参数来传递地址,从而达到在函数内部改变外部变量的值的目的。例如:

#include <stdio.h>

void swap(int *x, int *y) {
    int temp = *x;
    *x = *y;
    *y = temp;
}

int main() {
    int a = 100;
    int b = 200;
    printf("交换前:a = %d, b = %d\n", a, b);
    swap(&a, &b);
    printf("交换后:a = %d, b = %d\n", a, b);
    return 0;
}

输出结果:

交换前:a = 100, b = 200
交换后:a = 200, b = 100

在上述代码中,我们定义了一个swap()函数,该函数接受两个指向整型数据的指针变量xy作为参数,通过指针交换xy所指向的数据。在main()函数中,我们定义了两个整型变量ab,然后调用了swap()函数,并将ab的地址作为参数传递给该函数,从而实现了在函数内部交换ab的值的目的。

**思考/回忆:**如果将上面代码改成下面,则运行结果是什么?为什么?

这里回答有奖励哦!!!大家快响应,理一理我!!!✨🎉🍗

#include <stdio.h>

void swap(int x, int y) {
    int temp = x;
    x = y;
    y = temp;
}

int main() {
    int a = 100;
    int b = 200;
    printf("交换前:a = %d, b = %d\n", a, b);
    swap(a, b);
    printf("交换后:a = %d, b = %d\n", a, b);
    return 0;
}

1.6 函数指针及其应用(慢慢琢磨)😡

函数指针是指向函数的指针变量,它可以用来存储函数的地址,进而通过该指针调用函数。函数指针在C语言中具有重要的应用,它可以用来实现回调函数、函数参数多态性等高级应用。

1.6.1 基本概念🥱

1.6.1.1 定义函数指针🏷

定义函数指针的一般形式为:

return_type (*pointer_name)(param_list);

其中,return_type为函数返回值类型,pointer_name为函数指针变量名,param_list为函数参数列表。

例如,定义一个返回int类型、带有两个int类型参数的函数指针变量可以这样写:

int (*p)(int, int);

1.6.1.2 函数指针的赋值☁

函数指针变量可以像其他指针变量一样赋值。下面的示例代码演示了如何将函数的地址赋值给函数指针变量:

#include <stdio.h>

int add(int a, int b)
{
    return a + b;
}

int main()
{
    int (*p)(int, int);
    p = add;  // 将函数add的地址赋值给函数指针变量p
    int result = p(2, 3);  // 通过函数指针调用函数
    printf("%d\n", result);  // 输出结果5
    return 0;
}

1.6.1.3 函数指针的使用✏

函数指针可以像函数名一样直接调用函数,也可以作为参数传递给其他函数。下面的示例代码演示了如何将函数指针作为参数传递给其他函数:

#include <stdio.h>

int add(int a, int b)
{
    return a + b;
}

int calculate(int (*p)(int, int), int a, int b)
{
    return p(a, b);
}

int main()
{
    int result = calculate(add, 2, 3);  // 将函数指针变量add作为参数传递给calculate函数
    printf("%d\n", result);  // 输出结果5
    return 0;
}

另外函数指针含有很多高级应用方式,比如回调函数、函数指针数组、函数指针作为函数参数、函数指针作为返回值、函数指针与结构体,理解这些你的档次将提升N个level,可以大大提高C语言程序的灵活性和可扩展性。(或许你就不是一个和我一样没有对象的野指针了😭😭😭

2. 字符串😨

毁灭吧,累了,简单整点字符串,睡觉了咩👻👻👻

在C语言中,字符串实际上是一个字符数组,由若干个字符组成,以\0(null字符)结尾。因此,字符串在C语言中是以字符数组的形式存储的。

2.1 字符串的定义🤕

字符串的定义有以下两种方式:

  • 使用字符数组定义字符串
char str[] = "Hello, world!";
  • 使用指针定义字符串
char *str = "Hello, world!";

需要注意的是,使用指针定义字符串时,字符串常量被存储在只读数据段,不允许修改。因此,如果需要修改字符串,应该使用字符数组定义。

2.2 字符串的常见操作😇

C语言提供了许多字符串操作函数,常见的有:

  • strlen():获取字符串长度。
  • strcpy():将一个字符串复制到另一个字符串中。
  • strcat():将两个字符串连接起来。
  • strcmp():比较两个字符串是否相等。
  • strchr():在一个字符串中查找某个字符第一次出现的位置。

下面是一些常见的字符串操作示例:

#include <stdio.h>
#include <string.h>

int main()
{
    char str1[20] = "Hello";
    char str2[20] = "World";
    char str3[20];

    // 获取字符串长度
    printf("str1长度: %ld\n", strlen(str1));

    // 复制字符串
    strcpy(str3, str1);
    printf("将str1复制到str3: %s\n", str3);

    // 连接字符串
    strcat(str1, str2);
    printf("将str2拼接到str1: %s\n", str1);

    // 比较字符串
    int cmp = strcmp(str1, str2);
    if (cmp == 0) {
        printf("str1等价str2\n");
    } else {
        printf("str1不等价str2\n");
    }

    // 查找字符
    char *pos = strchr(str1, 'l');
    printf("'l'在str1中位置: %ld\n", pos - str1);

    return 0;
}

输出结果为:

str1长度: 5
将str1复制到str3: Hello
将str2拼接到str1: HelloWorld
str1不等价str2
'l'在str1中位置:: 2

需要注意的是,在使用字符串操作函数时,应该确保目标字符串有足够的空间来存储结果。

就到这了,下次再说,下班!

谢谢大家,看到这大家辛苦了,有问题向我反馈哈🤩😍😘

  • 1
    点赞
  • 1
    收藏
    觉得还不错? 一键收藏
  • 打赏
    打赏
  • 0
    评论
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包

打赏作者

zhihong2002

你的鼓励将是我创作的最大动力

¥1 ¥2 ¥4 ¥6 ¥10 ¥20
扫码支付:¥1
获取中
扫码支付

您的余额不足,请更换扫码支付或充值

打赏作者

实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值