C/C++中malloc的强制转换

因为数据结构课在使用malloc函数的时候一直很迷惑,为什么一定需要在前面加上一个强制转换语句,像是这样:int *a = (int *)malloc(sizeof(int)*3);。 为此我在菜鸟教程的malloc()函数介绍中找到了关于malloc的声明:void *malloc(size_t size),显然加上一个强制转换语句并不是标准语法必须的东西,但是在菜鸟教程下面的举例中是按照强制转换的写法来写的,可惜没有说为什么。为此我尝试了不加强制转换语句的malloc来直接分配空间,在gcc编译后并没有报错或者发出警告。 这就很神奇了,我换了多个姿势来对这两种用法进行测试,包括但不限于不同大小long *a = malloc(sizeof(int)*2)或者数组结构int *b = malloc(size(int)*3),他们都没有报错或警告,而强制转换亦是如此。 就在我怀疑是某种错误的如同void main这种异类写法产生了曼德拉效应时,我看到了另一篇博客的记录:在ANSI/ISO标准C下,我们是可以不使用强制转换来直接使用malloc的,并且使用强制转换还可能掩盖malloc()声明错误时产生的重要警告,反而不如直接使用malloc。但是使用malloc强制转换的好处在于,可以更方便地移植到C++中,因为C++似乎并不支持这种隐式转换。 根据这个帖子我大概猜测了一下国内这种喜欢在malloc函数前加强制转换命令的原因,除了个别学校在教学生C语言的时候把C/C++混为一谈,导致学生用C++的语法来理解C语言(这种情况真的不少),还有很大原因是因为国内高校很喜欢用Dev-C++这类常年未更新用着远古标准的IDE。

December 26, 2020 · 云雾海

C的main函数解析

终于开始学习Linux的C语言编程了嘤嘤嘤,有种终于入门的感动 关于Linux中C语言编程包括vim、gcc、makefile这些工具的用法这些不是本次的主题,我在这里就不详细展开了,本文只阐述一下main函数的参数调用问题。 工具 基本原理 实现与解析 工具 VirtualBox 6.1.12,Ubuntu 20.04,Code::Blocks,C 基本原理 众所周知,main函数对于系统来说其实也只是一个普通的函数,它作为一个接口与系统进行连接,每次系统调用main函数生成的程序文件。而Linux系统其实又是通过C语言写出来的,本质上其实也只是一个C程序。而调用C生成的程序文件其实就等同于将Linux的一个程序运行指针调用这个程序的地址,然后这个程序就执行起来了,而我们可以通过main函数的两个参数接口在调用这个程序的时候进行传参。 实现与解析 // Hello.c,用于测试main参数传递 #include <stdio.h> #include <string.h> int main(int argc, char *argv[]) { printf("程序地址为:%s\n", argv[0]); printf("本次传入参数共有%d个\n", argc - 1); int i = 1; while(i < argc) // 通过循环遍历传入所有参数 { switch(argv[i][0]) // 通过首字母进行快速定位 { case 'w': case 'W': { if(strcmp(argv[i], "World") == 0) { printf("Hello World!\n"); break; } else printf("Is W/w but not World~\tHello %s\n", argv[i]); // 是W/w但是并非World break; } case 'l': case 'L': { if(strcmp(argv[i], "Linux") == 0) { printf("Hello Linux!\n"); break; } else printf("Is W/w but not World~\tHello %s\n", argv[i]); // 是L/l但是并非Liunx break; } default: printf("This is %s\n", argv[i]); break; } i++ } return 0; } 这里我们可以看到main函数中有两个参数,分别是int类型的argc和char**类型的argv两个参数,当然这两个参数的名字可以变换,就像普通函数的形参一样,但是通常大家都用这两个,相当于约定俗成了。可以看出argv是一个指向char数组的指针数组的数组指针,听上去有点绕,但是用char * argv[]应该就比较好理解了,或者说甚至可以直接当成一个二维数组,其中第一维是一堆地址,每个地址分别指向一个char数组的首地址,而char数组则构成了第二维。而argc则记录了其中第一维的指针argv[]的个数。 ...

December 20, 2020 · 云雾海

C和C++在参数调用上的区别

在学习 C 语言的数据结构时,我发现教科书上出现的一些代码实际上并不能很好地在 C 语言环境中运行,而需要改成 C++才可以,在网上搜了一下,这里记录 C 和 C++在函数传参上的区别 C++的形参有三种写法: void example_CPP(&a, *b, c){ /*a为引用传参*/ /*b为指针传参*/ /*c为直接传参*/ } 三种写法各有用处,这里我们以实例进行研究—— 首先我们打开自己的 IDE,我用的 CodeBlocks,然后输入一下程序: #include <iostream> using namespace std; void example_CPP(int &a,int *b,int c); int main(){ /*定义三个变量并输出其值和地址*/ int x,y,z; x = y = z = 0; example_CPP(x, &y, z); cout<<"x的值:"<<x<<"\nx的地址"<<&x<<"\n"; cout<<"y的值:"<<y<<"\ny的地址"<<&y<<"\n"; cout<<"z的值:"<<z<<"\nz的地址"<<&z<<"\n"; } void example_CPP(int &a,int *b,int c){ /*将3个数分别加一*/ a += 1; *b += 1; c += 1; /*a为引用传参,传的是引用值*/ cout<<"a的值:"<<a<<"\na的地址"<<&a<<"\n"; /*b为指针传参,传的是地址*/ cout<<"b的值:"<<*b<<"\nb的地址"<<b<<"\n"; /*c为直接传参,传的是实际值*/ cout<<"c的值:"<<c<<"\nc的地址"<<&c<<"\n"; } 输出结果如下: 当我们使用直接传参时,实际过程可以理解为我们把原来 z 的值赋值给一个新的变量 c,在对 c 进行了一堆操作后释放 c 的空间,而 z 实际上并没有参与到函数中,而仅仅起到一个赋初值的作用。 而当我们进行指针传递时,可以理解为我们把 y 的地址赋值给一个指针变量 b,而通过指针 b 对其指向的 y 的存储空间进行操作,我们没有直接对 y 进行操作,但是通过指针 b 我们可以间接修改 y 的值。 ...

November 8, 2020 · 云雾海