C语言进阶之路之内存镜像与字符操作函数篇

news2024/11/29 13:51:23

目录

一、学习目标:

二、内存镜像

什么是进程

C进程内存布局

栈内存

静态数据

数据段(存储静态数据)与代码段

堆内存

三、字符操作函数

函数strstr

函数strlen

strlen与sizeof的区别

函数strtok

函数strcat与strncat

函数strcpy与strncpy

函数strcmp与strncmp

函数strchr与strrchr

四、总结


一、学习目标:

  • 知识点:
    • 一文掌握 C 语内存镜像关系
    • 掌握编程时各代码位置的实际分布内存
    • 简单了解字符操作函数的应用

二、内存镜像

什么是进程

        进程与程序的关系:

                程序: 是一个静态的文件,文件内存储的是一系列的二进制执行指令 (gcc hello.c -o hello ) 其中 Hello 就是一个程序文件。

                进程:则是把一个程序文件加载到内存中由 CPU 去执行对应的指令的一个过程,因此进程是一个动态的过程,这个动态的过程会有一些列对与内存的申请和释放操作。

                本小节就详细了解进程在运行过程中究竟是怎么申请内存空间,以及申请到的内存分别有什么特性。

C进程内存布局

        任何一个程序,正常运行都需要内存资源,用来存放诸如变量、常量、函数代码等等。这些不同的内容,所存储的内存区域是不同的,且不同的区域有不同的特性。因此我们需要研究财经处内存布局,逐个了解不同内存区域的特性。

        每个C语言进程都拥有一片结构相同虚拟内存,所谓的虚拟内存,就是从实际物理内存映射出来的地址规范范围,最重要的特征是所有的虚拟内存布局都是相同的,极大地方便内核管理不同的进程。例如三个完全不相干的进程p1、p2、p3,它们很显然会占据不同区段的物理内存,但经过系统的变换和映射,它们的虚拟内存的布局是完全一样的。

  • PM:Physical Memory,物理内存。
  • VM:Virtual Memory,虚拟内存。

将其中一个C语言含如进程的虚拟内存放大来看,会发现其内部包下区域:

  • 栈(stack)
  • 堆(heap)
  • 数据段
  • 代码段

        虚拟内存中,内核区段对于应用程序而言是禁闭的,它们用于存放操作系统的关键性代码,另外由于 Linux 系统的历史性原因,在虚拟内存的最底端 0x0 ~ 0x08048000 之间也有一段禁闭的区段,该区段也是不可访问的。

虚拟内存中各个区段的详细内容:

栈内存

  • 什么东西存储在栈内存中?
    • 环境变量 (比如库文件的路径、头文件的路径、可执行文件的路径等都被记录与环境变量中)
    • 命令行参数  (比如执行程序时从命令行中携带的参数:./a.out 123 456 Hello  )
    • 局部变量(包括形参)  (所有在函数体内定义的变量)
  • 栈内存有什么特点?
    • 空间有限,尤其在嵌入式环境下。因此不可以用来存储尺寸太大的变量
    • 每当一个函数被调用栈就会向下增长一段,用以存储该函数的局部变量
    • 每当一个函数退出,栈就会向上缩减一段,将该函数的局部变量所占内存归还给系统

  • 注意:

栈内存的分配和释放,都是由系统规定的,我们无法干预。

void func(int a, int *p) // 在函数 func 的栈内存中分配
{
    double f1, f2;        // 在函数 func 的栈内存中分配
    ...                   // 退出函数 func 时,系统的栈向上缩减,释放内存
}

int main(void)
{
    int m  = 100;  // 在函数 main 的栈内存中分配
    func(m, &m);  // 调用func时,系统的栈内存向下增长
}

地址验证:

#include <stdio.h>
#include <stdlib.h>

int main(int argc, char const *argv[])
{
    
    char * path =  getenv("PATH");
    
    int a = 123 ;
    char * ptr = NULL ;

    // 输出各项地址  高地址 --> 低地址
    printf("***********环境变量**********\n");
    printf("path:%p\n" , path );


    printf("***********命令行参数**********\n");
    for (int i = 0; i < argc; i++)
    {
        printf("argv[%d]:%p\n" ,  i , argv[i]  );
    }
    

    printf("***********局部变量**********\n");
    printf("argc:%p\n" , &argc);
    printf("argv:%p\n" , &argv);
    printf("path:%p\n" , &path);
    printf("a:%p\n" , &a);
    printf("ptr:%p\n" , &ptr);


    return 0;
}

静态数据

C语言中,静态数据有两种

  • 全局变量:定义在函数外部的变量。 (定义在函数体之外)
  • 静态局部变量:定义在函数内部,且被static修饰的局部变量
  • 示例:
int a; // 全局变量,退出整个程序之前不会释放
void f(void)
{
    static int b; // 静态局部变量,退出整个程序之前不会释放
    printf("%d\n", b);
    b++;
}

int main(void)
{
    f();
    f(); // 重复调用函数 f(),会使静态局部变量 b 的值不断增大
}

为什么需要静态数据?

  1. 全局变量在默认的情况下,对所有文件可见,为某些需要在各个不同文件和函数间访问的数据提供操作上的方便。
  2. 当我们希望一个函数退出后依然能保留局部变量的值,以便于下次调用时还能用时(记录上一次调用时的状态),静态局部变量可帮助实现这样的功能。
  • 注意1:
    • 定义时未初始化,则系统会将所有的静态数据自动初始化为0
    • 静态数据初始化语句,只会执行一遍
    • 静态数据从程序开始运行时便已存在,直到程序退出时才释放
  • 注意2:
    • static修饰局部变量:使之由内存临时数据,变成了静态数据存储于数据段中
    • static修饰全局变量:使之由各文件可见的静态数据,变成了本文件可见的静态数据。
    • static修饰函数:使之由各文件可见的函数,变成了本文件可见的静态函数

数据段(存储静态数据)与代码段

  • 数据段细分成如下几个区域
    • .bss 段:存放未初始化的静态数据,它们将被系统自动初始化为0
    • .data段:存放已初始化的静态数据
    • .rodata段:存放常量数据 (ro -> read Only )
  • 代码段细分成如下几个区域:
    • .text段:存放用户代码 (比如自己写的函数 main \ func \ test)
    • .init段:存放系统初始化代码( 由对应的编译器自动添加到程序中去 用于初始化该程序的内存空间)

int a;       // 未初始化的全局变量,放置在.bss 中
int b = 100; // 已初始化的全局变量,放置在.data 中

int main(void)
{
    static int c;       // 未初始化的静态局部变量,放置在.bss 中
    static int d = 200; // 已初始化的静态局部变量,放置在.data 中
    
    // 以上代码中的常量100、200防止在.rodata 中
}
  • 注意:数据段和代码段内存的分配和释放,都是由系统规定的,我们无法干预。

const + static 同时修饰一个变量:

// 被static 修饰后 kk 的内存在数据段中申请
//  再加一个 修改 const 则修饰为 read only  数据
//    最终 kK 的内存被分配到 .rodata
const static int kk = 123 ;  // 存储于.rodata 不允许修改
// int * p_kk = &kk ;
// *p_kk = 4333 ;  // 尝试从侧面偷偷修改这个数据会导致段错误


// const 修改一个普通的变量,并不会改变该变量的存储区域,因此它依然在栈中
const int bb = 456 ; // 存储于栈 可以被偷偷修改
int * p_bb = &bb ;
*p_bb = 45435 ;
printf("bb:%d\n" , bb );

堆内存

        堆内存(heap)又被称为动态内存自由内存,简称堆。堆是唯一可被开发者自定义的区段,开发者可以根据需要申请内存的大小、决定使用的时间长短等。但又由于这是一块系统“飞地”,所有的细节均由开发者自己把握系统不对此做任何干预,给予开发者绝对的“自由”,但也正因如此,对开发者的内存管理提出了很高的要求。对堆内存的合理使用,几乎是软件开发中的一个永恒的话题。

  • 堆内存基本特征:
    • 相比栈内存,堆的总大小仅受限于物理内存,在物理内存允许的范围内,系统对堆内存的申请不做限制
    • 相比栈内存,堆内存从下往上增长
    • 堆内存是匿名的,只能由指针来访问
    • 自定义分配的堆内存,除非开发者主动释放,否则永不释放直到程序退出

  • 相关API:
    • 申请内存:malloc() / calloc() /realloc () / reallocarray()
    • 清零堆内存:bzero()
    • 设置内存值:memset ()
    • 释放堆内存:free()

API 分析:

        malloc (配置内存空间)

头文件 :
    #include <stdlib.h> 
定义函数 :
    void *malloc(size_t size); 
参数分析:
    size --> 需要申请的堆内存区的大小
返回值:
    若配置成功则返回一指针,指向该内存区
    失败则返回 NULL.

        free (释放原先配置的内存)

头文件:
    #include <stdlib.h> 
定义函数:
    void free(void *ptr); 
参数分析:
    ptr --> 需要释放的内存空间的【入口地址】
返回值:
    无

        calloc (配置内存空间)

        该函会把申请到的内存空间进行初始化清空为 0 ,而malloc 则不会进行初始化操作;

头文件:
    #include <stdlib.h> 
定义函数:
    void *calloc(size_t nmemb, size_t size); 
参数分析:
    nmemb  --> 需要申请连续内存卡的数量
    size -->  每一个内存块的大小
返回值:
    成功: 返回成功申请到的堆内存地址
    失败: 返回 NULL 

        memset (将一段内存空间填入某值)


头文件:
    #include <string.h> 
定义函数:
    void * memset(void *s, int c, size_t n); 
参数分析:
    s --> 需要设置的数据
    c --> 需要设置的具体数据的值 【必须是 一个字节的大小 0 - 255】
    n --> 需要设置的内存区大小
返回值:
    成功:返回 s 指针
    失败:返回NULL 

实例:

// 进按字节行设置
// 从ptr 开始 按【每一个字节】填入一个 97 一共填入 6个
memset( ptr , 97 , 6 );
memset( ptr , 'a' , 6 );
bzero ( ptr , 6  ) ; // 设置ptr 的前6个字节的内存空间为 0 

        realloc (重新对堆内存空间进行调整(大小))

void *realloc(void *ptr, size_t size); 

参数分析:
    ptr --> 需要重新设置的内存入口地址
    size --> 新的大小 , 如果为 0 则相当于free 释放现有的内存
返回值:
    成功 返回新的入口地址 , 并free原先的地址
    失败 返回NULL 

注意:

        如果发生地址移动则该函数会释放原先的地址

        并把原先内存中的数据拷贝到新地址中

        如果是缩小的一般会不出现新的地址, 但是后面的数据不应该再进行访问,属于非法。

        reallocarray (重新对堆内存空间进行调整(大小))

 void *reallocarray(void *ptr, size_t nmemb, size_t size);
 
 函数分析:
     ptr --> 需要调整大小的地址
     nmemb --> 新内存的数量 (多少块)
     size --> 每一块的大小
 返回值:
    成功 返回新的入口地址, 并free原先的地址
    失败 返回NULL 
  • 注意:
    • malloc()申请的堆内存,默认情况下是随机值(不会清空内存),一般需要用 bzero() 、 memset() 来清零
    • calloc()申请的堆内存,默认情况下是已经清零了的,不需要再清零。
    • free()只能释放堆内存,并且只能释放整块堆内存(并且参数ptr必须是申请时的入口地址)不能释放别的区段的内存或者释放一部分堆内存。
  • 释放内存的含义:
    • 释放内存意味着将内存的使用权归还给系统
    • 释放内存并不会改变指针的指向
    • 释放内存并不会对内存做任何修改,更不会将内存清零
    • 因此在free(ptr ) 之后,ptr 变成了一个野指针, 应该 ptr = NULL ;

三、字符操作函数

函数strstr

  • 示例:
char *s = "abcd.txt";
char *p = strstr(s, ".wps");

if(p == NULL)
    printf("文件[%s]不是WPS文件\n", s);
else
    printf("文件[%s]是WPS文件\n", s);

函数strlen

  • 示例:
char *s = "www.yueqian.com.cn";
printf("粤嵌官网地址的长度是:%d\n", strlen(s));

strlen与sizeof的区别

char * msg = "Hello \0 Even Nihao GZ2351";

    // strlen 计算的过程中遇到 \0 结束符则直接停止工作,
    // 因此, 对于以上例子中 msg 内有 \0 则结算到该结束符就停止计算并返回
    size_t len =  strlen(msg);
    
    printf("Len:%ld\n" ,  len );


    // strlen 与sizeof 的区别:
    // strlen 计算的是字符串的长度
    // sizeof 计算的是变量或类型的大小
    size_t size =  sizeof(msg);
    printf("size:%ld\n" , size);
    


    char arr [] = "Hello GZ2351";
    printf("strlen(arr):%ld\n" , strlen(arr)); // 计算数据的长度
    printf("sizeof(arr):%ld\n" , sizeof(arr)); // 计算变量的大小

    // bzero(arr , 100);
        //             数组总大小 / 某个元素大小 *  每一个元素的尺寸  = 数组所占内存尺寸
    memset(arr , 0 , sizeof(arr)/sizeof(arr[0]) * sizeof(char) );
    printf("strlen(arr):%ld\n" , strlen(arr)); // 计算数据的长度  0
    printf("sizeof(arr):%ld\n" , sizeof(arr)); // 计算变量的大小  100

函数strtok

  • 注意:
    1. 该函数会将改变原始字符串 str,使其所包含的所有分隔符变成结束标记 ‘\0’
    2. 由于该函数需要更改字符串 str,因此 str 指向的内存必须是可写的。
    3. 首次调用时 str 指向原始字符串,此后每次调用 str 用 NULL 代替
    4. 参数delim 是一个字符串,实际上会认为给字符串中的没有给字符都是分隔符。如 delime = "-@;" 在分割的过程中只要与到- 或 @ 或 ; 都会进行分割
  • 示例:
char s[20] = "www.yueqian.com.cn";

char *p = strtok(s, ".");  // 首次调用时,s 指向需要分割的字符串
while(p != NULL)
{
    printf("%s\n", p);
    p = strtok(NULL, "."); // 此后每次调用,均使用 NULL 代替。
}

注:上述代码的运行结果就是将字符串 s 拆解为"www"、“yueqian”、“com” 和 “cn”

函数strcat与strncat

  • 注意:
    1. 这两个函数的功能,都是将 src 中的字符串,复制拼接到 dest 的末尾
    2. strcat() 没有边界控制,因此可能会由于 src 的过长而导致内存溢出
    3. strncat() 有边界控制,最多复制 n+1 个字符(其中最后一个是 ‘\0’ )到 dest 的末尾。
      1. n 的大小应该通过计算得到 目标地址的空余量 - 1
  • 示例:
char s1[10] = "abc";
strcat(s1, "xyz");
printf("%s\n", s1); // 输出 "abcxyz"

char s2[10] = "abc";
strcat(s3, "123456789"); // 此处操作内存溢出,可能会发生内存崩溃


char s[10]  = "abc";
strncat(s, "123456789", sizeof(s)-strlen(s)-1);
printf("%s\n", s); // 输出 "abc123456",两个字符串被拼接到了一起,且不会溢出
  • 注意:strncat()是具备边界检查的安全版本,推荐使用。

函数strcpy与strncpy

  • 注意:
    1. 这两个函数的功能,都是将 src 中的字符串,复制到 dest 中
    2. strcpy() 没有边界控制,因此可能会由于 src 的过长而导致内存溢出。
    3. strncpy() 有边界控制,最多复制 n-1 个字符其中最后一个是 ‘\0’ )到 dest 中。
char s1[5] = "abc";
strcpy(s1, "xyz);
printf("%s\n", s1); // 输出 "xyz",原有的"abc"被覆盖

char s2[5] = "abc";
strcpy(s2, "123456789"); // 此处操作内存溢出,可能会发生内存崩溃
  • 注意:strncpy()是具备边界检查的安全版本推荐使用

函数strcmp与strncmp

  • 注意:
    • 比较字符串大小,实际上比较的是字符的 ASCII码值的大小。
    • 从左到右逐个比较两个字符串的每一个字符,当能“决出胜负”时立刻停止比较。
  • 示例:
printf("%d\n", strcmp("abc", "abc")); // 输出0,两个字符串相等
printf("%d\n", strcmp("abc", "aBc")); // 输出1,"abc" 大于 "aBc"
printf("%d\n", strcmp("999", "aaa")); // 输出-1,"999" 小于 "aaa"

函数strchr与strrchr

  • 注意:
    1. 这两个函数的功能,都是在指定的字符串 s 中,试图找到字符 c。
    2. strchr() 从左往右找,strrchr() 从右往左找。
    3. 字符串结束标记 ‘\0’ 被认为是字符串的一部分。

         memcmp (比较内存内容)

头文件:
    #include <string.h> 
定义函数:
    int memcmp (const void *s1, const void *s2, size_t n); 
参数分析:
    s1  -->  需要比较的内存1 
    s2  -->  需要比较的内存1 
    n   --> 需要比较的内存区大小
返回值:
    相同 返回 0 
    不同 返回差值

        memcpy (内存内容的拷贝)

头文件:
    #include <string.h>
函数原型:
    void *memcpy(void *dest, const void *src, size_t n); 
参数分析:    
    dest  --> 目标地址
    src   -->  原地址
    n     -->  期望拷贝的字节数
返回值:
    成功返回 dest 
    失败返回  NULL 

总结:

        strxxxx 类型的函数在执行过程中有多个结束条件

  •                         遇到字符串中的 '\0' 结束符
  •                         如果strnxxx 则到达一个指定的大小条件
strcpy( buf1 , buf2 ); // 结束条件只有一个 遇到\0 结束符
strncpy( buf1 , buf2 , 10 ); // 结束条件有两个 : 遇到\0 结束符 + 达到期望值10个字节

        memxxx 类型的函数他执行过程中只有一个结束条件,就是达到用户的期望值。遇到结束符则把结束符也当成比较或拷贝的目标

四、总结

        本文介绍了C的编程时各代码位置的实际分布内存,还有字符操作函数等其他知识。理解本文所有知识点后,便可打败其中的小怪,拿下经验值~

        本文参照 粤嵌文哥 部分课件经整理和修改后发布在C站,如有转载,请联系本人

本文来自互联网用户投稿,该文观点仅代表作者本人,不代表本站立场。本站仅提供信息存储空间服务,不拥有所有权,不承担相关法律责任。如若转载,请注明出处:http://www.coloradmin.cn/o/1290934.html

如若内容造成侵权/违法违规/事实不符,请联系多彩编程网进行投诉反馈,一经查实,立即删除!

相关文章

PyTorch 基础篇(2):线性回归(Linear Regression)

# 包import torchimport torch.nn as nnimport numpy as npimport matplotlib.pyplot as plt # 超参数设置input_size 1output_size 1num_epochs 60learning_rate 0.001 # Toy dataset # 玩具资料&#xff1a;小数据集x_train np.array([[3.3], [4.4], [5.5], [6.71], [6.…

强敌环伺:金融业信息安全威胁分析——钓鱼和恶意软件

门口的敌人&#xff1a;分析对金融服务的攻击 Akamai会定期针对不同行业发布互联网状态报告&#xff08;SOTI&#xff09;&#xff0c;介绍相关领域最新的安全趋势和见解。最新的第8卷第3期报告主要以金融服务业为主&#xff0c;分析了该行业所面临的威胁和Akamai的见解。我们发…

浪潮信息KeyarchOS EDR 安全防护测评

背景 近几年服务器安全防护越来越受到企业的重视&#xff0c;企业在选购时不再仅仅看重成本&#xff0c;还更看重安全性&#xff0c;因为一旦数据泄露&#xff0c;被暴力破解&#xff0c;将对公司业务造成毁灭性打击。鉴于人们对服务器安全性的看重&#xff0c;本篇文章就来测…

智能外呼是什么?智能外呼怎么样?

智能外呼是什么&#xff1f; 当今业务通讯领域&#xff0c;智能外呼已经成为了一种普遍应用的技术。智能外呼是利用人工智能技术和自动化系统来进行电话呼叫和信息传递的一种方式。它可以帮助企业有效地进行市场营销和客户服务&#xff0c;极大地提高工作效率。 智能外呼系统…

HarmonyOS4.0从零开始的开发教程01运行Hello World

HarmonyOS&#xff08;一&#xff09;运行Hello World 下载与安装DevEco Studio 在HarmonyOS应用开发学习之前&#xff0c;需要进行一些准备工作&#xff0c;首先需要完成开发工具DevEco Studio的下载与安装以及环境配置。 进入DevEco Studio下载官网&#xff0c;单击“立即…

点滴生活记录1

2023/10/10 今天骑小电驴上班&#xff0c;带着小鸭子一起。路上的时候&#xff0c;我给小鸭子说&#xff0c;你要帮我看着点路&#xff0c;有危险的时候提醒我&#xff0c;也就刚说完没几分钟&#xff0c;一个没注意&#xff0c;直接撞到一个拦路铁墩子上&#xff0c;车子连人歪…

流量异常-挂马造成百度收录异常关键词之解决方案(虚拟主机)

一.异常现象&#xff1a;流量突然暴涨&#xff0c;达到平时流量几倍乃至几十倍&#xff0c;大多数情况下因流量超标网站被停止。 二.排查原因&#xff1a; 1.首先分析web日志&#xff1a;访问量明显的成倍、几十倍的增加&#xff1b;访问页面不同&#xff1b;访问IP分散并不固…

2023 IoTDB 用户大会成功举办,深入洞察工业互联网数据价值

2023 年 12 月 3 日&#xff0c;中国通信学会作为指导单位&#xff0c;Apache IoTDB Community、清华大学软件学院、中国通信学会开源技术委员会联合主办&#xff0c;“科创中国”开源产业科技服务团和天谋科技&#xff08;北京&#xff09;有限公司承办的 2023 IoTDB 用户大会…

深度学习(六):paddleOCR理解及识别手写体,手写公式,表格

1.介绍 1.1 什么是OCR? 光学字符识别&#xff08;Optical Character Recognition, OCR&#xff09;&#xff0c;ORC是指对包含文本资料的图像文件进行分析识别处理&#xff0c;获取文字及版面信息的技术&#xff0c;检测图像中的文本资料&#xff0c;并且识别出文本的内容。…

JVM 执行引擎篇

机器码、指令、汇编语言 机器码 各种用二进制编码方式表示的指令&#xff0c;叫做机器指令码。开始&#xff0c;人们就用它采编写程序&#xff0c;这就是机器语言。机器语言虽然能够被计算机理解和接受&#xff0c;但和人们的语言差别太大&#xff0c;不易被人们理解和记忆&a…

Centos服务器上根据端口号查询jar包,根据jar包查端口号

在开发springboot服务器时&#xff0c;经常会遇到其他人部署的java服务&#xff0c;需要自己维护&#xff0c;留下的信息又非常少。经常面临找不到jar包位置&#xff0c;或者不知道占用端口&#xff0c;不知道启动命令的问题。这里记录一下常用的centos服务器上的命令&#xff…

物联网安全芯片ACL16 采用 32 位内核,片内集成多种安全密码模块 且低成本、低功耗

ACL16 芯片是研制的一款32 位的安全芯片&#xff0c;专门面向低成本、低功耗的应用领域&#xff0c; 特别针对各类 USB KEY 和安全 SE 等市场提供完善而有竞争力的解决方案。芯片采用 32 位内核&#xff0c;片内集成多种安全密码模块&#xff0c;包括SM1、 SM2、SM3、 SM4 算法…

103.进程概述

目录 1.并行和并发 区别&#xff1a; 2.PCB 3.进程状态 4. 进程命令 从严格意义上来讲&#xff0c;程序和进程是两个不同的概念&#xff0c;他们的状态&#xff0c;占用的系统资源都是不同的。 程序&#xff1a;程序是一种静态实体&#xff0c;是存储在计算机存储介质上的…

docker基本管理和相关概念

1、docker是什么&#xff1f; docker是开源的应用容器引擎。基于go语言开发的&#xff0c;运行在Linux系统当中开源轻量级的“虚拟机”。 docker可以在一台主机上轻松的为任何应用创建一个轻量级的&#xff0c;可移植的&#xff0c;自给自足的容器。docker的宿主机是Linux系统…

5 TF-A

一、TF-A的使用 TF-A是什么&#xff1f; TF-A 全称是 Arm Trusted Firmware&#xff0c;TF-A是为了保证安全&#xff0c;arm退出的可信固件&#xff0c;简称TF-A。它的作用就是隔离硬件&#xff0c;为硬件提供一个安全环境并提供安全服务。 1. 系统源码获取 STM32MP1Dev - STM…

【算法】约瑟夫环

约瑟夫问题是个有名的问题&#xff1a;N个人围成一圈&#xff0c;从第一个开始报数&#xff0c;第M个将被杀掉&#xff0c;最后剩下一个&#xff0c;其余人都将被杀掉。例如N6&#xff0c;M5&#xff0c;被杀掉的顺序是&#xff1a;5&#xff0c;4&#xff0c;6&#xff0c;2&a…

软件测试外包干了2个月,技术进步2年。。。

先说一下自己的情况&#xff0c;本科生&#xff0c;18年通过校招进入北京某软件公司&#xff0c;干了接近2年的功能测试&#xff0c;今年国庆&#xff0c;感觉自己不能够在这样下去了&#xff0c;长时间呆在一个舒适的环境会让一个人堕落!而我已经在一个企业干了2年的功能测试&…

WireShark监控浏览器登录过程网络请求

软件开发中经常前后端扯皮。一种是用Chrome浏览器的开发者工具 来看网络交互&#xff0c;但是前提是 网络端口的确是通的。 WireShark工作在更低层。 这个工具最大的好处&#xff0c;大家别扯皮&#xff0c;看网络底层的log&#xff0c;到底 你的端口开没开&#xff0c; 数据…

Day03 linux高级系统编程--进程

概念 进程与程序的区别 进程&#xff1a;一个正在运行的代码就叫做进程&#xff0c;是动态的&#xff0c;会占用内存 程序&#xff1a;一段封装好的待运行的代码或可执行文件&#xff0c;是静态的&#xff0c;会占用磁盘空间 单道与多道程序 单道&#xff1a;程序一个一个…