【C语言】函数调用的参数压栈(详解)
[TOC] 前言在早期的学习中,我们已经了解到当函数传值调用参数的时候,用的是形参。 形参是实参的一份临时拷贝,对形参的改变不会影响实参里的值。 传值调用和传址调用👉点我 今天让我们以汇编语言来了解函数调用的参数压栈这一知识点 所用编译器:VS2019 不同编译器的实现可能略有不同,以实际为准 1.什么是栈区?栈,是一种数据结构。 在学习C语言的过程中,我们一般只关注内存中的3个区域,分别是栈区、堆区和静态区。 其中堆区主要用于动态内存管理,在之前的博客中已经和大家介绍过。 详解动态内存管理👉点我 而栈区就是编译器给函数运行分配的空间了。 和堆区空间需要手动分配不同,这一部分空间是编译器自动管理的,函数的栈帧会自动创建,自动销毁。 1.1栈区小知识点 栈区的使用是从高地址到低地址 栈区的使用遵循先进后出,后进先出 栈区的放置是从高地址往低地址放置:push压栈 删除是从低往高删除:pop出栈 2.知识点12345678910111213141516171819//本次使用的代码#include <stdio.h>int Add(int x,...
【C语言】程序运行过程:预处理/编译/汇编/链接
哈喽啊,盆友们。一起来看看C语言中编译预处理的内容吧!😜 1.程序编译的几个阶段众所不周知,C语言的程序运行分为几个阶段。 咱们可以看看下面这个图,简单了解一二👇 细分开来,编译还分为3个小阶段:预编译(预处理)、编译、汇编 这三个阶段又分别做了什么事情呢?这就需要我们用linux下的gcc编译器来验证了 1.1 预编译现在我们编写了一个这样的代码,分为两个文件 12345// Add.cint Add(int x,int y){ return x+y;} 123456789101112131415// test.c#include <stdio.h>extern int Add(int x,int y);#define M 100// 这是一个测试int main(){ int a=4; int b=10; printf("a+b=%d\n",Add(a,b)); printf("M+b=%d\n",Add(M,b)); return...
【树莓派开发】树莓派GeanyIDE和控制台下C/C++中文乱码问题解决方法
情况说明之前使用树莓派的时候,遇到了中文乱码的问题。 VS2019编译器下写的.c文件,里面的中文注释在树莓派ide上乱码 树莓派控制台上,C语言代码输出中文时乱码 这里需要调整三个设置来解决该问题 1.设置VS,将文件保存为UTF8编码VS2019默认用的是GBK编码,而不是一般中文需要的UTF8编码 这里我们可以安装一个Force UTF-8(No BOM)插件来解决该问题 在VS顶部工具栏里找到“拓展”-管理拓展 搜索Force UTF-8(No BOM),找到该插件并安装 这个插件的作用,是让VS保存文件都使用UTF8编码保存 安装完毕后,可以在原本文件中打一个注释并保存,这时候.c文件就已经是UTF8编码了 树莓派中可以更改文件编码,但这个更改并不会对已经乱码了的中文生效 更新22.03.01:使用该插件可能会导致报错该文件包含不能在当前代码页(936)中表示的字符。请将该文件保存为 Unicode 格式以防止数据丢失出现这种情况需要禁用插件,重启VS才能解决。否则程序有中文注释就无法运行 2.更改Geany...
【树莓派开发】使用树莓派在Linux环境下编写C语言代码
前言如何使用树莓派编译C语言代码呢? 21年暑假的时候,学习编程的劲头高涨,然后冲动消费买了个树莓派4B……结果压根不会用,吃灰了半年 不过现在已经学完了C语言,也接触了一丢丢Linux系统下的gcc指令,可以尝试用它来编写C语言代码了! 1.创建test.c文件首先我们需要在一个文件夹里创建一个test.c文件 点击test.c文件后,树莓派会用自带的Geany编辑器打开它 然后我们可以往里写入C语言最经典的helloword代码 1234567#include <stdio.h>int main(void){ printf("hello wordl!\n"); return 0;} 2.编译运行该文件保存文件后,打开顶部的命令行 输入以下代码。注意cd后需要空格,填写的是刚刚创建的test1.c文件的路径 1cd...
【Git】Sourcetree的初始化与使用
[TOC] 前言还在用小乌龟管理你的git本地代码吗? 为何不来尝试一下,这款界面更加直观的git可视化工具! sorcetree官网👉https://www.sourcetreeapp.com/ 别看到英文官网就跑了,软件本身是中文界面! 注:本博文只讲述sourcetree初始化方式,并不讨论其与TortoiseGit的功能强弱 什么?你还不知道git是啥? 那还不赶快点击这篇博客了解一二!👇 实习生 Git...
【牛客网】JZ65:不用四则运算符实现两数相加
[TOC] 问题来源 牛客网数据结构题目👉JZ65 题目要求如图 思考不能使用四则运算,根据过往的学习经历,我唯一能想到的就是位操作符和移位操作符 例:使用位操作符进行int变量交换 位操作符的使用先来回顾一下位操作符的作用 位操作符操作的是整形的二进制位,它的操作数是2,比较两个整型的二进制位 &按位与:对应的二进制 全为1才是1,否则0 |按位或:对应的二进制 有1为1,全为0才为0 ^按位异或:相同为0,不同为1 比较一下正常的二进制相加和按位异或,发现按位异或是没有进位的相加 原本应该是010,但是按位异或后是000 1+1需要进位的1并没有进到下一位里去 而使用按位与操作符,我们可以得到这两个数相加需不需要进位 1234560 0 10 0 1//按位与-全1为10 0 1//<< -左移1位0 1 0 这时候将按位与之后的结果和按位异或相加,就是我们的答案了 但是题目要求不能使用加减 再将按位与的结果0 1 0与 按位异或结果0 0 0进行按位与 得到0 0 0 ,代表无需进位 这时候将0 1 0与0 0 0...
【C语言】动态内存管理(详解malloc/calloc/realloc)
[TOC] 直入主题,动态内存管理!🕵️♂️ 1.为什么会有动态内存分配?我们一般使用以下两种方式开辟内存 12int a = 20;//在栈空间上开辟四个字节char arr[10] = {0};//在栈空间上开辟10个字节的连续空间 但是上述的开辟空间的方式有两个特点: 空间开辟大小是固定的。 数组在声明的时候,必须指定数组的长度,它所需要的内存在编译时分配。 但是对于空间的需求,不仅仅是上述的情况。有些时候,我们并不能提前知道需要的空间大小,而部分编译器并不支持变长数组。这时候以数组的方式开辟连续空间的方法就有点不适用了。 其次,全局变量/局部变量是存放在栈区里面的。如果存放的变量太多,就会出现栈溢出的错误。 这时候就轮到动态内存管理上场了! 2.动态内存函数2.1 malloc12#include <stdlib.h>//malloc的头文件void* malloc (size_t size); 这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针。 如果开辟成功,则返回一个指向开辟好空间的指针。...
【C语言】自定义类型(详解)
[TOC] 在C语言中,有几个比较特殊的自定义类型:结构体、枚举、联合 本篇博客,就让我们来认识一下这些自定义类型吧!😶 1.结构体结构体是一些值的集合,结构体的每个成员可以是不同类型的变量 1.1结构体的声明以个人信息为例,有姓名、性别、年龄、身高等几个元素。可以定义结构体如下 1234567struct Stu{ char name[20]; char sex[5]; int age; int hight;}s2, s3, s4;//s2,s3,s4全局变量 1.2特殊声明在声明结构体的时候,可以不完全声明 12345678910111213struct{ char c; int a; double d;}sa;struct{ char c; int a; double...
【C语言】常用的字符串函数和内存函数
[TOC] 今天我们来学习一些新的字符串函数和内存函数,了解它们背后运行的原理,并完成部分函数的自我实现😘 1.字符串函数1.1 strlen这个函数我们已经很熟悉了,它的作用是计算字符串的大小,以\0作为结尾 模拟实现如下: 123456789101112131415161718192021//1.strlen模拟实现int my_strlen(char* p){ assert(p); int count = 0; while (*p) { count++; p++; } return count;}int main(){ char arr[] = { "abcdef" }; int sz = my_strlen(arr); printf("sz=%d\n", sz); return 0;} assert:断言,库函数,用于判断指针是否为空,若为空会报错 1.2 strcpy该函数用于拷贝字符串,将arr2里的内容拷贝到arr1里 123char*...