
C语言
文章平均质量分 67
小米内推官_AngelDg
我们总以为,是生活欠我们一个“满意”,其实是我们欠生活一个“努力”。
展开
-
#define 宏的边际效应是什么
在C语言和C++中,#define宏进行的字符替换,要注意边际效应:举例一:#define N 2+3我们预想的N值是5,我们这样使用N,int a = N/2;我们预想的a的值是2.5,可实际上a的值是3.5(这样说不太恰当,因为是取整,但为了说明先这样理解)原因在于在预处理阶段,编译器将 a = N/2处理成了 a = 2+3/2;这就是宏定义的字符串替换的“边缘效应”,因此要如下定义:#define N (2+3)举例二:#define MIN(a, b) a > b ? b原创 2021-09-06 20:32:10 · 750 阅读 · 0 评论 -
C / C++:const 关键字的作用
文章目录C与C++中 const 关键字有什么区别使用 const 提高函数的健壮性用 const 修饰函数的参数用 const 修饰函数的返回值C与C++中 const 关键字有什么区别C语言中const的用法:const修饰的变量是只读的,本质还是变量。const修饰的局部变量在栈分配空间,这里举一个例子:#include <stdio.h>#include <stdlib.h>int main() { const int c = 0; int *p =原创 2021-03-11 15:29:09 · 512 阅读 · 0 评论 -
数组和指针的对比
C++/C程序中,指针和数组在不少地方可以相互替换着用,让人产生一种错觉,以为两者是等价的。 数组要么在静态存储区被创建(如全局数组),要么在栈上被创建。数组名对应着(而不是指向)一块内存,其地址与容量在生命期内保持不变;数组实际上就是一个常量指针,例如: char ar[10]; 就相当于char * const ar; 即数组名对应一块空间, 该数组名不能指向其他空间。 指针可以随时指向任意类型的内存块,它的特征是“可变”,所以我们常用指针来操作动态内存。指针远比数组灵活,但也更危险原创 2021-03-09 21:51:11 · 440 阅读 · 5 评论 -
#pragma once 与 #ifndef 相关知识点
提问为什么要在头文件前加上 #pragma once 或者 #ifndef ?为了避免同一个文件被include多次同一个文件被 include 多次的危害:防止重复定义的错误如果这个头文件变化,那么所有include这个文件的源文件都需要重新编译,即使没有去使用里面的任何内容避免措施:头文件加#pragma once... ... // 一些声明语句头文件加#ifndef __SOMEFILE_H__ // 宏名 #define __SOMEFILE_H__原创 2020-12-29 21:44:57 · 140 阅读 · 0 评论 -
malloc 的实现原理
文章目录结论具体内容内存分配的原理具体分配过程提问摘要:由于面试题会问到 malloc 的底层原理,今天就来记录一下,毕竟学习要“知其所以然”,这样才会胸有成竹。注:下面分析均是基于 linux 环境下的 malloc 实现。Linux 的虚拟内存管理有几个关键概念:每个进程都有独立的虚拟地址空间,进程访问的虚拟地址并不是真正的物理地址;虚拟地址可通过每个进程上的页表(在每个进程的内核虚拟地址空间)与物理地址进行映射,获得真正物理地址;如果虚拟地址对应物理地址不在物理内存中,则产生缺页中断,原创 2020-12-28 00:06:14 · 5159 阅读 · 3 评论 -
详解:如何写参数个数不定的函数(类似printf的函数)
文章目录实现 printf() 函数解析 stdarg.h 头文件#include <stdio.h>#include <stdarg.h> // 要包含这个头文件void variable(int i, ...){ int j = 0; va_list arg_ptr; // 第1步,定义这个指向参数列表的变量,把这个换成 char*试一试? va_start(arg_ptr, i); // 第2步,把上面这个变量初始化.即让它指向参数列表原创 2020-12-23 23:58:28 · 1084 阅读 · 1 评论 -
了解常用的C/C++函数调用约定
函数调用约定什么是函数调用约定?约束事件编辑什么是函数调用约定?调用约定(Calling convention)决定以下内容:函数参数的压栈顺序由调用者还是被调用者把参数弹出栈产生函数修饰名的方法。关于 C/C++ 函数调用约定,大多数时候并不会影响程序逻辑,但遇到跨语言编程时,了解一下还是有好处的。 VC 中默认调用是 __cdecl 方式,Windows API 使用 __stdcall 调用方式,在 DLL 导出函数中,为了跟 Windows API 保持一致,建议使用 __st原创 2020-12-15 18:59:31 · 225 阅读 · 0 评论 -
递归与循环的区别(P:尾递归优化)
递归与循环递归算法循环算法尾递归尾递归的概念函数栈的作用尾递归为什么可以优化递归算法递归就是函数体中调用自己,如果不加控制,将无休止的调用自己,直到堆栈溢出。优点:代码简洁、清晰,并且容易验证正确性。(如果你真的理解了算法的话,否则你更晕)缺点:它的运行需要较多次数的函数调用(消耗空间和时间),每次函数调用,都需要增加额外的堆栈处理,比如参数传递需要压栈等操作,会对执行效率有一定影响。递归算法的运行效率较低。在递归调用的过程中系统为每一层的返回点、局部变量等开辟了栈来储存。递归次数过原创 2020-12-15 13:10:48 · 881 阅读 · 0 评论 -
C++:重载++与--操作符
文章目录C与C++中 ++ 与 -- 的区别重载++、--操作符图解++操作符,前置与后置的区别代码示例:要点总结:C与C++中 ++ 与 – 的区别在C语言中,前置和后置++,–都不能作为左值在C++中,前置的++和–可以作为左值,(从下面的重载运算符中也可以看出,它们返回的是引用)C++类似的提升还有三目运算符?:,在c中也不可以做左值,但c++中可以。重载++、–...原创 2020-03-19 11:49:29 · 454 阅读 · 0 评论 -
C/C++:动态内存管理方式的区别
C语言中动态内存管理方式malloc/calloc/realloc和free代码示例void Test () { int* p1 = (int*) malloc(sizeof(int)); free(p1); // 1.malloc/calloc/realloc的区别是什么? int* p2 = (int*)calloc(4, sizeof (int)); ...原创 2020-03-15 01:48:37 · 335 阅读 · 0 评论 -
C/C++:内存分配,详解内存分布(P:图解及代码示例)
文章目录内存分布图解内存分布说明常见的内存分布图我们先来看下面的一段代码和相关问题int globalVar = 1;static int staticGlobalVar = 1;void Test(){ static int staticVar = 1; int localVar = 1; int num1[10] = {1, 2, 3, 4}; ch...原创 2020-03-15 00:46:47 · 25929 阅读 · 8 评论 -
[每日一题]10:输入两个字符串,从第一字符串中删除第二个字符串中所有的字符
题目描述:输入两个字符串,从第一字符串中删除第二个字符串中所有的字符输入描述:“They are students” “aeiou”输出描述: “Thy r stdnts”思路:由于字符(char)是一个长度为8的数据类型,因此总共有可能256 种可能。于是我们创建一个长度为256的数组,每个字母根据其ASCII码值作为数组的下标对应数组的对应项,而数组中存储的是每个字符对应的次数...原创 2020-03-03 22:47:33 · 738 阅读 · 0 评论 -
[每日一题]9:请找出数组中两个只出现一次的数字
题目描述一个整形数组里除了两个数字之外,其他的数字都出现了两次。请写程序找出这两个只出现一次的数字。例如数组为{ 1, 3, 5, 7, 1, 3, 5, 9},找出数字7和9。思路对数组内每个数进行按位异或( ^ )[因为相同的数字异或后为0,数组中只有两个数字出现一次,其余都出现两次,异或出来的结果一定不为0]得到异或出来的数字的二进制位第一个为1的位数(右–>左)将数组中的...原创 2020-03-02 23:07:37 · 372 阅读 · 0 评论 -
详解二叉树的后序遍历
后序遍历:首先遍历左子树,然后遍历右子树,最后访问根节点(左->右->根)后序遍历的递归算法思路:遍历左子树遍历右子树访问根节点代码如下:void BinaryTreePostOrder(BTNode* root){ if (root){ BinaryTreePostOrder(root->lChild); BinaryTreePostOrder(...原创 2020-02-26 21:11:39 · 1980 阅读 · 0 评论 -
详解二叉树的中序遍历
中序遍历:首先遍历左子树,然后访问根节点,最后遍历右子树(左->根->右)中序遍历的递归算法思路:遍历左子树访问根节点遍历右子树代码如下:void BinaryTreePrevOrder(BTNode* root){ if (root){ BinaryTreePrevOrder(root->lChild); putchar(root->dat...原创 2020-02-26 20:50:17 · 1664 阅读 · 0 评论 -
详解二叉树的层序遍历
思路借助队列完成先将二叉树根节点入列取队顶打印如果她有左孩子就入队左孩子;如果有右孩子就入队右孩子队顶出队(队列为空,则跳出;不会空,则返回步骤2直至队列为空)图解层序遍历#include ""#include ""//二叉树层序遍历(队列):二叉树层层压栈,层层递归跳出(先入先出)void BinaryTreeLevelOrder(BTNode* root){ Q...原创 2020-02-26 18:42:51 · 469 阅读 · 0 评论 -
详解二叉树的前序遍历
思路先使用二叉链的结构写一个建立二叉树的函数(函数返回根节点)代码以前序遍历方式输入二叉树,当输入“#”时,指针指向NULL,说明是该结点是为空结点二叉树的前序遍历:首先访问根结点,然后遍历左子树,最后遍历右子树(根->左->右)顺序:访问根节点->前序遍历左子树->前序遍历右子树前序遍历递归算法图解前序遍历代码如下:#include <stdi...原创 2020-02-23 14:43:45 · 1610 阅读 · 0 评论 -
空指针、野指针、通用指针、垂悬指针
题目:空指针是指()A.所指向的空间位置是未存放任何数据的指针.B.所指向的空间位置存放着数据0的指针.C.所指向的空间位置可用于存放任何类型数据的指针.D.所指向的空间位置就是地址0的指针.答案: D解析如下:空指针即p=NULL,NULL就代表系统的0地址单元....原创 2020-02-20 20:48:24 · 483 阅读 · 0 评论 -
内存分配方式(堆、栈 / 栈帧、自由存储区、全局/静态存储区和常量存储区)
程序的内存分配:一个由C/C++编译的程序占用的内存分为以下几个部分:栈区(stack): 由编译器自动分配释放,存放函数的参数值,局部变量的值等。栈的生长方向是从高往低的(向着内存地址减小的方向),其操作方式类似于数据结构中的栈。堆区(heap) : 堆区的生长方向是向上增长的(向着内存地址增加的方向),用于分配程序员申请的内存空间(比如new 申请的动态内存),一般由程序员分配释放,若...原创 2020-02-20 18:17:29 · 1785 阅读 · 1 评论 -
详解 CPU 大段存储与小端存储
计算机界的大小端问题有著名的CPU两大派系,PowerPC系列采用大端(big endian)的方式存储数据,而X86系列则采用小端(little endian)方式存储数据。很显然如果你的程序只运行在PowerPC系列的CPU上,你完全可以不管什么是little endian,但是如果你PowerPC上的程序要和X86上的程序打交道,那么你就必须进行转换才能相互识别,我们又该怎样去理解它呢?...原创 2020-02-20 11:37:46 · 1766 阅读 · 0 评论 -
详解二叉树的四种遍历方式
二叉树的遍历是指从根结点出发,按照某种次序依次访问二叉树中所有结点,使得每个结点被访问一次且仅被访问一次。在二叉树的遍历中存在三种较为常用的遍历方式:前序遍历、中序遍历、后序遍历前序遍历使用递归方式实现前序遍历的具体过程为:先访问根节点再序遍历左子树最后序遍历右子树中序遍历使用递归方式实现中序遍历的具体过程为:先中序遍历左子树再访问根节点最后中序遍历右子树后序遍历使用递归...原创 2020-02-19 11:43:17 · 2403 阅读 · 0 评论 -
C:八种基本排序——基数排序(8)
基数排序原理:【性能】:假设在基数排序中,r为基数,d为位数。则基数排序的时间复杂度为O(d(n+r))。对于任何位数上的基数进行“装桶”操作时,都需要n+rd个临时空间。是稳定排序算法。思路:图解基数排序算法解析:C代码如下:代码生成图如有不同见解,欢迎留言讨论!...原创 2020-02-16 23:20:47 · 644 阅读 · 2 评论 -
C:八种基本排序——快速排序(7)
快速排序原理:【思路】:每轮选择一个基准元素(比如第一个),将待排序的记录分割成两部分,一部分的元素值均比基准元素值小,另一部分比基准值大,然后分别对这两部分用同样的方法排序。一般基于递归实现。冒泡排序每次只调整了一个数或几个数的相对关系,而快速排序每遍都让两边保持相对关系。【性能】:快速排序是不稳定排序,时间复杂度为O(nlogn)。快速排序是通常被认为在O(nlog2n)的排序方法中平均...原创 2020-02-14 23:57:34 · 442 阅读 · 0 评论 -
C:八种基本排序——堆排序(6)
知识扩充完全二叉树的特点:从作为第一层的根开始,除了最后一层之外,第N层的元素个数都必须是2的N次方;第一层2个元素,第二层4个,第三层8个,以此类推。每一行的元素都从最左边开始安放(生成的顺序是从上往下,从左往右),两个元素之间不能有空闲小根堆与大根堆的定义:有一棵完全二叉树,对于任意一个子节点,其数值均不小于其父节点的值,这样层层递推,就是根节点的值最小,这样的树,称为小根堆...原创 2020-02-10 23:50:59 · 294 阅读 · 0 评论 -
C:八种排序算法——归并排序(5)
归并排序原理:归并排序采用的是分治法,并且依托于归并操作,其思想是分而治之。归并操作是将两个有序的数列合并到一个有序的序列,那么对于一个无序的长序列,可以把它分解为若干个有序的子序列,然后依次进行归并。如果我们说每一个数字都是单独有序的序列,那么只要把原始长序列依次分解,直到每个子序列都只有一个元素的时候,再依次把所有的序列进行归并,直到序列数为1为止。思路:分解:将列表越分越小,直至...原创 2020-02-09 22:35:18 · 320 阅读 · 0 评论 -
C:八种基本排序——希尔排序(4)
希尔排序原理:希尔排序,也称递减增量排序算法,是插入排序的一种更高效的改进版本。先将整个待排序的记录序列分割成为若干子序列分别进行直接插入排序,待整个序列中的记录“基本有序”时,再对全体记录进行依次直接插入排序。思路:选择一个增量序列 t1,t2,……,tk,其中 ti > tj, tk = 1;按增量序列个数 k,对序列进行 k 趟排序;每趟排序,根据对应的增量 ti,将待...原创 2020-02-08 23:56:04 · 377 阅读 · 0 评论 -
C:八种基本排序——插入排序(3)
直接插入排序原理:将一个数据插入到已经排好序的有序数据中,从而得到一个新的、个数加一的有序数据,算法适用于少量数据的排序。思路:将数组的第一个数认为是有序数组,从前往后扫描该有序数组,把数组中其余n-1个数,根据数值的大小,插入到有序数组中,直至数组中的所有数有序排列为止。性能:直接插入排序是稳定排序,时间复杂度为O(n^2),不需要额外空间。图解冒泡排序:算法分析当初始序列...原创 2020-02-06 23:55:24 · 297 阅读 · 0 评论 -
[每日一题]:2.在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。
题目:在一个二维数组中,每一行都按照从左到右递增的顺序排序,每一列都按照从上到下递增的顺序排序。请完成一个函数,输入这样的一个二维数组和一个整数,判断数组中是否含有该整数。思路:这是一个杨氏矩阵,解法在以下博客有介绍https://blog.youkuaiyun.com/AngelDg/article/details/100988348代码如下:#define _CRT_SECURE_NO_W...原创 2020-01-26 22:29:46 · 413 阅读 · 0 评论 -
C/C++:#define 与 typedef、const 的使用区别
#define的用法#define为一宏定义语句,通常用它来定义常量,以及用它来实现宏。它本身并不在编译过程进行,而是在这之前的预处理过程中已经完成了,但也因此难以发现潜在的错误以及其他代码维护问题。typedef的用法typdef常用来定义一个标识符以及关键字的别名,它是语言编译过程的一部分,但它并不实际分配内存空间。在刷笔试题的时候有问到这个:test.c文件中包括如下语句:#de...原创 2020-01-26 15:30:59 · 404 阅读 · 0 评论 -
C/C++:assert()断言的用法
assert宏的原型定义在<assert.h>中作用:如果它的条件返回错误,则终止程序执行。原型定义:#include <assert.h>void assert( int expression );assert的作用是先计算表达式 expression ,如果其值为假(即为0),那么它先向 stderr 打印一条出错信息,然后通过调用 abort 来终止程序运...原创 2020-01-18 14:22:36 · 850 阅读 · 0 评论 -
C:动态存储通讯录的实现(可文件存储)
test.c#define _CRT_SECURE_NO_WARNINGS#include <stdio.h>#include <string.h>#include <stdlib.h>#include "MailList.h"//引用两次会出现重定义现象int menu(){ int tmp, ret; printf("0. 退出\n"...原创 2020-01-13 23:51:01 · 321 阅读 · 0 评论 -
C:八种基本排序——选择排序(2)
选择排序原理:从头至尾扫描序列,找出最小的一个元素,和第一个元素交换,接着从剩下的元素中继续这种选择和交换方式,最终得到一个有序序列。思路:在长度为N的无序数组中,第一次遍历n-1个数,找到最小的数值与第一个元素交换;第二次遍历n-2个数,找到最小的数值与第二个元素交换;……第n-1次遍历,找到最小的数值与第n-1个元素交换,排序完成。图解选择排序:算法分析:排序算法...原创 2019-12-08 18:17:14 · 838 阅读 · 0 评论 -
C/C++:struct 与 typedef struct的使用区别
1.首先:注意在C和C++里不同在C中定义一个结构体类型要用typedeftypedef struct Student{ int a;}Stu;于是在声明变量的时候就可:Stu stu1;(如果没有typedef就必须用struct Student stu1;来声明)这里的Stu实际上就是struct Student的别名。Stu==struct Student另外这里也可以不写S...原创 2019-12-05 01:50:05 · 251 阅读 · 0 评论 -
C:文件操作相关的函数的使用细则
文件的打开和关闭文件在读写之前应该先打开文件,在使用结束之后应该关闭文件。在编写程序的时候,在打开文件的同时,都会返回一个FILE*的指针变量指向该文件,也相当于建立了指针和文件 的关系。ANSIC 规定使用fopen函数来打开文件,fclose来关闭文件。打开方式如下:FILE * fopen ( const char * filename, const char * mode );...原创 2019-12-03 19:47:43 · 469 阅读 · 0 评论 -
printf,sprintf,fprintf的区别和用法
三个函数的目的一致,即输出格式化的文本内容至屏幕。一、输出目标不同printf,是把格式化字符串输出到标准输出,即标准输出文件,对应终端的屏幕。sprintf,是把格式化字符串输出到指定字符串,也可作为缓冲区,而printf只能输出到命令行上。fprintf,是把格式化字符串输出到指定文件中。二、函数原型不同printf函数原型 int printf ( const...原创 2019-11-26 17:19:07 · 371 阅读 · 0 评论 -
关于C/C++前置++与后置++的区别与习题
本题相信大多数人都是对D选项有疑惑:D选项,函数的参数是从右向左压栈的,输出时从栈顶开始,相当于: int i = 3; ++i; ++i; printf("%d,%d",i,i);所以是 5,5;再举一个例子,int i = 1; printf("%d,%d", i += 2, i *= 3); 在输出i之前先进行了i *= 3和 i += 2;最终i = 5;所以结果是5,5;下面是...原创 2019-11-25 18:11:27 · 1037 阅读 · 0 评论 -
详解sizeof与strlen的区别~~
区别:一、定义不同sizeof是运算符,在头文件中typedef为unsigned int,其值在编译时即计算好了,参数可以是数组、指针、类型、对象、函数等。2、它的功能是:获得保证能容纳实现所建立的最大对象的字节大小。具体而言,当参数分别如下时,sizeof返回的值表示的含义如下:数组——编译时分配的数组空间大小;指针——存储该指针所用的空间大小(存储该指针的地址的长度,是长整型,应该为4...原创 2019-11-25 11:35:47 · 1647 阅读 · 0 评论 -
面试题之GetMemory关于内存的详解
题目一:void GetMemory(char *p){ p = (char *)malloc(100);}void Test(void){ char *str = NULL; GetMemory(str);//目的是通过此函数给str空间 strcpy(str, "hello world"); printf(str);}出现问题:在函数内部修...原创 2019-11-12 14:34:22 · 801 阅读 · 0 评论 -
结构体、枚举与联合(共用体)的应用(内存对齐规则)
C语言的数据类型如下图所示:结构体结构体类型创建定义:结构是一些值的集合,这些值称为成员变量。结构的每个成员可以是不同类型的变量。结构:struct 结构体名{ 成员列表};声明与定义:例如将学生的信息定义为结构体:struct Stu { char name[20];//名字 int age;//年龄 char sex[5];//性别 char id...原创 2019-11-01 09:36:22 · 945 阅读 · 0 评论 -
C:轻松理解 strcpy、strcat、strcmp(P:扩展)
strncpy原型:char * strncpy (char * destination, const char * source, size_t num );destination:目的字符串source:源字符串num:复制字符个数原理:拷贝num个字符从源字符串到目标空间。如果源字符串的长度小于num,则拷贝完源字符串之后,在目标的后边追加0,直到num个。代码实现:#...原创 2019-10-31 12:12:29 · 398 阅读 · 0 评论