0
  • 聊天消息
  • 系统消息
  • 评论与回复
登录后你可以
  • 下载海量资料
  • 学习在线课程
  • 观看技术视频
  • 写文章/发帖/加入社区
创作中心

完善资料让更多小伙伴认识你,还能领取20积分哦,立即完善>

3天内不再提示

C语言中指针的命令行参数

C语言编程学习基地 来源:C语言编程学习基地 作者:C语言编程学习基地 2022-09-26 10:18 次阅读

指针是C语言最重要也是最难理解的部分,它在我们平时的工作中无处不在。

今天我们继续来看看指针的剩下的知识总结吧!上一批的话可以在主页看到哦~

4c3c116e-3bdc-11ed-9e49-dac502259ad0.png

5 指针与结构体

一个指针,它指向的可以是一个结构体类型,这称为结构体指针。而一个结构体,它的成员中也可以有指针成员。

struct{    char *name;  //姓名    int num;  //学号    int age;  //年龄    char group;  //所在小组    float score;  //成绩} stu1 = { "Tom", 12, 18, 'A', 136.5 }, *pstu = &stu1;

上面的代码中,定义了一个结构体变量stu1。这个变量中有一个指针变量name。还定义了一个结构体指针pstu。

我们想要通过结构体指针访问结构体成员一般有以下两种方式:

(*pstu).name;pstu->name;

6 指针与const:常量指针与指针常量

初学者常常对这两个概念搞错。首先,我认为需要理解这里说的常量是什么意思。常量就是只可读不可修改的。那常量指针和指针常量到底哪个是只可读不可修改的呢?是指针还是指针指向的内容?这里有一个方法,能让你迅速明白哪个是不可修改的。就是在声明时,以星号(*)为界,分成两部分,星号左边的和星号右边的。const在哪边,那个就是只可读不可修改的。以下面这个代码为例,我们来分析一下:以星号(*)为界,星号左边是char,没有const关键词,所以它指向的内容不是常量。然后,我们看星号的右边是const ptr,所以我们可以说ptr是一个常量。所以,这行代码声明了一个是常量的指针但是指向的内容不是常量。即这个是一个指针常量。

char* const ptr = "just a string";

类似的,我们也可以分析下面的代码:

// Neither the data nor the pointer are const//char* ptr = "just a string";
// Constant data, non-constant pointer//const char* ptr = "just a string";
// Constant pointer, non-constant data//char* const ptr = "just a string";
// Constant pointer, constant data//const char* const ptr = "just a string";

6.1 指针常量(Constant Pointers)

指针常量(Constant Pointers): 它的本质是一个常量,只不过这个常量是指针。由于指针是只可读不可修改的,所以这个指针不能指向别的地址了,但是该地址里的内容还是可以改变的。指针常量的声明格式如下:

 * const 例如: int * const ptr;

我们来看下序:

#includeint main(void){    int var1 = 0, var2 = 0;    int *const ptr = &var1;    ptr = &var2;    printf("%d
", *ptr);
    return 0;}

上面这段程序中:

我们首先定义了两个变量var1,var2;

然后,定义了一个指针常量ptr,并且指向了var1

接着,试图让ptr指向var2

最后,打印出指针ptr指向的地址的内容

让我们来运行一下这个程序:

main.c: In function 'main':main.c9: error: assignment of read-only variable 'ptr'     ptr = &var2;         ^

我们看到这个程序编译报错了:试图对只读(read-only)变量ptr进行赋值。所以,一旦我们定义了指针常量,那这个指针就不能指向其他变量了。

但是我们还是可以修改指向的地址里的内容的:

#includeint main(void){    int var1 = 0;    int *const ptr = &var1;    *ptr = 10; // OK    printf("%d
", *ptr); // 10    return 0;}

6.2 常量指针(Pointer to Constants)

常量指针(Pointer to Constants):它的本质是一个指针,只不过它指向的值是常量(只可读,不可修改)。由于指向的是一个只可读不修改的值,所以指针不能通过它存储的地址间接修改这个地址的值,但是这个指针可以指向别的变量。

常量指针的声明格式如下:

const * 例如: const int* ptr;

还是有一段程序:

#include
int main(void){    int var1 = 0;    const int* ptr = &var1;    *ptr = 1;    printf("%d
", *ptr);
    return 0;}

我们还是来分析一下这个程序:

我们定义了一个变量 var1,并且初始化为0

然后我们定义了一个指针常量ptr,并且将它指向了var1

接着,试图通过指针ptr来改变var1的值

最后,打印出ptr指向的地址的内容。

我们进行编译:

main.c: In function 'main':main.c10: error: assignment of read-only location '*ptr'     *ptr = 1;          ^

编译报错也很明显: *ptr是一个只读的。所以不能通过ptr来修改var1的值。

但是,我们可以将ptr指向其他的变量:

#include
int main(void){    int var1 = 0;    const int* ptr = &var1;    printf("%d
", *ptr); // 0    int var2 = 20;    ptr = &var2; // OK    printf("%d
", *ptr); // 20    return 0;}

6.3 指向常量的常量指针

理解了上面两种类型的话,理解这个就很容易了。指向常量的常量指针是指这个指针既不能指向其他的地址也不能通过地址修改内容。

它的声明格式如下:

const * const 例如: const int* const ptr;

同样,下面一段程序,我想你一定知道哪里编译错误了。

#include
int main(void){    int var1 = 0,var2 = 0;    const int* const ptr = &var1;    *ptr = 1;    ptr = &var2;    printf("%d
", *ptr);
    return 0;}

编译结果:

main.c: In function 'main':main.c10: error: assignment of read-only location '*ptr'     *ptr = 1;          ^main.c9: error: assignment of read-only variable 'ptr'     ptr = &var2;         ^

7 指针与函数

7.1 函数指针

指针与函数相结合有两种情况:指针函数、函数指针。

指针函数,它的本质是一个函数,它的返回值是一个指针。

int * func(int x, int y);

函数名本身就是一个指针(地址),这个地址就是函数的入口地址。

#include int sum(int a, int b){  return a + b;} int main(){  printf("%p
", sum);  return 0;}

输出:

0000000000401550

而函数指针,它的本质是一个指针。只不过它存的地址恰好是一个函数的地址罢了。

函数指针变量定义的格式一般是:

返回值 (*变量名)(参数列表)

比如:

#include int sum(int a, int b){    return a + b;} int main(){    printf("%p
", sum);    int (*psum)(int, int);  // 函数指针变量,参数名可以省略    psum = sum;    printf("%p
", psum);    return 0;}

输出:

00000000004015500000000000401550

可以发现,两者地址相等。

函数指针类型的定义:

typedef  返回值 (* 类型名)(参数列表);复制代码

比如:

typedef int(*PSUM)(int, int);PSUM pSum2 = sum;PSUM pSum3 = sum;

这样的好处就是,首先通过typedef定义一个函数指针类型PSUM,定义完后,PSUM就相当于一种新的类型,可以用此类型去定义其他函数指针变量,就不用每次都使用int(*pSum)(int, int);来定义一个函数指针变量。

#include int sum(int a, int b){    return a + b;}int func2(int a, int b){    return a - b;}typedef int (*PFUNC) (int, int);int main(){    int (*psum)(int, int);    psum = sum;    printf("psum(4, 5):%d
", psum(4, 5));    PFUNC p2 = func2;    printf("p2(5, 2):%d
", p2(5, 2));    p2 = sum;    printf("p2(5, 2):%d
", p2(5, 2));    return 0;}

输出:

psum(4, 5):9p2(5, 2):3p2(5, 2):7

7.2 回调函数

说到函数指针,那还有一个概念不得不提——回调函数。因为在实际的项目代码中实在是太常见了。

回调函数就是一个通过函数指针调用的函数。如果你把函数的指针(地址)作为参数传递给另一个函数,当这个指针被用来调用其所指向的函数时,我们就说这是回调函数。

那为什么要使用回调函数呢?或者说使用回调函数有什么好处呢?回调函数允许用户把需要调用的方法的指针作为参数传递给一个函数,以便该函数在处理相似的事情时,可以灵活的使用不同的方法。

怎么使用回调函数:

#include int Callback_1(int a)   ///< 回调函数1{    printf("Hello, this is Callback_1: a = %d 
", a);    return 0;}
int Callback_2(int b)  ///< 回调函数2{    printf("Hello, this is Callback_2: b = %d 
", b);    return 0;}
int Callback_3(int c)   ///< 回调函数3{    printf("Hello, this is Callback_3: c = %d 
", c);    return 0;}
int Handle(int x, int (*Callback)(int)) // 注意这里用到的函数指针定义{    Callback(x);}
int main(){    Handle(4, Callback_1);    Handle(5, Callback_2);    Handle(6, Callback_3);    return 0;}

如上述代码:可以看到,Handle()函数里面的参数是一个指针,在main()函数里调用Handle()函数的时候,给它传入了函数Callback_1()/Callback_2()/Callback_3()的函数名,这时候的函数名就是对应函数的指针,也就是说,回调函数其实就是函数指针的一种用法。

8 二维指针

二维指针,或者二级指针。就是指向指针的指针。比如:

#includeint main(){    int a = 10;    int *pa = &a;    int **ppa = &pa;    printf("%p, %p, %p, %p, %p", a, pa, *pa, ppa, *ppa);    return 0;}

输出如下:

000000000000000A, 000000000061FE14, 000000000000000A, 000000000061FE08, 000000000061FE14

从输出结果也可以看到,pa存的内容*pa= 000000000000000A,刚好与a的地址相同。而ppa存的内容*ppa= 000000000061FE14也刚好等于pa的地址。它们之间的内存关系可以用如下的图表示:

4c50c62c-3bdc-11ed-9e49-dac502259ad0.png

8.1 命令行参数

处理命令行参数是指向指针的指针的一个用武之地。

一般main函数具有两个形参。第一个通常称为argc,它表示命令行参数的数目。第2个通常称为argv,它指向一组参数值。由于参数的数目并没有内在的限制,所以argv指向这组参数值(从本质上来说是一个数组)的第一个元素。这些元素的每个都是指向一个参数文本的指针。如果程序需要访问命令行参数,main函数在声明时就要加上这些参数。

【int main(int argc, char **argv)

举例:

#include 
int main(int argc, char *argv[]){    printf("argc: %d
", argc);
    // 打印参数,直到遇到NULL指针。程序名被跳过    while (*++argv != NULL) {        printf("%s
", *argv);    }    return 0;}

在windows上执行: est2.exe hello world

argc: 3helloworld

注意,如果命令行中传递的一个参数包括空格,就需要用 ""将参数括起来,比如:

. est2.exe "hello word"

则上面的代码将输出:

argc: 2hello word

9 结束语

本文关于指针的讲解就结束了。我相信你一定对指针有更深入的了解。

审核编辑:彭静
声明:本文内容及配图由入驻作者撰写或者入驻合作网站授权转载。文章观点仅代表作者本人,不代表电子发烧友网立场。文章及其配图仅供工程师学习之用,如有内容侵权或者其他违规问题,请联系本站处理。 举报投诉
  • C语言
    +关注

    关注

    180

    文章

    7527

    浏览量

    128179
  • 函数
    +关注

    关注

    3

    文章

    3863

    浏览量

    61303
  • 指针
    +关注

    关注

    1

    文章

    472

    浏览量

    70361

原文标题:C语言基础知识:最核心的—指针!知识总结(第二部分)

文章出处:【微信号:cyuyanxuexi,微信公众号:C语言编程学习基地】欢迎添加关注!文章转载请注明出处。

收藏 人收藏

    评论

    相关推荐

    C语言中指针的定义

    上一节中,我们利用了一个小知识来介绍了一下指针,在上面这个例子中,小明和小丽手中的这个杯子就好比我们C语言中的变量,它确实是实实在在存放一些有具体意义的数据。这个杯套就类似于C语言中指针的作用,假设
    发表于 08-15 16:24 1662次阅读
    C<b class='flag-5'>语言中指针</b>的定义

    在STM32实现命令行

    工作中的开发环境都是基于linux命令行交互,作为命令行的重度使用者,玩单片机也要使用命令行工具,百度了一些命令行工具,有几个不错的开源 cmd 交互工具,主要看了 finsh
    发表于 12-09 11:32 1616次阅读

    C语言中指针的基本概念和用法

    在C语言中指针是一项重要的概念,它允许我们直接访问和操作内存地址。
    发表于 08-17 15:30 511次阅读

    谈谈C语言中指针有什么好处,请各位高手们谈谈自己的体会

    谈谈C语言中指针有什么好处,请各位高手们谈谈自己的体会...
    发表于 09-01 17:38

    支持命令行传递的参数吗?

    的每一个。要手动尝试在Makefile中设置CFLAGS。可以在预处理器宏部分访问命令行传递的参数吗?如果这是在命令行值不是构建的一部分的IDE中构建的,那么我还需要能够支持默认值。
    发表于 03-17 06:03

    Linux命令行的基本使用

    嵌入式Linux开发环境的构建,Linux命令行的基本使用,VI、GCC、Makefile基本工具的使用,交叉开发环境的使用。学习条件: 1.C语言编程基础
    发表于 11-05 09:08

    C语言入门教程-命令行参数

    命令行参数 在C中,获取用户输入的命令行参数是很方便的。程序的主函数会接受一个argv参数。有许多高级的库函数都会用到argv结构,所以了
    发表于 07-29 14:22 2471次阅读

    caxa命令行中的应用

    caxa命令行中的应用 命令行对于大多用户来说往往只是输入数据的作用,但是其中的奥妙还有很多,下面就给大家
    发表于 10-18 18:18 2164次阅读

    C语言中指针的介绍非常详细

    C语言中指针的介绍非常详细 C语言中指针的介绍非常详细
    发表于 12-25 10:39 57次下载

    博达环网配置命令行

    博达工业交换要环网配置命令行
    发表于 12-27 16:24 0次下载

    CMD的命令行高级教程

    CMD的命令行高级教程
    发表于 10-24 08:31 30次下载
    CMD的<b class='flag-5'>命令行</b>高级教程

    C语言中一个简单的实例,检查命令行是否有提供参数

    多个命令行参数之间用空格分隔,但是如果参数本身带有空格,那么传递参数的时候应把参数放置在双引号 "" 或单引号 '' 内部。让我们重新编写上
    的头像 发表于 11-12 14:49 3298次阅读

    Golang基于flag库实现一个命令行工具

    Golang 标准库中的 flag 库提供了解析命令行选项的能力,我们可以基于此来开发命令行工具。
    的头像 发表于 10-28 09:26 973次阅读

    linux虚拟机怎么调出命令行

    在Linux虚拟机中调出命令行界面,可以通过以下步骤实现: 打开虚拟机,进入到Linux系统。 在桌面或应用菜单中找到终端或命令行图标,点击打开。 输入命令行指令,执行相应的操作。 另外,也可以通过
    的头像 发表于 11-08 11:28 1608次阅读

    idea如何输入命令行参数

    。 在大多数编程语言中,都提供了内置的机制来处理命令行参数,以便程序可以根据用户的需求进行不同的操作。下面我们将逐步介绍如何在常见的编程语言中输入
    的头像 发表于 12-06 15:01 360次阅读