【CSAPP】家庭作业2.55~2.76
文章目录
- 2.55*
- 2.56*
- 2.57*
- 2.58**
- 2.59**
- 2.60**
- 位级整数编码规则
- 2.61**
- 2.62***
- 2.63***
- 2.64*
- 2.65****
- 2.66***
- 2.67**
- 2.68**
- 2.69***
- 2.70**
- 2.71*
- 2.72**
- 2.73**
- 2.74**
- 2.75***
- 2.76*
2.55*
问:在你能访问的不同的机器上,编译show_bytes.c
并运行代码,确定这些机器的字节顺序。
答:
// show_bytes.c
#include <stdio.h>typedef unsigned char *byte_pointer;void show_bytes(byte_pointer start, size_t len)
{for (size_t i = 0; i < len; ++i) {printf("%.2X ", start[i]);}printf("\n");
}void show_int(int x)
{show_bytes((byte_pointer)&x, sizeof(int));
}
在x86_64
上,运行结果为:
// show_int(0x87654321);
[liheng@localhost2 2]$ ./a.out
21 43 65 87
低位字节保存在低地址,该机器按小端顺序存储多字节对象。
2.56*
问:试着用不同的示例值来运行show_bytes.c
。
答:
// show_int(0x11223344);
[liheng@localhost2 2]$ ./a.out
44 33 22 11
// show_int(0x22);
[liheng@localhost2 2]$ ./a.out
22 00 00 00
// show_int(0x11000000);
[liheng@localhost2 2]$ ./a.out
00 00 00 11
2.57*
问:编写并运行程序show_short
、show_long
和show_double
。
答:
void show_short(short x)
{show_bytes((byte_pointer)&x, sizeof(short));
}void show_long(long x)
{show_bytes((byte_pointer)&x, sizeof(long));
}void show_double(double x)
{show_bytes((byte_pointer)&x, sizeof(double));
}
在x86_64
上,运行结果为:
// show_short(0x1234);
// show_long(0x1234);
// show_double(0x1234);
[liheng@localhost2 2]$ ./a.out
34 12
34 12 00 00 00 00 00 00
00 00 00 00 00 34 B2 40
// show_short(0x1030);
// show_long(0x1030);
// show_double(0x1030);
[liheng@localhost2 2]$ ./a.out
30 10
30 10 00 00 00 00 00 00
00 00 00 00 00 30 B0 40
2.58**
问:编写过程is_little_endian
,当在小端法机器上运行时返回1
,否则返回0
。
答:
int is_little_endian()
{uint32_t x = 0x12345678; // #include <stdint.h>return *(uint8_t *)&x == (uint8_t)0x78;
}
在x86_64
上,运行结果为:
// printf("is_little_endian: %d\n", is_little_endian());
[liheng@localhost2 2]$ ./a.out
is_little_endian: 1
2.59**
问:编写一个C
表达式,它生成一个字,由x
的最低有效字节和y
中剩下的字节组成。对于x = 0x89ABCDEF
、y = 0x76543210
得到0x765432EF
。
答:表达式为(x & 0xFF) | (y & ~0xFF)
。
2.60**
问:假设我们将一个w
位的字中的字节从0
(最低位字节)到w / 8 - 1
(最高位字节)编号,写出下面C
函数的代码,它会返回一个无符号值,其中参数x
的字节i
被替换成字节b
。
unsigned replace_byte(unsigned x, int i, unsigned char b);
// replace_byte(0x12345678, 2, 0xAB) --> 0x12AB5678
// replace_byte(0x12345678, 0, 0xAB) --> 0x123456AB
答:
replace_byte
的实现:
unsigned replace_byte(unsigned x, int i, unsigned char b)
{unsigned bits = i << 3;unsigned x1 = x & ~(0xFF << bits);unsigned b1 = b << bits;return x1 | b1;
}
在x86_64
上的运行结果:
// printf("%p\n", replace_byte(0x12345678, 4, 0xAB));
// printf("%p\n", replace_byte(0x12345678, 3, 0xAB));
// printf("%p\n", replace_byte(0x12345678, 2, 0xAB));
// printf("%p\n", replace_byte(0x12345678, 1, 0xAB));
// printf("%p\n", replace_byte(0x12345678, 0, 0xAB));
[liheng@localhost2 2]$ ./a.out
0x123456ab
0xab345678
0x12ab5678
0x1234ab78
0x123456ab
位级整数编码规则
在接下来的作业中,我们特意限制了你能使用的编程结构,来帮助你更好地理解C
语言的位级、逻辑和算术运算。你的代码必须遵守以下规则:
- 假设
- 整数用补码形式表示。
- 有符号数的右移是算术右移。
- 数据类型
int
是w
(一定是8
的整数倍)位长的。某些题目会给出w
的值。
- 禁止使用
- 条件语句
if
或? :
、循环、分支语句、函数调用和宏调用。 - 除法、模运算和乘法。
- 相对比较运算
<
、>
、<=
和>=
。
- 允许的运算
- 所有的位级和逻辑运算。
- 左移和右移,位移量只能在
0 ~ w-1
之间。 - 加法和减法。
- 相等
==
和不相等!=
。 - 整型常数
INT_MIN
和INT_MAX
。 - 对
int
和unsigned
进行隐式或显式强制类型转换。
个别题目有特殊的限制。
2.61**
问:写一个C
表达式,在下列描述的条件下产生1
,在其他情况下得到0
,假设x
是int
类型。
答:
x
的任何位都等于1
。
!~x
x
的任何位都等于0
。
!x;
x
的最低有效字节中的位都等于1
。
!~(x | ~0xFF)
x
的最高有效字节中的位都等于0
。
!((0xFF << ((sizeof(int) - 1) << 3)) & x);
2.62***
问:编写一个函数int_shifts_are_arithmetic()
,在对int
类型的数使用算术右移的机器上运行时这个函数返回1
,其他情况下返回0
。
答:
int int_shifts_are_arithmetic()
{int x = -1;return (x >> 8) == x; // return !(x ^ (x >> 8));
}
在x86_64
上的运行结果:
// printf("%d\n", int_shifts_are_arithmetic());
[liheng@localhost2 2]$ ./a.out
1
2.63***
问:将下面的C
函数代码补充完整。函数srl
用算术右移(由值xsra
给出)完成逻辑右移,后面的操作不包括右移或者除法。函数sra
用逻辑右移(由值xsrl
给出)来完成算术右移,后面的操作不包括右移或者除法。w = sizeof(int) * 8
,k
的取值范围是0 ~ w-1
。
答:
unsigned srl(unsigned x, in k)
{unsigned xsra = (int)x >> k; // 算术右移的值int mask = ((1 << k) - 1) << ((sizeof(int) << 3) - k);return xsra & ~mask;
}int sra(int x, int k)
{int xsrl = (unsigned)x >> k; // 逻辑右移的值int sign = !!(x & (1 << ((sizeof(int) << 3) - 1)));int mask = ((sign << k) - sign) << ((sizeof(int) << 3) - k);return xsrl | mask;
}
在x86_64
上的运行结果:
// printf("%p\n", srl(-1, 0));
// printf("%p\n", srl(-1, 16));
// printf("%p\n", srl(-1, 31));
// printf("%p\n", sra(-1, 0));
// printf("%p\n", sra(-1, 16));
// printf("%p\n", sra(-1, 31));
// printf("%p\n", sra(0x0F000000, 16));
[liheng@localhost2 2]$ ./a.out
0xffffffff
0xffff
0x1
0xffffffff
0xffffffff
0xffffffff
0xf00
2.64*
问:实现一个函数,入参是一个整型x
(w = 32
),如果有一个奇数位是1
,就返回1
,否则返回0
。
首先需要构造32
位的掩码10[10]...
,使用该掩码去掉x
中的偶数位,再判断奇数位是否存在一个1
。
32
位的掩码10[10]...
的十六进制表示为0x55555555
。
答:
int any_odd_one(unsigned x)
{int mask = 0x55555555;return x & mask;
}
在x86_64
机器上的运行结果:
// printf("%d\n", any_odd_one(0x1));
// printf("%d\n", any_odd_one(0x2));
[liheng@localhost2 2]$ ./a.out
1
0
2.65****
问:实现一个函数,入参是一个整型x
(w = 32
),当x
有奇数个值为1
的位时,返回1
,否则返回0
。
答:
int odd_ones(unsigned x)
{x ^= x >> 16;x ^= x >> 8;x ^= x >> 4;x ^= x >> 2;x ^= x >> 1;return x & 0x1;
}
第一个
^=
运算把x
的0~15
位和16~31
位的^
运算结果放在了x
的0~15
位;第二个^=
运算把x
(上一步的运算结果)的0~7
位和8~15
位的^
运算结果放在了x
的0~7
位,以此类推。最终x
的第0
位上放的就是初值的x
的所有位的^
结果。
1 ^ 1 = 0
、0 ^ 0 = 0
、1 ^ 0 = 1
,异或会抵消掉相同的位,把值归0
,且异或具有结合律。因此只要把x
中的所有位按任意顺序异或一遍,最终结果为1
的话就说明它包含奇数个值为1
的位。
在x86_64
机器上的运行结果:
// printf("%d\n", odd_ones(0x0)); // 0个值为1的位
// printf("%d\n", odd_ones(0x1)); // 1个值为1的位
// printf("%d\n", odd_ones(0x3)); // 2个值为1的位
// printf("%d\n", odd_ones(-1)); // 32个值为1的位
// printf("%d\n", odd_ones(369)); // 5个值为1的位
// printf("%d\n", odd_ones(11825)); // 7个值为1的位
[liheng@localhost2 2]$ ./a.out
0
1
0
0
1
1
2.66***
问:实现一个函数,入参是一个整型x
(w = 32
),返回一个掩码指示最高位的1
的位置。如输入0xFF00
返回0x8000
,输入0x6600
返回0x4000
,输入0
返回0
。
答:
int leftmost_one(unsigned x)
{x |= x >> 1;x |= x >> 2;x |= x >> 4;x |= x >> 8;x |= x >> 16;return (x >> 1) + !!x;
}
从
x
的值为1
的最高位算起往它的低位开始数,第一次|=
运算的结果把2
个位设置为1
,第二次|=
运算的结果把4
个位设置为1
,以此类推,把全32
位都设置为1
。最后把结果右移1
位再加1
,就得到了指示最高位的1
的位置的数。
在x86_64
机器上的运行结果:
// printf("%d\n", leftmost_one(0x0));
// printf("%p\n", leftmost_one(0xF));
// printf("%p\n", leftmost_one(0x6600));
// printf("%p\n", leftmost_one(0x8000));
// printf("%p\n", leftmost_one(0x46531));
// printf("%p\n", leftmost_one(-1));
[liheng@localhost2 2]$ ./a.out
0
0x8
0x4000
0x8000
0x40000
0x80000000
2.67**
问:实现一个函数,当在一个int
是32
位的机器上运行时,该程序产生1
,其他情况产生0
。不允许使用sizeof
。
下面是开始的尝试:
int bad_int_size_is_32()
{int set_msb = 1 << 31;int beyond_msb = 1 << 32;// set_msb非零时,int_size >= 32;beyond_msb为零时,int_size <= 32return set_msb && !beyond_msb;
}
当我们在SUN SPARC
这样的32
位机器上编译运行时,这个过程返回的却是0
。编译器打印了一句warning
:
warning: left shift count >= width of type
答:
- 我们的代码在哪个方面没有遵守
C
语言标准?
C
标准没有明确规定当移位操作的位数大于等于变量的宽度时的行为。有的机器上1 << 32
是零,有的机器上1 << 32
是非零(移位的位数%
(取模)变量的宽度)。上述代码预期在这种情况下,1 << 32
是零。
为了保证程序的可移植性,需要程序员保证移位数的取值范围是[0, w)
。 - 修改代码,使得它在
int
至少为32
位的机器上都能正确地运行。
int int_size_is_32()
{int set_msb = 1 << 31;int beyond_msb = set_msb << 1; // 确保在不同的机器上,程序的行为是一致的。// set_msb非零时,int_size >= 32;beyond_msb为零时,int_size <= 32return set_msb && !beyond_msb;
}
- 修改代码,使得它在
int
至少为16
位的机器上都能正确地运行。
int int_size_is_32()
{int set_msb = 1 << 15 << 15 << 1; // 保证左移行为符合预期int beyond_msb = set_msb << 1;// set_msb非零时,int_size >= 32;beyond_msb为零时,int_size <= 32return set_msb && !beyond_msb;
}
2.68**
问:实现一个函数,输入正整数n
(1≤n≤w)(1 \le n \le w)(1≤n≤w),返回低n
位均为1
的掩码值。如输入6
返回0x3F
,输入17
返回0x1FFFF
。
答:
int lower_one_mask(int n)
{return (unsigned)-1 >> ((sizeof(int) << 3) - n);
}
在x86_64
机器上的运行结果:
// printf("%d\n", lower_one_mask(0));
// printf("%p\n", lower_one_mask(6));
// printf("%p\n", lower_one_mask(17));
// printf("%p\n", lower_one_mask(31));
// printf("%p\n", lower_one_mask(32));
[liheng@localhost2 2]$ ./a.out
0
0x3f
0x1ffff
0x7fffffff
0xffffffff
2.69***
问:实现循环左移,0≤n<w0 \le n <w0≤n<w。如x = 0x12345678
、w = 32
,n = 4
返回0x23456781
,n = 20
返回0x67812345
。
答:
unsigned rotate_left(unsigned x, int n)
{unsigned low = x >> ((sizeof(unsigned) << 3) - n);unsigned high = x << n;return high | low;
}
在x86_64
机器上的运行结果:
// printf("%p\n", rotate_left(0x12345678, 0));
// printf("%p\n", rotate_left(0x12345678, 4));
// printf("%p\n", rotate_left(0x12345678, 8));
// printf("%p\n", rotate_left(0x12345678, 12));
// printf("%p\n", rotate_left(0x12345678, 16));
// printf("%p\n", rotate_left(0x12345678, 20));
// printf("%p\n", rotate_left(0x12345678, 24));
// printf("%p\n", rotate_left(0x12345678, 28));
// printf("%p\n", rotate_left(0x12345678, 31));
[liheng@localhost2 2]$ ./a.out
0x12345678
0x23456781
0x34567812
0x45678123
0x56781234
0x67812345
0x78123456
0x81234567
0x91a2b3c
2.70**
问:实现一个函数,如果x
能被表示成n
位(1≤n≤w)(1 \le n \le w)(1≤n≤w)的二进制补码,就返回1
,否则返回0
。
答:
int fits_bits(int x, int n)
{int w = sizeof(int) << 3;int offset = w - n;return ((x << offset) >> offset) == x; // 如果x不能用n个比特位表示,移位操作会使它丢失最高的有效位
}
在x86_64
机器上的运行结果:
// printf("%d\n", fits_bits(-4, 3));
// printf("%d\n", fits_bits(3, 3));
// printf("%d\n", fits_bits(-5, 3));
// printf("%d\n", fits_bits(4, 3));
[liheng@localhost2 2]$ ./a.out
1
1
0
0
2.71*
问:packed_t
类型是将4
个有符号字节封装成一个32
位的unsigned
,字节从0
(最低有效字节)编码到3
最高有效字节。有如下一个函数xbyte
,提取出特定的字节,再把它符号扩展成一个int
。
typedef unsigned packed_t;
int xbyte(packed_t word, int byteNum)
{return (word >> (byteNum << 3)) & 0xFF;
}
答:
- 写上述代码的人被解雇了,这段代码错在哪里?
编译器会把(word >> (byteNum << 3)) & 0xFF
的结果当作无符号数,扩展时使用零扩展而非符号扩展。
// printf("%d\n", xbyte(-1, 3));
[liheng@localhost2 2]$ ./a.out
255
- 给出函数的正确实现。
typedef unsigned packed_t;
int xbyte(packed_t word, int byteNum)
{return (int8_t)((word >> (byteNum << 3)) & 0xFF); // 把结果转成有符号数
}
在x86_64
机器上的运行结果:
// printf("%d\n", xbyte(-1, 3));
[liheng@localhost2 2]$ ./a.out
-1
2.72**
问:下面的函数将整数val
复制到缓冲区buf
中。
void copy_int(int val, void *buf, int maxbytes)
{if (maxbytes - sizeof(val) >= 0) {memcpy(buf, &val, sizeof(val));}
}
答:
sizeof
的返回值类型是size_t
,这段代码存在什么问题?
size_t
是无符号类型unsigned
的别名,maxbytes
是有符号数,无符号数和有符号数运算时,结果是无符号数(永远≥0\ge0≥0),因此if
分支的判断语句永远为true
。memcpy
会造成缓冲区的写溢出。- 改正代码。
void copy_int(int val, void *buf, int maxbytes)
{if (maxbytes >= sizeof(val) { // 无符号数之间的比较memcpy(buf, &val, sizeof(val));}
}
2.73**
问:实现饱和加法:正溢出时返回TMax
,负溢出时返回TMin
。
答:
int saturating_add(int x, int y)
{int s = x + y;int mask = 1 << ((sizeof(int) << 3) - 1);int neg_overflow = (x & mask) && (y & mask) && !(s & mask);int pos_overflow = !(x & mask) && !(y & mask) && (s & mask);(neg_overflow && (s = INT_MIN)) || (pos_overflow && (s = INT_MAX));return s;
}
在x86_64
机器上的运行结果:
// printf("%d\n", saturating_add(123, 456));
// printf("%d\n", saturating_add(-123, -456));
// printf("%d\n", saturating_add(INT_MAX, 123));
// printf("%d\n", saturating_add(INT_MIN, -123));
[liheng@localhost2 2]$ ./a.out
579
-579
2147483647
-2147483648
2.74**
问:实现一个函数,两数相减不溢出就返回1
,否则返回0
。
答:
int tsub_ok(int x, int y)
{int s = x - y;return !((x > 0 && y < 0 && s < 0) || (x < 0 && y > 0 && s > 0));
}
在x86_64
机器上的运行结果:
// printf("%d\n", tsub_ok(-1, 3));
// printf("%d\n", tsub_ok(INT_MIN, 1));
// printf("%d\n", tsub_ok(INT_MAX, -1));
[liheng@localhost2 2]$ ./a.out
1
0
0
正常情况:正数+正数=正数;溢出情况:正数+正数=负数。
正常情况:负数+负数=负数;溢出情况:负数+负数=正数。
正常情况:正数-负数=正数;溢出情况:正数-负数=负数。
正常情况:负数-正数=负数;溢出情况:负数-正数=正数。
2.75***
问:假设我们要计算x * y
的完整的2w
位表示,其中x
和y
都是无符号数,并且w=32
,乘积的低w
位能够用表达式x * y
计算。所以我们只需要额外计算它的高w
位,声明如下:
unsigned unsigned_high_prod(unsigned x, unsigned y);
我们使用一个库函数,它计算在x
和y
采用补码形式的情况下,x * y
的高w
位。声明如下:
int signed_high_prod(int x, int y);
编写代码调用signed_high_prod
,实现unsigned_high_prod
。
答:
假设x
和y
是无符号数,x′x'x′和y′y'y′分别是它们的补码数。有x=x′+xw−12wx=x'+x_{w-1}2^wx=x′+xw−12w、y=y′+yw−12wy=y'+y_{w-1}2^wy=y′+yw−12w,因此
x∗y=(x′+xw−12w)∗(y′+yw−12w)=x′∗y′+(x′yw−1+y′xw−1)2w+xw−1yw−122wx*y=(x'+x_{w-1}2^w)*(y'+y_{w-1}2^w)=x'*y'+(x'y_{w-1}+y'x_{w-1})2^w+x_{w-1}y_{w-1}2^{2w}x∗y=(x′+xw−12w)∗(y′+yw−12w)=x′∗y′+(x′yw−1+y′xw−1)2w+xw−1yw−122w
取低2w
位,结果是x′∗y′+(x′yw−1+y′xw−1)2wx'*y'+(x'y_{w-1}+y'x_{w-1})2^wx′∗y′+(x′yw−1+y′xw−1)2w,获取其中的高w
位的实现如下:
unsigned unsigned_high_prod(unsigned x, unsigned y)
{int a = signed_high_prod(x, y);return a + x * (y >> 31) + y * (x >> 31);
}
2.76*
问:
库函数calloc
声明如下:
void *calloc(size_t nmemb, size_t size);
函数calloc
为一个数组分配内存,并将内存设置为0
。该数组有nmemb
个元素,每个元素的大小为size
字节。如果nmemb
或size
为0
,calloc
返回NULL
。
编写calloc
的实现,通过malloc
分配内存,再通过memset
将内存设置为0
。你的代码应该没有任何由算术溢出引起的漏洞,且无论size_t
用多少位表示,代码都应该正常工作。malloc
和memset
的声明如下:
void *malloc(size_t size);
void *memset(void *s, inc c, size_t n);
答:
calloc
的实现如下:
void *calloc(size_t nmemb, size_t size)
{size_t bytes = nmemb * size;if ((bytes == 0) || (bytes / nmemb != size)) { // 分配0字节或溢出return NULL;}void *addr = malloc(bytes);if (addr == NULL) {return NULL;}return memset(addr, 0x00, bytes);
}
相关文章:
【CSAPP】家庭作业2.55~2.76
文章目录2.55*2.56*2.57*2.58**2.59**2.60**位级整数编码规则2.61**2.62***2.63***2.64*2.65****2.66***2.67**2.68**2.69***2.70**2.71*2.72**2.73**2.74**2.75***2.76*2.55* 问:在你能访问的不同的机器上,编译show_bytes.c并运行代码,确定…...
Python操作MySQL数据库详细案例
Python操作MySQL数据库详细案例一、前言二、数据准备三、建立数据库四、处理和上传数据五、下载数据六、完整项目数据和代码一、前言 本文通过案例讲解如何使用Python操作MySQL数据库。具体任务为:假设你已经了解MySQL和知识图谱标注工具Brat,将Brat标注…...
MicroBlaze系列教程(8):AXI_CAN的使用
文章目录 @[toc]CAN总线概述AXI_CAN简介MicroBlaze硬件配置常用函数使用示例波形实测参考资料工程下载本文是Xilinx MicroBlaze系列教程的第8篇文章。 CAN总线概述 **CAN(Controller Area Network)**是 ISO 国际标准化的串行通信协议,是由德国博世(BOSCH)公司在20世纪80年代…...
网络安全领域中八大类CISP证书
CISP注册信息安全专业人员 注册信息安全专业人员(Certified Information Security Professional),是经中国信息安全产品测评认证中心实施的国家认证,对信息安全人员执业资质的认可。该证书是面向信息安全企业、信息安全咨询服务…...
stm32学习笔记-5EXIT外部中断
5 EXIT外部中断 [toc] 注:笔记主要参考B站 江科大自化协 教学视频“STM32入门教程-2023持续更新中”。 注:工程及代码文件放在了本人的Github仓库。 5.1 STM32中断系统 图5-1 中断及中断嵌套示意图 中断 是指在主程序运行过程中,出现了特定…...
MySQL Workbench 图形化界面工具
Workbench 介绍 MySQL官方提供了一款免费的图形工具——MySQL Workbench,它是一款功能强大且易于使用的数据库设计、管理和开发工具,总之,MySQL Workbench是一款非常好用的MySQL图形工具,可以满足大多数MySQL用户的需求。 目录 W…...
雪花算法(SnowFlake)
简介现在的服务基本是分布式、微服务形式的,而且大数据量也导致分库分表的产生,对于水平分表就需要保证表中 id 的全局唯一性。对于 MySQL 而言,一个表中的主键 id 一般使用自增的方式,但是如果进行水平分表之后,多个表…...
Linux防火墙
一、Linux防火墙Linux的防火墙体系主要在网络层,针对TCP/IP数据包实施过滤和限制,属于典型的包过滤防火墙(或称为网络层防火墙)。Linux系统的防火墙体系基于内核编码实现,具有非常稳定的性能和极高的效率,因…...
网络安全系列-四十七: IP协议号大全
IP协议号列表 这是用在IPv4头部和IPv6头部的下一首部域的IP协议号列表。 十进制十六进制关键字协议引用00x00HOPOPTIPv6逐跳选项RFC 246010x01ICMP互联网控制消息协议(ICMP)RFC 79220x02IGMP...
HTTP协议格式以及Fiddler用法
目录 今日良言:焦虑和恐惧改变不了明天,唯一能做的就是把握今天 一、HTTP协议的基本格式 二、Fiddler的用法 1.Fidder的下载 2.Fidder的使用 今日良言:焦虑和恐惧改变不了明天,唯一能做的就是把握今天 一、HTTP协议的基本格式 先来介绍一下http协议: http 协议(全称为 &q…...
自动写代码?别闹了!
大家好,我是良许。 这几天,GitHub 上有个很火的插件在抖音刷屏了——Copilot。 这个神器有啥用呢?简单来讲,它就是一款由人工智能打造的编程辅助工具。 我们来看看它有啥用。 首先就是代码补全功能,你只要给出函数…...
项目心得--网约车
一、RESTFULPost:新增Put:全量修改Patch:修改某个值Delete: 删除Get:查询删除接口也可以用POST请求url注意:url中不要带有敏感词(用户id等)url中的名词用复数形式url设计:api.xxx.co…...
【二叉树广度优先遍历和深度优先遍历】
文章目录一、二叉树的深度优先遍历0.建立一棵树1. 前序遍历2.中序遍历3. 后序遍历二、二叉树的广度优先遍历层序遍历三、有关二叉树练习一、二叉树的深度优先遍历 学习二叉树结构,最简单的方式就是遍历。 所谓二叉树遍历(Traversal)是按照某种特定的规则ÿ…...
Spring Cloud微服务架构必备技术
单体架构 单体架构,也叫单体应用架构,是一个传统的软件架构模式。单体架构是指将应用程序的所有组件部署到一个单一的应用程序中,并统一进行部署、维护和扩展。在单体架构中,应用程序的所有功能都在同一个进程中运行,…...
TCP三次握手与四次挥手(一次明白)
TCP基本信息 默认端口号:80 LINUX中TIME_WAIT的默认时间是30s TCP三次握手 三次握手过程:每行代表发起握手到另一方刚刚收到数据包时的状态 客户端服务端客户端状态服务端状态握手前CLOSELISTEN客户端发送带有SYN标志的数据包到服务端一次握手SYN_SENDLISTEN二次握手服务端发送…...
pyside6@Mouse events实例@QApplication重叠导致的报错@keyboardInterrupt
文章目录报错内容鼠标事件演示报错内容 在pyside图形界面应用程序开发过程中,通常只允许运行一个实例 假设您重复执行程序A,那么可能会导致一些意向不到的错误并且,从python反馈的信息不容易判断错误的真正来源 鼠标事件演示 下面是一段演示pyside6的鼠标事件mouseEvent对象…...
订单30分钟未支付自动取消怎么实现?
目录了解需求方案 1:数据库轮询方案 2:JDK 的延迟队列方案 3:时间轮算法方案 4:redis 缓存方案 5:使用消息队列了解需求在开发中,往往会遇到一些关于延时任务的需求。例如生成订单 30 分钟未支付࿰…...
< 开源项目框架:推荐几个开箱即用的开源管理系统 - 让开发不再复杂 >
文章目录👉 SCUI Admin 中后台前端解决方案👉 Vue .NetCore 前后端分离的快速发开框架👉 next-admin 适配移动端、pc的后台模板👉 django-vue-admin-pro 快速开发平台👉 Admin.NET 通用管理平台👉 RuoYi 若…...
内网渗透-基础环境
解决依赖,scope安装 打开要给cmd powershell 打开远程 Set-ExecutionPolicy RemoteSigned -scope CurrentUser; 我试了好多装这东西还是得科学上网,不然不好用 iwr -useb get.scoop.sh | iex 查看下载过的软件 安装sudo 安装git 这里一定要配置bu…...
Go语言学习的第一天(对于Go学习的认识和工具选择及环境搭建)
首先学习一门新的语言,我们要知道这门语言可以帮助我们做些什么?为什么我们要学习这门语言?就小wei而言学习这门语言是为了区块链,因为自身是php出身,因为php的一些特性只能通过一些算法模拟的做一个虚拟链,…...
C和C++到底有什么关系
C++ 读作”C加加“,是”C Plus Plus“的简称。顾名思义,C++是在C的基础上增加新特性,玩出了新花样,所以叫”C Plus Plus“,就像 iPhone 6S 和 iPhone 6、Win10 和 Win7 的关系。 C语言是1972年由美国贝尔实验室研制成功的,在当时算是高级语言,它的很多新特性都让汇编程序…...
14个Python处理Excel的常用操作,非常好用
自从学了Python后就逼迫用Python来处理Excel,所有操作用Python实现。目的是巩固Python,与增强数据处理能力。 这也是我写这篇文章的初衷。废话不说了,直接进入正题。 数据是网上找到的销售数据,长这样: 一、关联公式:…...
async/await 用法
1. 什么是 async/await async/await 是 ES8(ECMAScript 2017)引入的新语法,用来简化 Promise 异步操作。在 async/await 出 现之前,开发者只能通过链式 .then() 的方式处理 Promise 异步操作。示例代码如下: import …...
好意外,发现永久免费使用的云服务器
原因就不说了,说一下过程,在百度搜pythonIDE的时候,发现了一个网站 https://lightly.teamcode.com/https://lightly.teamcode.com/ 就是这个网站,看见这个免费试用,一开始觉得没什么,在尝试使用的过程中发…...
VSCode使用技巧,代码编写效率提升2倍以上!
VSCode是一款开源免费的跨平台文本编辑器,它的可扩展性和丰富的功能使得它成为了许多程序员的首选编辑器。在本文中,我将分享一些VSCode的使用技巧,帮助您更高效地使用它。 1. 插件 VSCode具有非常丰富的插件生态系统,通过安装插…...
SQL执行过程详解
1 、用户在客户端执行 SQL 语句时,客户端把这条 SQL 语句发送给服务端,服务端的进程,会处理这条客户端的SQL语句。 2 、服务端进程收集到SQL信息后,会在进程全局区PGA 中分配所需内存,存储相关的登录信息等。 3 、客…...
【物联网NodeJs-5天学习】第四天存储篇⑤ ——PM2,node.js应用进程管理器
【NodeJs-5天学习】第四天存储篇⑤ ——PM2,node.js应用进程管理器1. 前言2. 官方说明3. 安装PM24. PM2常用命令4.1 启动命令4.2 重新启动命令4.3 热重载命令4.4 停止命令4.5 删除命令4.6 查看进程运行状态4.4 显示某一个进程的具体信息4.8 显示日志信息4.9 终端监控…...
【C++学习】【STL】deque容器
dequeDouble Ended Queues(双向队列)deque和vector很相似,但是它允许在容器头部快速插入和删除(就像在尾部一样)。所耗费的时间复杂度也为常数阶O(1)。并且更重要的一点是,deque 容器中存储元素并不能保证所有元素都存储到连续的内…...
当 App 有了系统权限,真的可以为所欲为?
看到群里发了两篇文章,出于好奇,想看看这些个 App 在利用系统漏洞获取系统权限之后,都干了什么事,于是就有了这篇文章。由于准备仓促,有些 Code 没有仔细看,感兴趣的同学可以自己去研究研究,多多…...
vue3.js的介绍
一.vue.js简述 Vue是一套用于构建用户开源的MVVM结构的Javascript渐进式框架,尤雨溪在2015年10月27日发布了vue.js 1.0Eavangelion版本,在2016年9月30日发布了2.0Ghost in the Shell版本,目前项目由官方负责 vue的核心只关注图层࿰…...
网站的英文版怎么做的/网站设计开发网站
KingbaseES数据库结构[kingbasepostgresV8]$ tree -LP2data/ . ├── data │ ├── base # 存储用户创建的数据库文件及隶属于用户数据库的所有关系.比如表、索引... │ ├── current_logfiles. # 记录当前被日志收集器写入的日志文件的文件…...
宁德网站推广/全渠道营销成功案例
(1)RAID技术规范简介 冗余磁盘阵列技术最初的研制目的是为了组合小的廉价磁盘来代替大的昂贵磁盘,以降低大批量数据存储的费用,同时也希望采用冗余信息的方式,使得磁盘失效时不会使对数据的访问受损失,从而…...
国外网站建设费用/100个商业经典案例
【ORACLE】redo和undo_改变向量redo和undo1.1 oracle 9i任务执行过程--DML更新数据操作:1.创建一个改变向量(保存改变之前的数据)描述undo数据块的改变;2.创建改变向量(保存改变之后的数据),描述数据块的改变;3.合并两个改变向量为…...
泸州做网站公司/手机建网站软件
隐写3 打开是一张图片 winhex打开没发现异常 winhex改一下长高后发现碰巧出了flag zip伪加密 简单题 winhex打开后将图片的09改为00即可解伪加密 赛博朋克 打开是一个txt打开发现有PNG前缀 于是改后缀为png 发现一张图片 winhex查看后发现有Steganography字样 就猜测为LS…...
手机网页制作与网站建设/广州百度竞价开户
编译阶段:将java文件编译为class字节码文件 类加载 类加载:将class字节码加载进内存 1、加载(Loading) 将class类模型相关信息加载到方法区当中。 类加载器 BootStrapClassLoader 引导/启动类加载器 核心类库ExtensionClassLoader 扩展类加载器 特…...
app音乐网站开发/长尾关键词挖掘爱站网
2019独角兽企业重金招聘Python工程师标准>>> 简单记录一下。关于Oracle exp导出操作注意的地方。 1、客户端安装,环境变量配置:path or NLS_LANG 2、导出过程中存在问题 a、导出语句:exp useridusername/passwordip/dbname ind…...