C语言__指针

本文详细介绍了C语言中的指针,包括变量和指针的关系、指针定义与初始化、指针运算符及其用途,如快速传值和修改实参。讨论了指针在遍历数组和字符串中的应用,以及与函数参数的交互。还提醒了常见的指针错误,并介绍了返回指针的函数和指向函数的指针的概念及用途。

摘要生成于 C知道 ,由 DeepSeek-R1 满血版支持, 前往体验 >

C语言__指针

变量和指针

通过变量名引用变量,由系统自动完成变量名和其存储地址之间的转换,称为变量的"直接引用"方式

首先将变量a的地址存放在另一个变量中,比如存放在变量b中,然后通过变量b来间接引用变量a,间接读写变量a的值。这就是"间接引用"。

指针的定义

一般形式:类名标识符  *指针变量名;
int *p;

float *q;

前面的类型标识符表示指针变量所指向的变量的类型,而且只能指向这种类型的变量
"*"是一个说明符,用来说明这个变量是个指针变量,是不能省略的,但它不属于变量名的一部分

指针的初始化

1.先定义后初始化
// 定义int类型的变量a
int a = 10;

// 定义一个指针变量p
int *p;

// 将变量a的地址赋值给指针变量p,所以指针变量p指向变量a
p = &a;


2.在定义的同时初始化
// 定义int类型的变量a
int a = 10;

// 定义一个指针变量p
// 并将变量a的地址赋值给指针变量p,所以指针变量p指向变量a
int *p = &a;

注意:指针变量没有明确的指明指向地址的时候,不能读写。(为了系统的安全,程序还没有分配指向内存的操作权限,一旦操作很可能引起系统的奔溃,因为强行使用会使别的正在使用该内存的程序崩坏)

指针运算符

// 指针变量p指向变量a  取地址运算符&
char *p = &a;

//将指针变量的指向内存值取出赋值给value  取地址指向内容*
char value = *p;

指针的用途

    快速传值

    修改实参

    实现函数多返回值

指针的学习解答

在同一种编译器环境下,一个指针变量所占用的内存空间是固定的。

指针变量要分类型,只能指向一种类型的变量,由编译器决定从指针变量处取出多少字节。不同数据类型的字节分配由不同的编译器决定

指针指向一维数组

由于数组名代表着数组的首地址,即a == &a[0];并且数组名是指针常量,不可以通过两个数组名(指针常量)来赋值【例】a = b;

使用指针遍历数组

// 定义一个int类型的数组
int a[4] = {1, 2, 3, 4};

// 定义一个int类型的指针,并指向数组的第0个元素
int *p = a; // *可以理解为,取以p内容为地址的变量 *p可以一起理解成一个int变量

int i;
for (i = 0; i < 4; i++) {
    // int value = *(p++); 指针不在指向数组的第一个元素,已经向下移动了一个逻辑单位

    // 利用指针运算符*取出数组元素的值
    int value = *(p+i);//注意的是:遍历完毕后,指针变量p还是指向a[0],因为p值一直没有变过
    
    printf("a[%d] = %d \n", i, value);
}
//指针+1在逻辑上是向后找到下一个元素,在物理地址上则根据不同过的数据类型相应的加上去
//【例】int类型在16位编译器下增加的是2个字节
//下图是在16位编译器环境下的情况。

引用一个数组元素可以有两种方法:

    下标法: 如a[i]

    指针法: 如*(p+i) 或 *(a+i)

数组、指针与函数参数

形参为指针,实参可以传指针和数组名(数组名本就是指针常量,是数组第一个元素的地址)

用数组名作为函数实参时,是把实参数组的首地址传递给形参数组,两个数组共同占用同一段内存空间,这样形参数组中的元素值发生变化就会使实参数组的元素值也同时变化

字符数组

一个字符串由一个或多个字符组成,因此我们可以用字符数组来存放字符串,不过在数组的尾部要加上一个空字符'\0'。

用指针遍历字符串的所有字符

// 定义一个指针p
char *p;

// 定义一个数组s存放字符串
char s[] = "mj";

// 指针p指向字符串的首字符'm'
p = s; // 或者 p = &s[0];

for (; *p != '\0'; p++) {
    printf("%c \n", *p);
}
//数组判停标志为‘\0’

指针指向字符串

1.定义一个字符串数组存放字符串,然后将数组首地址传给指针p,让p指向字符串的首字符。

2.也可以直接用指针指向一个字符串,省略定义字符数组这个步骤

    // 定义一个字符串,用指针s指向这个字符串
    char *s = "mj";
    
    // 使用strlen函数测量字符串长度
    int len = strlen(s);

   // 使用指针输出字符串
 char *s = "mj";
 printf("%s", s);

常见错误

1 char *s = "mj";
2 
3 *s = "like";
第3行代码犯了2个错误:
    第3行代码相当于把字符串"like"存进s指向的那一块内存空间,由第1行代码可以看出,s指向的是"mj"的首字符'm',也就是说s指向的一块char类型的存储空间,只有1个字节,要"like"存进1个字节的空间内,肯定内存溢出

    由第1行代码可以看出,指针s指向的是字符串常量"mj"!因此是不能再通过指针来修改字符串内容的!就算是*s = 'A'这样"看起来似乎正确"的写法也是错误的,因为s指向的一个常量字符串,不允许修改它内部的字符。

    char a[] = "lmj";定义的是一个字符串变量!

    char *p2 = "lmj";定义的是一个字符串常量!

返回指针的函数

// 将字符串str中的小写字母变成大写字母,并返回改变后的字符串
// 注意的是:这里的参数要传字符串变量,不能传字符串常量
char * upper(char *str) {
    // 先保留最初的地址。因为等会str指向的位置会变来变去的。
    char *dest = str;
    
    // 如果还不是空字符
    while (*str != '\0') {
        // 如果是小写字母
        if (*str >= 'a' && *str <= 'z') {
            // 变为大写字母。小写和大写字母的ASCII值有个固定的差值
            *str -= 'a' - 'A';
        }
        
        // 遍历下一个字符
        str++;
    }
    
    // 返回字符串
    return dest;
}

int main()
{
    // 定义一个字符串变量
    char str[] = "lmj";
    
    // 调用函数
    char *dest = upper(str);
    
    printf("%s", dest);
    return 0;
}

指向函数的指针

函数作为一段程序,在内存中也要占据部分存储空间,它也有一个起始地址,即函数的入口地址。可以利用一个指针指向一个函数。函数名就代表着函数的地址。

指向函数的指针的定义

定义的一般形式:函数的返回值类型 (*指针变量名)(形式参数1, 形式参数2, ...)
#include <stdio.h>

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

int main()
{
    // 定义一个指针变量p,指向sum函数
    int (*p)(int a, int b) = sum;
    // 或者 int (*p)(int, int) = sum;
    // 或者 int (*p)() = sum;
    
    // 利用指针变量p调用函数
    int result = (*p)(1, 3);
    // 或者 int result = p(1, 3);
    
    printf("%d", result);
    return 0;
}
返回指针的函数的定义char *upper(char *str) 和指向函数的指针的定义int (*p)(int a, int b)非常相似,使用时特别注意区分

指向函数的指针变量主要有两个用途:

    1.调用函数。
    2.将函数作为参数在函数间传递。以下举例
#include <stdio.h>

// 减法运算
int minus(int a, int b) {
    return a - b;
}

// 加法运算
int sum(int a, int b) {
    return a + b;
}

// 这个counting函数是用来做a和b之间的计算,至于做加法还是减法运算,由函数的第1个参数决定
void counting( int (*p)(int, int) , int a, int b) {
    int result = p(a, b);
    printf("计算结果为:%d\n", result);
}

int main()
{
    // 进行加法运算
    counting(sum, 6, 4);
    
    // 进行减法运算
    counting(minus, 6, 4);
    
    return 0;
}
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

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

余额充值