C++_辗转相除法—遍历和执行

辗转相除法

 欧几里德算法又称辗转相除法,用于计算两个整数a,b的最大公约数。
 其计算原理依赖于下面的定理:定理:divi(a, b) = divi(a, a%b)
 
###计算机--迭代的思想--递归
  //辗转相除法
  int divi_1(int a, int b)
  {
  	int divi = 0;
  	while (a%b)
  	{
  		divi = a % b;
  		a = b;
  		b = divi;
  	}
  	divi = b;
   
  	return divi;
  }

使用取余和除法操作来反转整数

主要过程--使用数学方法 以及关于溢出的判断
    // 弹出 x 的末尾数字 digit
    digit = x % 10
    x /= 10
    // 将数字 digit 推入 rev 末尾
    rev = rev * 10 + digit
###示例代码  假设环境不允许存储 64 位整数(有符号或无符号)
class Solution {
    public int reverse(int x) {
        int rev = 0;
        while (x != 0) {
		    //判断溢出,因为输入的是32位的有符号整数 x
             //即输入的 -2147483648<=x<=2147483647
             //所以翻转后的最后一位是1或2并不会导致溢出
             //因此只需判断九位数 > int.MaxValue / 10 或者 < int.MinValue / 10
            if (rev < Integer.MIN_VALUE / 10 || rev > Integer.MAX_VALUE / 10) {
                return 0;
            }
            int digit = x % 10;
            x /= 10;
            rev = rev * 10 + digit;
        }
        return rev;
    }
}

#### 按照字符串进行处理	
    实现字符串反转,包括 切片、reversed()、循环、递归、模拟栈操作等
	  遍历 :
	    使用 for 循环遍历   使用 for 循环和 range() 在遍历列表   使用列表推导式遍历列表
        使用 while 循环遍历 	
        使用 enumerate() 方法遍历列表   使用 zip() 遍历列表	
        使用 map() 和 lambda 遍历列表	使用迭代器 iter() 和 next() 遍历列表		
	方法:切片--   使用reversed()方法   模拟出栈pop()
          方法3:使用while循环
          方法4:使用for循环字符串拼接
          方法5:使用递归
		 len()
	数据结构:
	  语言对字符串提供了 split(拆分),reverse(翻转)和 join(连接)等方法,

    python :
	  a = '123456789'
      print(a[::-1])  # 利用字符串下标倒序输出
	  print(''.join(reversed('123456789')))
	  
    def reverse_string(str):
        l_str = list(str)  # 模拟全部入栈
        new_string = ""
        while len(l_str)>0:
            new_string += l_str.pop()  # 模拟出栈
        return new_string
	
	使用list循环获取,再转换成字符串类型
    def reverse_string_list(str):
        str_lis = [] # 定义空列表
        index = len(str)  # 字符串长度
        # 在str字符穿长度内执行循环语句,实现倒序输出
        while index:
            index -= 1                       
            str_lis.append(str[index])  # 将下标对应值输出到空列表str_lis中
        return ''.join(str_lis)

    def reverse_string(str):
        l = len(str)
        x=""
        for i in range(l-1,-1,-1):
            x += str[i]
        return x

    def reverse_string(s): 
        if len(s) == 1:  # 判断字符串长度是否只含有一位数字,若是直接返回,本身即为反转后的字符串
            return s
        str = s[-1] + reverse_string(s[:-1])  # 利用递归实现
        return str

C++遍历

 ### for 循环遍历
     数组指针  指针等
 ### while 循环遍历  
 ### range  for_each  
      for (auto& i: a){  // auto能够自动推导变量类型,引用类型除外
 ### 迭代器
     for(auto i = begin(a); i != end(a); i++){  // 成员函数begin()和end()来获取遍历开始地址和遍历结束地址,同时,迭代器使用之后会自动回收
###高阶
    std::transform
###遍历算法
   -深度优先遍历;3-广度优先遍历
   
   
###C++反转字符串
   C++标准库提供了一个名为std::reverse的函数,可以直接对字符串进行反转
   使用递归
   使用循环
    std::string reverseString(const std::string&amp; str) {
        std::string reversedStr;
        for (int i = str.length() - 1; i &gt;= 0; i--) {
            reversedStr += str[i];
        }
        return reversedStr;
    }	  
    std::string reverseString(const std::string&amp; str) {
        if (str.length() &lt;= 1) {
            return str;
        }
        return reverseString(str.substr(1)) + str[0];
    }

###使用头尾帧交换的方式	
双指针法,我们定义两个指针(也可以说是索引下标),一个从字符串前面,一个从字符串后面,两个指针同时向中间移动,并交换元素
class Solution {
public:
    void reverseString(vector<char>& s) {
        // 1.库函数:
        //reverse(s.begin(), s.end());
        // 2.双指针交换:
        for (int i = 0, j = s.size() - 1; i < j; i++, j--) {
            swap(s[i], s[j]);
        }
    }
};


 在遍历字符串的过程中,只要让 i += (2 * k),i 每次移动 2 * k 就可以了,然后判断是否需要有反转的区间。
  不用一个一个字符计数判断。
    class Solution {
    public:
        string reverseStr(string s, int k) {
            for (int i = 0; i < s.size(); i += (2 * k)) {
                // 1. 每隔 2k 个字符的前 k 个字符进行反转
                // 2. 剩余字符小于 2k 但大于或等于 k 个,则反转前 k 个字符
                if (i + k <= s.size()) {
                    reverse(s.begin() + i, s.begin() + i + k );
                } else {
                    // 3. 剩余字符少于 k 个,则将剩余字符全部反转。
                    reverse(s.begin() + i, s.end());
                }
            }
            return s;
        }
    };

应用--叠帧的场景

def reverseStr(timestamps_ls,step,ignore_num)
    cur_idex =0
	K = len(timestamps_ls)
	while(cur_index  < K):
	    target_ts = timestamps_ls[cur_idex]
		selectd = range(max(0,cur_idex),min(cur_idex+step,K))
		cur_idex += step
		ts_wind = [timestamps_ls[s] for s in selectd]
		if len(ts_wind) >= ignore_num:
		    for i,ts in enumerate(ts_wind):
			    pass
		else:
		    break

def reverseStr(timestamps_ls,step,ignore_num)
    cur_idex =0
	K = len(timestamps_ls)
    for( cur_idex = 0; cur_idex < K; cur_idex += step )
	    target_ts = timestamps_ls[cur_idex]	
	    selectd = range(max(0,cur_idex),min(cur_idex+step,K))
		ts_wind = [timestamps_ls[s] for s in selectd]
	    if len(ts_wind) >= ignore_num:
		    for i,ts in enumerate(ts_wind):
			    pass
		else:
		    break	

while循环是在进入循环之前
  先判断条件是否满足,
    如果条件为真,则执行循环体;
	如果条件不满足,则整个循环体一次都不执行。
而do-while循环是 
  先执行一次循环体,
      然后再判断条件是否满足,只有在条件为真的情况下,才会继续执行后续的循环体,
	  否则结束循环

while循环‌:需要手动定义和管理循环变量的状态
for 循环 
   for(单次表达式;条件表达式;末尾循环体)
     {中间循环体;}

逆向工程

分析二进制文件:
    使用逆向工程工具打开应用程序的二进制文件,进行分析。可以查看函数、变量、控制流等信息,理清应用程序的逻辑结构。
反汇编代码:
     对应用程序的二进制代码进行反汇编,将其转换成汇编代码进行分析。可以查看应用程序的底层执行逻辑,找出其中的漏洞或隐藏的功能。
调试应用程序:
     使用调试器如GDB对应用程序进行调试,可以逐步执行代码并查看寄存器、内存等信息,帮助理解程序的行为。
动态分析:
        通过动态分析可以在运行时跟踪应用程序的执行过程,监视其行为并分析其运行时状态。可以使用工具如strace、ltrace等进行API调用和库函数跟踪。
修改和重构代码:
      通过逆向工程可以了解应用程序的内部结构和逻辑,可以对其进行修改和重构,实现定制化功能或漏洞修复。
在Linux环境下进行C++应用的逆向工程通常可以通过以下步骤来实现:
     使用逆向工程工具:在Linux下有许多强大的逆向工程工具可供选择,如IDA Pro、Ghidra、Radare2等
	   这些工具能够帮助分析和反汇编应用程序的二进制代码,还可以进行静态和动态分析。
readelf, objdump, ldd, xxd,hexdump, dd, strace,   	   
    2 使用ldd探索依赖性
  	3 使用xxd查看文件内容
  	4 使用readelf解析并提取ELF库文件
  	5 使用nm解析符号 C++编译器提出了符号修饰(mangled name)。符号修饰实质上是原始函数名称与函数参数编码的组合。这样,函数的每个版本都会获得唯一的名
  	6 使用strings查看Hints
  	7 使用strace和ltrace跟踪系统调用和库文件调用
  	8 使用 objdump 检查指令集行为
  	9 使用GDB转储动态字符串缓冲区
  		
      GNU binutils    (配合gcc工作)
      GNU coreutils	  coreutils【对应的嵌入式场合,主要是 busybox 】 		 

汇编语句

    二进制指令是一样的
       JE(Jump if Equal)、JNE(Jump if Not Equal)、JG(Jump if Greater)、JL(Jump if Less)
    x86_64架构下的CPU有两种主要的汇编风格: Intel风格和AT&T风格。
	  支持Intel汇编风格的操作系统主要是Windows,
	  支持AT&T汇编风格的操作系统主要是Unix以及Unix-like操作系统
        AT&T汇编是从左向右执行   mov %ax, %bx   寄存器前面有一个%  字面量前面都有一个$
		Intel汇编是从右往左执行  mov bx, ax
	  控制转移包括jump、call、ret 
    编译过程 
      -g   -g可执行程序包含调试信息  为了调试用的  加个-g 是为了gdb 用,不然gdb用不到		
	  -c    只编译不链接  产生.o文件,就是obj文件,不产生执行文
	  -Wall 选项意思是编译后显示所有警告
	 
    在CMakeLists.txt 中 
	  add_definitions("-Wall -g")
      set(CMAKE_BUILD_TYPE "Debug")
	  
	  
	obj  objdump 用来显示一个或者多个目标文件的信息		 
	 -d:将代码段反汇编
     -S:将代码段反汇编的同时,将反汇编代码和源代码交替显示,编译时需要给出-g,即需要调试信息 
	
     objdump  -S -C -d a.out

参考

反转字符串——Python笔试题干货 https://blog.csdn.net/qq_39312119/article/details/135343897		
C/C++逆向:循环语句逆向分析 https://blog.csdn.net/WolvenSec/article/details/142535149	
posted @ 2024-12-16 13:37  辰令  阅读(196)  评论(0)    收藏  举报