第一章 Python基础

Python基础、函数、模块、面向对象、网络和并发编程、数据库和缓存、 前端、django、Flask、tornado、api、git、爬虫、算法和数据结构、Linux、设计题、客观题、其他

第一章 Python基础

4 Python和Java、PHP、C、C#、C++等其他语言的对比?

Python、Java、PHP、C、C#、C++ 等编程语言各有其优势和适用场景。
1. **Python:**
   - **优势:** 简洁易读,适合快速开发和原型设计。拥有强大的生态系统和第三方库。
   - **适用场景:** Web 开发、数据科学、人工智能、自动化脚本等。

2. **Java:**
   - **优势:** 跨平台性强,具有良好的性能和稳定性。适合大型企业应用和分布式系统。
   - **适用场景:** 企业级应用、Web 后端、大数据处理等。

3. **PHP:**
   - **优势:** 专注于Web开发,易于学习。被广泛用于服务器端脚本。
   - **适用场景:** Web 开发、动态网站。

4. **C:**
   - **优势:** 面向过程的语言,性能高。适合系统编程和嵌入式开发。
   - **适用场景:** 操作系统、嵌入式系统、系统级编程。

5. **C#:**
   - **优势:** 面向对象的语言,与.NET框架紧密结合,易于开发 Windows 应用。
   - **适用场景:** Windows 应用、桌面应用、游戏开发(使用Unity)。

6. **C++**
   - **优势:** 面向对象,性能高,支持多范式编程。适用于系统级编程和性能关键型应用。
   - **适用场景:** 操作系统、游戏引擎、嵌入式系统、高性能应用。

5 简述解释型和编译型编程语言?

解释型和编译型编程语言是两种不同的代码执行方式:

1. **解释型语言:**
   - **定义:** 解释型语言的代码在运行时逐行被解释器翻译成机器码,然后执行。
   - **特点:** 不需要显式的编译步骤,直接运行源代码。
   			   每次运行程序都要进行解释,因此运行速度相对较慢。
   - **例子:** Python、JavaScript、Ruby。

2. **编译型语言:**
   - **定义:** 编译型语言的代码在运行之前需要通过编译器转换为机器码或者中间代码,然后由计算机执行。
   - **特点:** 编译过程产生的目标代码可以多次执行,因此执行速度较快。但在运行之前需要明确的编译步骤。
   - **例子:** C、C++、Java(在Java中,虽然代码是编译的,
   	           但是Java在虚拟机上执行,先编译成中间代码,然后由虚拟机解释执行)。

**对比:**
- 解释型语言的优势在于跨平台性和灵活性,可以在不同的环境中直接运行源代码。
- 编译型语言的优势在于执行效率高,因为代码在运行前已经被编译成机器码。

很多语言在执行时采用了混合的方式,例如,Java是先编译成字节码,然后在虚拟机中解释执行。
这样既保留了跨平台性,又提高了执行效率。

6 Python解释器种类以及特点?

Python 解释器有多种种类,其中两个主要的是 CPython 和 Jython。
以下是一些主要的 Python 解释器及其特点:

1. **CPython:**
   - **特点:** CPython 是 Python 的官方解释器,大多数用 Python 编写的软件都是在 
   			   CPython 上运行的。它是一个基于 C 语言开发的解释器。
   - **优点:** 最广泛使用,社区庞大,生态系统完备。
   - **缺点:** 在某些性能方面可能不如一些经过专门优化的解释器。

2. **Jython:**
   - **特点:** Jython 是一个在Java平台上运行的Python解释器,它将Python代码编译成Java字节码。
   - **优点:** 可以与 Java 代码无缝集成,可以使用 Java 的类库和工具。
   - **缺点:** 不如 CPython 流行,有时可能无法完全支持某些 Python 特性。

3. **IronPython:**
   - **特点:** IronPython 是一个在 .NET 平台上运行的Python解释器,它与CPython在很多方面类似,但是它是用 C# 实现的。
   - **优点:**.NET 平台深度集成,可以直接使用 .NET 的类库。
   - **缺点:** 对于一些 CPython 特有的库和工具支持不完全。

4. **PyPy:**
   - **特点:** PyPy是一个用Python 编写的、支持即时编译的解释器。与CPython相比,PyPy在性能上有很大的提升。
   - **优点:** 良好的性能,支持 Just-In-Time(JIT)编译。
   - **缺点:** 可能在某些特殊库的兼容性上有一些问题。

5. **MicroPython:**
   - **特点:** MicroPython 是一个专为嵌入式系统设计的 Python 解释器,可以在资源受限的环境中运行。
   - **优点:** 非常轻量级,适用于嵌入式设备。
   - **缺点:** 不支持所有的 Python 特性。

每个解释器都有其自己的优势和适用场景,选择取决于具体的应用需求和平台。

7 位和字节的关系?

位(bit)和字节(byte)是计量计算机存储容量的基本单位。

- **位(bit):** 是计算机内存中最小的数据单位,只能表示 01。
	计算机中的数据以二进制形式表示,每一位就是一个二进制位。

- **字节(byte):** 是计算机中基本的存储单元,由 8 个位组成。
	一个字节可以表示256种不同的状态,因为每个位可以是01,所以总共有 \(2^8 = 256\) 种可能。

关系:

- 1 字节 = 8- 1 千字节(KB)= \(2^{10}\) 字节 = 1024 字节
- 1 兆字节(MB)= \(2^{20}\) 字节 = 1024 KB
- 1 吉字节(GB)= \(2^{30}\) 字节 = 1024 MB
- 1 太字节(TB)= \(2^{40}\) 字节 = 1024 GB

以此类推。在计算机存储和传输中,常用的单位有字节和其衍生单位,而位则通常用于表示数据的最小单元。

8 b、B、KB、MB、GB 的关系?

这是计算机存储容量单位的关系:

- **Bit(位):** 计算机中最小的数据单位,取值为 01- **Byte(字节):**8 个比特组成,是计算机中基本的存储单元。
- **KB(Kilobyte,千字节):** 等于 1024 字节。
- **MB(Megabyte,兆字节):** 等于 1024 KB,或者是 \(1024 \times 1024\) 字节。
- **GB(Gigabyte,吉字节):** 等于 1024 MB,或者是 \(1024 \times 1024 \times 1024\) 字节。
这些单位通常用于描述计算机的内存容量、硬盘容量以及数据传输速率等。

9 请列举你了解的PEP8 规范?

PEP 8 是 Python Enhancement Proposal 8 的缩写,是 Python 社区为了提高代码的可读性和
一致性而制定的一系列编码规范。以下是 PEP 8 的一些主要规范:

1. **缩进:** 使用 4 个空格进行缩进,而不是制表符。
    # Good
    def function(arg):
        if arg:
            print(arg)
    # Bad
    def function(arg):
        if arg:
        	print(arg)

2. **最大行长度:** 每行不超过 79 个字符,对于注释和文档字符串不超过 72 个字符。
    # Good
    def my_function(parameter):
        if parameter > 0 and parameter < 100:
            print(parameter)
    # Bad
    def my_function(parameter):
        if parameter > 0 and parameter < 100: print(parameter)

3. **空行:** 使用空行来组织代码,顶层函数和类之间用两个空行隔开,类中的方法之间用一个空行隔开。
    # Good
    class MyClass:

        def method1(self):
            pass

        def method2(self):
            pass


    # Bad
    class MyClass:
        def method1(self):
            pass
        def method2(self):
            pass

4. **导入:** 导入应该分成三个部分:标准库导入、相关第三方导入、本地应用程序/库导入。
	每个部分之间用一个空行隔开。
    # Good
    import os
    import sys

    from math import sqrt
    from urllib import request

    from my_local_module import my_function

5. **命名规范:** 模块名应该使用小写字母,函数和变量名应该使用小写字母和下划线的组合,
	类名应该使用驼峰式命名法。
    # Good
    def my_function():
        pass

    class MyClass:
        pass

    # Bad
    def MyFunction():
        pass

    class my_class:
        pass

6. **注释:** 使用文档字符串描述模块、类和函数,单行注释使用 `#`,多行注释使用三引号。
    # Good
    def add(x, y):
        """
        This function adds two numbers.
        """
        return x + y

    # Bad
    def add(x, y):
        # Function to add two numbers
        return x + y

这些规范有助于编写一致、易读、易维护的 Python 代码。

10 求结果:or and

v1 = 1 or 3: 返回第一个为真的值,所以v1的值是 1。
v2 = 1 and 3: 返回最后一个为真的值,所以v2的值是 3。
v3 = 0 and 2 and 1: 返回第一个为假的值,所以v3的值是 0。
v4 = 0 and 2 or 1: 先计算 0 and 2得到0,然后0 or 1得到1,所以v4的值是1。
v5 = 0 and 2 or 1 or 4: 先计算0 and 2得到0,然后0 or 1 or 4得到1,所以v5的值是1。
v6 = 0 or False and 1: 先计算 0 or False得到False,然后False and 1得到False,所以v6的值是 False

11 ascii、unicode、utf-8、gbk 区别?

这是一些字符编码的概念:
1. **ASCII(American Standard Code for Information Interchange):**
   - ASCII 是一个使用7位或8位二进制数字表示128个字符(包括控制字符、数字、字母和常见符号)的字符编码标准。
   - 由于只使用7位,ASCII 只能表示128种字符,无法涵盖所有语言字符。

2. **Unicode:**
   - Unicode 是一个标准,旨在为世界上的每个字符设定一个唯一的数字码点,以便在计算机中进行存储和处理。
   - Unicode 的编码空间较大,能够容纳全球范围内的字符,包括各种语言的字母、符号和表意文字。

3. **UTF-8(Unicode Transformation Format-8):**
   - UTF-8 是一种针对 Unicode 的可变长度字符编码,它使用14个字节表示不同的字符。
   - UTF-8 是目前 Web 上最常见的 Unicode 实现方式之一。

4. **GBK(Guojia Biaozhun Kuozhan):**
   - GBK 是中华人民共和国国家标准,是对 GB 2312 进行了扩展,支持更多的汉字。
   - GBK 编码使用12个字节表示一个字符。

**总结:**
- ASCII 是较早的字符编码,只能表示有限的字符。
- Unicode 是一个更广泛的字符集,包括世界上几乎所有的字符。
- UTF-8 是 Unicode 的一种实现方式,广泛用于 Web。
- GBK 是中文编码标准,用于支持汉字。

12 字节码和机器码的区别?

**字节码(Bytecode):**
- 字节码是一种中间代码,介于源代码和机器代码之间。
- 字节码通常由一种虚拟机执行,而不是由硬件直接执行。
- Python、Java 等语言采用字节码的执行方式。

**机器码(Machine Code):**
- 机器码是一种由计算机硬件直接执行的二进制代码。
- 机器码是特定于计算机体系结构的,不同的 CPU 有不同的机器码。
- 机器码是硬件能够直接理解和执行的最低级别的代码。

**区别:**
1. **执行方式:**
   - 字节码需要通过虚拟机来执行。
   - 机器码可以由计算机的硬件直接执行。

2. **可移植性:**
   - 字节码是相对可移植的,因为它们是在虚拟机上执行的,只要有相应的虚拟机,就可以在不同的平台上运行。
   - 机器码是与具体硬件平台相关的,不同的平台上的机器码是不同的。

3. **编译方式:**
   - 字节码通常是在源代码经过解释器编译成的,在运行时由虚拟机解释执行。
   - 机器码是通过编译器将源代码直接转换成硬件可以执行的二进制代码。

4. **人类可读性:**
   - 字节码通常比机器码更容易阅读和理解,因为它们通常是高级语言的中间表示。
   - 机器码是二进制的,对人类来说难以直接理解。

在 Python 中,源代码首先被编译成字节码,然后由 Python 解释器执行。
这使得 Python 具有一定的可移植性,并且可以在不同的平台上运行,只要有相应的 Python 解释器。

13 三元运算编写格式

三元运算符的基本格式为:
x if 布尔表达式 else y,如果为 `True`,返回 `x`,否则返回 `y`。

14 列举你了解的所有Python2和Python3的区别?

Python 2 和 Python 3 之间存在许多区别,以下是其中一些主要的差异:

1. **print 语句 vs print 函数:**
   - Python 2 使用 `print` 语句,如 `print "Hello"`
   - Python 3 使用 `print()` 函数,如 `print("Hello")`

2. **整数除法:**
   - Python 2 中整数除法返回整数,如 `5 / 2` 返回 `2`
   - Python 3 中整数除法返回浮点数,如 `5 / 2` 返回 `2.5`,使用 `//` 执行整数除法

3. **字符串表示:**
   - Python 2 默认使用 ASCII 编码,Unicode 字符串需要在字符串前加 `u`,如 `u"Hello"`
   - Python 3 默认使用 Unicode 编码,字符串是 Unicode 字符串,而字节字符串需要在字符串前加 `b`,如 `b"Hello"`

4. **xrange 函数:**
   - Python 2 中有 `xrange()` 用于生成一个 xrange 对象,适用于大范围的迭代
   - Python 3 中 `xrange()` 被弃用,`range()` 返回类似 Python 2 中 `xrange` 的惰性序列

5. **input 函数:**
   - Python 2 中 `input()` 接收用户输入的内容作为字符串,`raw_input()` 接收用户输入作为字符串
   - Python 3 中 `input()` 接收用户输入作为字符串,`raw_input()` 被移除

6. **异常语法:**
   - Python 2 使用 `,` 将异常类型和异常实例分开,如 `except ValueError, e:`
   - Python 3 使用 `as`,如 `except ValueError as e:`

7. **range 函数:**
   - Python 2 中 `range()` 返回列表,`xrange()` 返回迭代器
   - Python 3 中 `range()` 返回迭代器,`list(range())` 返回列表

8. **字典迭代:**
   - Python 2 中使用 `dict.iteritems()` 迭代字典的键值对
   - Python 3 中 `dict.items()` 返回一个视图,`dict.items()` 返回一个列表

9. **Unicode 支持:**
   - Python 2 中 Unicode 字符串和普通字符串区分,需要 `u` 前缀表示 Unicode 字符串
   - Python 3 中默认所有字符串都是 Unicode 字符串

10. **其他:**
    - Python 3 引入了新的语法和特性,如 `async/await` 异步编程模型,类型提示等。

需要注意的是,Python 2 已于 2020 年停止维护,因此建议使用 Python 3 进行新的项目。

15 用一行代码实现数值交换:

   a = 1
   b = 2

结果如下:
	a, b = b, a

18 Python3和Python2中 int 和 long的区别?

在Python 3 中,整型(`int`)可以存储任意大的整数,而不再有独立的 `long` 类型。
这是因为 Python 3 引入了一种称为 "无限精度整数" 的机制,即整数可以根据需要自动扩展。
这种机制消除了在 Python 2 中由于整数溢出而导致需要使用 `long` 类型的情况。

在 Python 2 中,`int` 类型是有范围的,而 `long` 类型则可以存储更大的整数。
当整数超过 `sys.maxint`(根据平台的不同,通常是 2^31-12^63-1)时,自动转为 `long` 类型。

因此,Python 3 中的整数类型(`int`)没有范围限制,可以表示任意大的整数,
而 Python 2 中的整数类型有范围限制,需要使用 `long` 类型来表示大整数。

19 xrange和range的区别?

在 Python 2 中,`range()` 函数返回的是一个列表,它会一次性生成所有的元素,这可能导致在处理
大范围的数据时占用大量内存。为了解决这个问题,Python 2 中引入了 `xrange()` 函数。

1. **`range()`:** 返回一个列表,包含指定范围内的所有整数。
	如果需要遍历这个范围,会一次性生成并存储整个列表。
    numbers = range(5)
    print(numbers)  # Output: [0, 1, 2, 3, 4]


2. **`xrange()`:** 返回的是一个 xrange 对象,它在遍历时生成下一个值,
而不会一次性生成所有的值,因此在处理大范围数据时更加节省内存。
    numbers = xrange(5)
    print(numbers)  # Output: xrange(5)


在 Python 3 中,range()的行为更像 Python 2 中的xrange(),即返回一个可迭代对象而不是列表。
因此,Python 3 中不再有 xrange()。如果需要列表,可以使用 list(range())来获得类似的效果。

20 如何实现字符串的反转?如: name = “lingege” 请反转为 name = “egegnil”

在 Python 中,可以使用切片(slice)来实现字符串的反转。具体做法是使用 `[::-1]` 切片表示法,
它表示从字符串的最后一个字符开始,以逆序的方式遍历整个字符串。

以下是实现字符串反转的示例:
name = "linjun"
reversed_name = name[::-1]
print(reversed_name)

上述代码会输出:egegnil
这里 `[::-1]` 切片表示法是 Python 中用于逆序的一种常见写法。

21 文件操作时:xreadlines和readlines的区别?

在 Python 中,`readlines()` 和 `xreadlines()` 都是用于读取文件内容的方法,
但它们存在一些区别:

1. **`readlines()` 方法:**
   - **Python 2 和 Python 3 中都存在。**
   - 返回一个包含文件所有行的列表,每一行都是列表的一个元素。
   - 一次性将整个文件加载到内存中,可能对大文件不够友好,因为会占用较多内存。
   with open('a.txt', 'r') as file:
       lines = file.readlines()
       
2. **`xreadlines()` 方法:**
   - **仅在 Python 2 中存在,Python 3 中已经废弃。**
   - 返回一个迭代器(iterator),每次迭代获取文件的一行,而不是一次性加载整个文件。
   - 更适合处理大文件,因为它不会一次性加载整个文件到内存中。
   with open('a.txt', 'r') as file:
       for line in file.xreadlines():
           # 处理每一行


总体而言,如果在 Python 3 中进行文件读取操作,建议使用 `readlines()` 方法。
如果需要逐行处理大文件,可以使用 `for line in file`,因为在 Python 3 中,
文件对象默认就是一个迭代器,而无需使用 `xreadlines()`。

22 列举布尔值为False的常见值?

1. **False** 布尔值 False 本身就是 False。
    x = False

2. **None** 表示空值或不存在的对象。
    x = None

3. **数值中的零:** 整数、浮点数中的零都被视为 False。
    x = 0
    y = 0.0

4. **空序列和空集合:** 空字符串、空列表、空元组和空字典都被视为 False。
    x = ""
    y = []
    z = ()
    w = {}

5. **自定义对象中的 `__bool__` 或 `__len__` 方法返回 0False** 
	如果在自定义对象中定义了 `__bool__` 或 `__len__` 方法,并且它们返回 0False,
	那么该对象在布尔上下文中将被视为 Falseclass MyClass:
        def __bool__(self):
            return False

    obj = MyClass()
这些值在布尔上下文中被视为 `False`,其他值被视为 `True`。

23 列举字符串、列表、元组、字典每个常用的5个方法?

*** 1 字符串(str):***
1. **`str.capitalize()`:** 返回字符串的副本,其中第一个字符大写。
    s = "hello"
    result = s.capitalize()
    print(result)  # 输出:Hello
    
2. **`str.upper()`:** 返回字符串的副本,所有字符都转换为大写。
    s = "hello"
    result = s.upper()
    print(result)  # 输出:HELLO

3. **`str.lower()`:** 返回字符串的副本,所有字符都转换为小写。
    s = "Hello"
    result = s.lower()
    print(result)  # 输出:hello

4. **`str.strip()`:** 返回字符串的副本,移除字符串两侧的空格和换行符。
    s = "  hello  "
    result = s.strip()
    print(result)  # 输出:hello

5. **`str.split()`:** 将字符串分割成列表,默认以空格为分隔符。
    s = "apple orange banana"
    result = s.split()
    print(result)  # 输出:['apple', 'orange', 'banana']


*** 2 列表(list):***
1. **`list.append()`:** 在列表末尾添加一个元素。
    my_list = [1, 2, 3]
    my_list.append(4)
    print(my_list)  # 输出:[1, 2, 3, 4]

2. **`list.extend()`:** 将一个可迭代对象的元素添加到列表末尾。
    my_list = [1, 2, 3]
    other_list = [4, 5, 6]
    my_list.extend(other_list)
    print(my_list)  # 输出:[1, 2, 3, 4, 5, 6]

3. **`list.pop()`:** 移除并返回列表中的最后一个元素。
    my_list = [1, 2, 3, 4]
    last_element = my_list.pop()
    print(last_element)  # 输出:4

4. **`list.remove()`:** 移除列表中第一个匹配给定值的元素。
    my_list = [1, 2, 3, 2]
    my_list.remove(2)
    print(my_list)  # 输出:[1, 3, 2]

5. **`list.reverse()`:** 反转列表中的元素顺序。
    my_list = [1, 2, 3]
    my_list.reverse()
    print(my_list)  # 输出:[3, 2, 1]

*** 3 元组(tuple):***
1. **`tuple.count()`:** 返回指定值在元组中出现的次数。
    my_tuple = (1, 2, 2, 3, 4)
    count_of_2 = my_tuple.count(2)
    print(count_of_2)  # 输出:2

2. **`tuple.index()`:** 返回指定值在元组中第一次出现的索引。
    my_tuple = (1, 2, 3, 2, 4)
    index_of_2 = my_tuple.index(2)
    print(index_of_2)  # 输出:1

3. **`len(tuple)`:** 返回元组中元素的个数。
    my_tuple = (1, 2, 3, 4)
    length = len(my_tuple)
    print(length)  # 输出:4

4. **`max(tuple)`:** 返回元组中最大的元素。
    my_tuple = (1, 5, 3, 2)
    max_value = max(my_tuple)
    print(max_value)  # 输出:5

5. **`min(tuple)`:** 返回元组中最小的元素。
    my_tuple = (1, 5, 3, 2)
    min_value = min(my_tuple)
    print(min_value)  # 输出:1


*** 4 字典(dict):***
字典是Python中非常常用的数据结构,以下是字典常用的5个方法:
1. **`get(key, default=None)`:**
   - 获取指定键的值。如果键不存在,返回默认值(默认为 `None`)而不是引发 KeyError。
   my_dict = {'a': 1, 'b': 2, 'c': 3}
   value = my_dict.get('b', 0)
   print(value)  # 输出:2

2. **`keys()`:** 返回字典中所有键的视图。
   my_dict = {'a': 1, 'b': 2, 'c': 3}
   all_keys = my_dict.keys()
   print(all_keys)  # 输出:dict_keys(['a', 'b', 'c'])

3. **`values()`:** 返回字典中所有值的视图。
   my_dict = {'a': 1, 'b': 2, 'c': 3}
   all_values = my_dict.values()
   print(all_values)  # 输出:dict_values([1, 2, 3])

4. **`items()`:** 返回字典中所有键值对的视图。
   my_dict = {'a': 1, 'b': 2, 'c': 3}
   all_items = my_dict.items()
   print(all_items)  # 输出:dict_items([('a', 1), ('b', 2), ('c', 3)])

5. **`update(dictionary)`:** 使用另一个字典或键值对序列更新当前字典。
   my_dict = {'a': 1, 'b': 2}
   my_dict.update({'b': 3, 'c': 4})
   print(my_dict)  # 输出:{'a': 1, 'b': 3, 'c': 4}

24 is和==的区别?

在Python中,`is` 和 `==` 是两个不同的比较操作符,用于比较对象之间的相等性。
它们之间的区别主要体现在以下几个方面:

1. **比较的对象类型:**
   - `==` 用于比较对象的值是否相等。
   - `is` 用于比较对象的标识(identity),即检查两个对象是否指向同一块内存空间。

2. **比较的结果:**
   - `==` 返回 `True` 如果对象的值相等,否则返回 `False`。
   - `is` 返回 `True` 如果对象的标识相等,即它们是同一个对象,否则返回 `False`。

3. **适用范围:**
   - `==` 可以用于比较几乎所有类型的对象,不仅限于基本数据类型。
   - `is` 主要用于比较对象的标识,通常在比较单例对象(如 `None`)时使用较多。

4. **性能:**
   - `==` 操作符通常涉及到对象的值比较,因此可能会涉及更多的计算。
   - `is` 操作符仅涉及对象标识的比较,因此通常比 `==` 更快。

示例:
a = [1, 2, 3]
b = [1, 2, 3]

# == 比较值
print(a == b)  # 输出:True

# is 比较标识
print(a is b)  # 输出:False


在这个例子中,虽然 `a` 和 `b` 的值相等,但它们是两个不同的列表对象,因此 `a is b` 返回 `False`。

25 1、2、3、4、5 能组成多少个互不相同且无重复的三位数

百位:5种选择
十位:4种选择
个位:3种选择
故共有:5*4*3=60

26. 什么是反射?以及应用场景?

在编程中,**反射(Reflection)**是指在运行时检查、探知和修改程序状态或行为的能力。通常,
反射允许程序在运行时获取类型信息、方法和属性,以及在运行时创建、修改、删除类、对象、方法和属性。

在Python中,反射通常通过内置的`getattr`、`hasattr`、`setattr`等函数实现。

以下是反射的一些常见应用场景:
1. **动态导入模块和调用函数:** 
	通过字符串形式指定模块名和函数名,然后动态导入模块,并在运行时调用相关函数。
    module = __import__('module_name')
    func = getattr(module, 'function_name')
    func()

2. **配置文件处理:** 在运行时根据配置文件的内容动态创建对象、修改属性。
    config = {'class': 'MyClass', 'params': {'param1': 42, 'param2': 'value'}}
    
    # 根据配置动态创建对象
    obj = globals()[config['class']](**config['params'])

3. **Django中的ORM:** 
	Django中的ORM系统允许你通过模型类直接访问数据库,可以在运行时动态地创建、修改数据库中的表。
    class MyModel(models.Model):
        name= models.CharField(max_length=50)
        price= models.IntegerField()

    # 动态创建表
    MyModel.objects.create(name='value', price=42)

5. **插件系统:** 可以通过反射加载和执行插件,使程序具有可扩展性。
    plugin_name = 'my_plugin'
    plugin_module = __import__(f'plugins.{plugin_name}', fromlist=['*'])


总的来说,反射使得程序更加灵活,允许在运行时做出决策,适用于需要动态配置和扩展的场景。
然而,过度使用反射可能会导致代码难以理解和维护,因此需要谨慎使用。

27. 简述Python的深浅拷贝?

在 Python 中,深拷贝(deep copy)和浅拷贝(shallow copy)是关于对象拷贝的两个概念。
1. **浅拷贝(Shallow Copy)**- 浅拷贝创建一个新的对象,但是只复制原对象的最外层元素,而不会复制嵌套的对象。
   - 对于可变对象(例如列表、字典),新对象中的子对象(元素)是原对象中子对象的引用。
   	 修改子对象会影响原对象和新对象。
   - 可以使用 `copy` 模块的 `copy()` 函数来进行浅拷贝。
     import copy

     list1= [1, [2, 3], 4]
     cp_list = copy.copy(list1)

     list1[1][0] = 'X'
     print(list1)        # [1, ['X', 3], 4]
     print(cp_list )     # [1, ['X', 3], 4]

2. **深拷贝(Deep Copy)**- 深拷贝创建一个新的对象,并递归地复制原对象及其所有嵌套的对象。
   - 新对象和原对象是完全独立的,修改一个不会影响另一个。
   - 可以使用 `copy` 模块的 `deepcopy()` 函数来进行深拷贝。
     import copy

     list1= [1, [2, 3], 4]
     cp_list = copy.deepcopy(list1)

     list1[1][0] = 'X'
     print(list1)       # [1, ['X', 3], 4]
     print(cp_list )    # [1, [2, 3], 4]
     ```

总体而言,浅拷贝和深拷贝的选择取决于数据结构的嵌套程度以及是否需要保持独立性。

24 Python垃圾回收机制?

引用计数器为主,标记清除和分代回收为辅。

- 引用计数器
	Python中每个对象内部都维护了一个值,该值记录这此对象被引用的次数,
	如果次数为0,则Python垃圾回收机制会自动清除此对象
	
Python 使用自动垃圾回收机制来管理内存。
垃圾回收的主要目标是检测并回收不再被程序使用的内存,以防止内存泄漏。

Python 的垃圾回收机制主要依赖于两种策略:

1. **引用计数(Reference Counting)**- Python 中的每个对象都有一个引用计数,表示指向该对象的引用数量。
   - 当引用计数为零时,说明没有任何引用指向该对象,可以安全地将其内存释放。
   - 引用计数机制的优势是实时性,对象在变成垃圾时就能立即被回收。
   - 但是引用计数无法解决循环引用的问题。

2. **循环垃圾回收(Cycle Garbage Collection)**- 为了解决循环引用的问题,Python 引入了循环垃圾回收机制。
   - 通过周期性地检测循环引用并清理无法通过引用计数解决的对象。
   - 主要的算法是使用标记-清除(Mark and Sweep)策略。
   - 在标记阶段,从一组根对象(全局变量、调用栈、等等)出发,标记所有可以访问到的对象。
   - 在清除阶段,回收未标记的对象。
   - Python 的 `gc` 模块提供了与循环垃圾回收相关的功能,可以手动触发垃圾回收。
   
   # 手动触发垃圾回收
   import gc
   gc.collect()

这两种策略共同工作,保障了 Python 的内存管理。需要注意的是,Python 的垃圾回收机制在绝大多数情况
下能够很好地处理内存问题,但在某些场景下仍然可能出现内存泄漏。在这种情况下,通常需要通过代码审查、
性能分析等手段来定位和解决。

30. 求结果

v = dict.fromkeys(['k1', 'k2'], [])
v['k1'].append(666)
print(v)  # {'k1': [666], 'k2': [666]}
v['k1'] = 777
print(v)  # {'k1': 777, 'k2': [666]}


这段代码可能会导致预期之外的结果。让我们逐步解释:
v = dict.fromkeys(['k1', 'k2'], [])
v['k1'].append(666)
print(v)
"""
在这里,`fromkeys` 方法创建了一个字典 `v`,其中 `'k1'` 和 `'k2'` 是键,
而对应的值都是指向同一个空列表 `[]` 的引用。
因此,当你修改 `'k1'` 对应的列表时,实际上修改了字典中所有与之相同引用的值。
"""
输出将是:{'k1': [666], 'k2': [666]}
接下来的部分:
v['k1'] = 777
print(v)

"""
在这里,你更改了 `'k1'` 键的值,使其指向了一个新的整数 `777`。
但是请注意,原始的空列表 `[666]` 仍然存在于字典中,因为它是在创建字典时与键相关联的。
"""

输出将是:{'k1': 777, 'k2': [666]}


-如果你想避免这种情况,可以使用字典推导式创建具有独立列表的字典:
v = {key: [] for key in ['k1', 'k2']}
v['k1'].append(666)
print(v)
v['k1'] = 777
print(v)

这样你就能得到预期的结果:
{'k1': [666], 'k2': []}
{'k1': 777, 'k2': []}

31 一行代码实现删除列表中重复的值 ?

你可以使用 Python 的集合(Set)来快速删除列表中的重复值。一行代码如下:
lst= list(set(your_list))

这样,`your_list` 中的重复值将被去除,得到一个仅包含唯一元素的列表 `unique_list`。
请注意,这种方法可能会改变列表元素的顺序,因为集合是无序的。
如果需要保持原始顺序,可以使用以下方法:
lst= sorted(set(your_list), key=your_list.index)
这将确保 `lst` 的顺序与原始列表中的顺序相同。

32 如何实现 “1,2,3” 变成 [‘1’,’2’,’3’]

你可以使用字符串的 `split` 方法将字符串拆分成列表。
例如:
string = "1,2,3"
result_list = string.split(',')
print(result_list)


这将输出:['1', '2', '3']

在这里,`split(',')` 将字符串根据逗号进行拆分,得到包含每个数字的列表。

33 如何实现[‘1’,’2’,’3’]变成[1,2,3]

你可以使用列表推导来实现:
string_list = ['1', '2', '3']
result_list = [int(item) for item in string_list]
print(result_list)


这将输出:[1, 2, 3]
在这里,`int(item)` 将每个字符串元素转换为整数,然后列表推导创建一个包含整数的新列表。

34 比较: a = [1,2,3] 和 b = [(1),(2),(3) ] 以及 c = [(1,),(2,),(3,) ] 的区别?

在 Python 中,这三者之间的区别主要在于元素的类型和结构:

1. **a = [1, 2, 3]:**
   - `a` 是一个包含整数的列表。
   - 每个元素都是一个整数,列表中的元素类型是一致的。

2. **b = [(1), (2), (3)]:**
   - `b` 是一个包含元组的列表。
   - 每个元组只包含一个元素,这个元素是整数。元组用括号表示。

3. **c = [(1,), (2,), (3,)]:**
   - `c` 是一个包含元组的列表。
   - 每个元组只包含一个元素,这个元素是整数。
   - 与 b 不同的是,这里的元组元素后面有一个逗号,表示这是一个包含一个元素的元组。

实际上,在 Python 中,逗号是用于创建包含一个元素的元组的,例如 `(1,)`。
没有逗号的话,括号会被当作运算符使用。因此,`(1)` 被解释为整数 1,而不是包含一个元素的元组。

35 如何用一行代码生成[1,4,9,16,25,36,49,64,81,100] ?

你可以使用列表推导式来生成指定的列表,
例如:
result = [x**2 for x in range(1, 11)]
print(result)

这将生成包含 110 的平方的列表。
在这个例子中,`x**2` 表示 x 的平方,`for x in range(1, 11)` 表示对 x 在 110 范围内进行迭代。

36 常用字符串格式化哪几种?

在 Python 中,有几种常见的字符串格式化方式:
1. **百分号(%)格式化:**
   - 使用 `%` 操作符,类似于 C 语言的 `printf` 格式化。
   - 示例:
     name = "John"
     age = 30
     print("Name: %s, Age: %d" % (name, age))

2. **`str.format()` 方法:**
   - 使用 `{}` 占位符,通过 `format` 方法填充。
   - 示例:
     name = "John"
     age = 30
     print("Name: {}, Age: {}".format(name, age))

3. **f-字符串(格式化字符串字面值):**
   - 在字符串前加上 `f` 或 `F`,可以在字符串中直接嵌入变量。
   - 示例:
     name = "John"
     age = 30
     print(f"Name: {name}, Age: {age}")

4. **`str.join()` 方法:**
   - 使用 `join` 方法将多个字符串拼接在一起。
   - 示例:
     name = "John"
     age = 30
     print("Name: " + name + ", Age: " + str(age))

这些方法各有优劣,选择哪一种通常取决于具体的需求和个人偏好。
在 Python 3.6 及更高版本中,f-字符串是一种推荐的、简洁的格式化方式。

37 什么是断言(assert)?应用场景?

断言(assertion)是一种用于检查代码中的假设是否成立的语句。
在运行时,如果断言的条件为假,Python 解释器会抛出 `AssertionError` 异常。

`assert` 语句的语法如下:assert expression[, message]

- `expression` 是一个条件表达式,如果为 `True`,则什么都不发生,如果为 `False`,则会触发 `AssertionError`。
- `message` 是一个可选的参数,用于在触发异常时显示自定义的错误消息。

*** 应用场景:***
1. **调试:** 断言可以用于在代码中插入调试语句,检查某个条件是否成立,
	如果不成立,就会触发断言异常,帮助开发者定位问题。
   def divide(x, y):
       assert y != 0, "Cannot divide by zero"
       return x / y
       
2. **自检:** 在开发过程中,可以使用断言来进行自检,确保代码的执行环境满足预期条件。
   assert isinstance(value, int), "Value must be an integer"

3. **约定:** 断言可以用于设定约定,即预期代码的某些条件,有助于代码的可读性和维护性。
   assert len(items) > 0, "List should not be empty"


请注意,由于在生产环境中可能关闭了断言(使用 `-O` 选项运行 Python),
因此不应该依赖断言来处理错误或异常情况。它更适用于开发和调试阶段。

38 有两个字符串列表a和b,每个字符串是由逗号分隔的一些字符:

from collections import defaultdict

# 两个字符串列表a和b
a= [ 
	'a,1',
    'b,3,22',
    'c,3,4',
]

b = [
    'a,2',
    'b,1',
    'd,2',
]
按每个字符串的第一个值,合并a和b到c
c = [
    'a,1,2',
    'b,3,22,1',
    'c,3,4',
    'd,2'
]

# 合并a和b到c
c_dict = defaultdict(list)
print(c_dict)  # defaultdict(<class 'list'>, {})

# 将a和b中的每个字符串按照第一个值分组
for string in a + b:
    key, *values = string.split(',')
    c_dict[key].extend(values)

"""
这段代码是在处理两个字符串列表 `a` 和 `b`,每个字符串由逗号分隔的一些字符组成。
代码的目的是将这两个列表合并成一个新的列表 `c`,其中每个元素的第一个值作为字典的键,其余的值作为列表。

解释代码:
1. `for string in a + b:`:遍历列表 `a` 和 `b` 的元素,将它们合并成一个新的列表。
2. `key, *values = string.split(',')`:对于每个字符串,使用 `split(',')` 方法
	以逗号为分隔符拆分字符串,将第一个值赋给 `key`,将剩余的值赋给 `values`。
	这里使用了 	`*values` 来收集剩余的值,因为一个字符串可能包含多个逗号分隔的部分。

3. `c_dict[key].extend(values)`:将 `key` 对应的值从字典 `c_dict` 中取出,
	然后使用 `extend` 方法将 `values` 中的值添加到这个列表中。
	如果 `key` 在字典中不存在,会抛出 `KeyError`,因此需要确保 `c_dict` 中已经包含了所有可能的键。

综合起来,这段代码的作用是将两个字符串列表中的元素按照第一个值合并到一个新的字典 `c_dict` 中,
其中字典的键是第一个值,对应的值是一个列表,包含所有的剩余值。
"""

# 将结果格式化成要求的形式
c = [f"{key},{','.join(map(str, values))}" for key, values in c_dict.items()]
print(c)  # ['a,1,2', 'b,3,22,1', 'c,3,4', 'd,2']
"""
这段代码使用列表推导式构建了一个新的列表 `c`。
它将字典 `c_dict` 中的键值对格式化成字符串,并将这些字符串放入列表中。

具体解释:
1. `for key, values in c_dict.items()`: 迭代字典 `c_dict` 中的键值对。
2.  `','.join(map(str, values))`: 使用 `','.join()` 方法将列表 `values` 中的元素
	连接成一个字符串,每个元素之间用逗号分隔。
	`map(str, values)` 将 `values` 列表中的元素转换为字符串类型。

4.  `f"{key},{','.join(map(str, values))}"`: 使用 f-string 将 `key` 和连接后的字符串组合成一个新的字符串。

5. `[...]`: 构建一个列表,其中每个元素都是一个格式化后的字符串。

综合起来,这段代码的作用是将字典 c_dict`中的键值对格式化成字符串,并将这些字符串放入列表 `c` 中。
最终,c中的每个元素都代表了一个字符串,形如'a,1,2',其中'a'是键,而'1,2'是对应的值的字符串形式。
"""

这段代码首先使用 defaultdict(list) 创建了一个字典,然后遍历两个字符串列表 a 和 b,
将每个字符串按照第一个值分组。最后,将结果格式化成目标形式。

39 有一个多层嵌套的列表A=[1,2,[3,4,[“434”,…]]], 请写一段代码遍历A中的每一个元素并打印出来

当处理多层嵌套列表时,可以使用递归来遍历每个元素。
以下是一个示例代码:
def recursive_print(lst):
    for item in lst:
    	# isinstance(item, list)用于检查一个对象是否是给定类型的实例。在这里,它检查 item 是否是列表类型
        if isinstance(item, list): 
            recursive_print(item)
        else:
            print(item)

# 多层嵌套的列表
A = [1, 2, [3, 4, ["434", 5, [6, 7]]]]

# 调用递归函数遍历并打印
recursive_print(A)

此代码定义了一个递归函数 `recursive_print`,该函数接受一个列表作为参数,
并对列表中的每个元素进行遍历。如果元素是列表,则递归调用该函数,否则直接打印元素。

40 a = range(10),a[::-3] 的结果是

`a = range(10)` 创建了一个包含09range 对象。
`a[::-3]` 是切片操作,步长为-3,表示从后往前每隔3个元素取一个。

解释:
1. `a = range(10)`: 创建了一个 range 对象,包含 09 的整数。
2. `a[::-3]`: 从后往前每隔3个元素取一个。这里的步长为-3,表示反向取值。
	所以,`a[::-3]` 的结果是包含从后往前每隔3个元素的 range 对象。
	在这个例子中,从后往前数,索引为 -1-4-7。所以结果为 `range(9, 6, 3)`。

41 下面那个命令可以从虚拟环境中退出

A.  deactivate  
B.  exit
C.  quit
D.  以上均可

选择:A

42 将列表内的元素,根据位数合并成字典

lst = [1,2,4,8,16,32,64,128,256,512,1024,32769,65536,4294967296]

# 输出
{
    1:[1,2,3,8],
    2:[16,32,64],
    3:[128,256,512],
    4:[1024,],
    5:[32769,65536],
    6:[4294967296]
}

# 定义一个空列表
result_dict = {}

for num in lst:
    num_str = str(num)
    length = len(num_str)
    
    if length not in result_dict:
        result_dict[length] = []
    
    result_dict[length].append(num)

print(result_dict)
# {1: [1, 2, 4, 8], 2: [16, 32, 64], 3: [128, 256, 512], 4: [1024], 5: [32769, 65536], 10: [4294967296]}


"""
这段代码的目的是将列表 `lst` 中的元素按照它们的位数进行分组,然后将它们存储到一个字典 `result_dict` 中。

1. `result_dict = {}`: 创建一个空字典,用于存储分组后的结果。
2. `for num in lst:`: 遍历列表 `lst` 中的每个元素。
3. `num_str = str(num)`: 将当前数字转换为字符串,以便计算它的位数。
4. `length = len(num_str)`: 获取当前数字的位数。
5. `if length not in result_dict:`: 如果当前位数在字典中不存在,就在字典中创建一个空列表。
6. `result_dict[length].append(num)`: 将当前数字添加到对应位数的列表中。

最终,`result_dict` 将包含每个位数的数字列表。
"""

43 请尽量用简洁的方法将二维数组转换成一维数组

: 转换前 :
lst=[[1,2,3],[4,5,6],[7,8,9]]

转换后:
lst = [1,2,3,4,5,6,7,8,9]


# 使用列表推导将二维数组转换为一维数组
flattened_lst = [item for sublist in lst for item in sublist]

print(flattened_lst)  # [1, 2, 3, 4, 5, 6, 7, 8, 9]

44 将列表按下列规则排序, 补全代码

1.正数在前负数在后
2.正数从小到大
3.负数从大到小

例: 

排序前[7,-8,5,4,0,-2,-5]

排序后[0,4,5,7,-2,-5,-8]

补全代码:

sorted(lst,key=lambda x:_____)

sorted_lst = sorted(lst, key=lambda x: (x >= 0, abs(x)))
"""
这使用了 sorted 函数的 key 参数。lambda x: (x >= 0, abs(x)) 返回一个元组,
其中第一个元素是一个布尔值,表示正数(True)或负数(False),第二个元素是数字的绝对值。
这确保了正数在前,正数按从小到大排序,负数按从大到小排序。
"""

45 哈希冲突回避算法有哪几种, 分别有什么特点?

1. **开放寻址法(Open Addressing)**- **线性探测(Linear Probing):** 如果发生冲突,就线性地检查下一个槽位,直到找到一个空槽。
    - **二次探测(Quadratic Probing):** 如果发生冲突,就使用二次方程来找到下一个槽位。
    - **双重散列(Double Hashing):** 使用第二个哈希函数来计算下一个槽位。

2. **链地址法(Separate Chaining)**- 将哈希表的每个槽位指向一个链表,发生冲突时,将元素添加到相应的链表中。

3. **再哈希(Rehashing)**- 当哈希表达到一定的负载因子时,进行扩容,重新计算哈希值。这是一种动态调整哈希表大小的策略。

4. **建立公共溢出区域(Cuckoo Hashing)**- 使用两个或多个哈希函数,如果发生冲突,尝试将元素移动到另一个槽位。如果无法移动,就重新哈希。

5. **Coalesced Hashing**- 类似于链地址法,但是将冲突的元素直接存储在数组中,而不是在链表中。

6. **局部敏感哈希(Locality-Sensitive Hashing)**- 主要应用于近似最近邻搜索等问题,通过哈希函数将相似的输入映射到相似的哈希值,从而减小哈希冲突的概率。

每种算法都有其适用的场景和性能特点,选择合适的冲突解决算法取决于具体的应用和需求。

46 简述Python的字符串驻留机制?

在Python中,字符串的驻留机制是指对于较短的字符串,Python 会确保相同的字符串对象只有一个实例,
而不是在内存中创建多个相同内容的字符串。

这个机制的好处是:
1. **节省内存:** 对于较短的字符串,如果相同的字符串频繁出现,采用驻留机制可以减少内存的使用,
	因为相同的字符串只需保存一份。
	
2. **提高性能:** 字符串的比较可以通过对象的身份比较(identity comparison)来实现,
	而不是逐字符比较,这样可以提高比较的速度。

字符串的驻留机制并不是对所有字符串都生效的,它有一些限制,
例如:
- 驻留机制通常只对较短的字符串生效,Python 中的具体阈值可能会因版本和实现而有所不同。
- 字符串的驻留是由解释器控制的,而不是由程序员手动控制的。
	例如,通过字符串拼接或格式化生成的字符串可能不会进行驻留。

字符串对象的驻留状态可以通过 `sys.intern()` 函数来手动触发。
这个函数会尝试将字符串驻留,如果成功,返回驻留的字符串对象;如果字符串已经驻留,直接返回该对象。

47 以下代码输出是什么? list=[‘a’,‘b’,‘c’,‘d’,‘e’] print list[10:]

A.  []
B.  程序异常
C.  ['a','b','c','d','e']
D.  输出空

在给定的代码中,`list` 是一个 Python 列表,包含元素 `'a', 'b', 'c', 'd', 'e'`。
但是,当你尝试通过索引 `10` 获取列表的子集时,由于索引越界,Python 并不会抛出 `IndexError`,
而是返回一个空列表。
所以,`list[10:]` 的输出将是 `[]`,表示从索引 `10` 开始的子列表为空。

48 Python语言中哪些类型的数据才能做为字典的key?

A.  没有限制
B.  字母数字下划线
C.  字母
D.  可被hash的类型

在 Python 中,字典的键(key)必须是不可变的数据类型。这是因为字典是基于哈希表实现的,
而哈希表的键需要是不可变的,以保证哈希值的稳定性。
以下是常见的可以作为字典键的数据类型:

1. **不可变数据类型:**
   - **整数(int**
   - **浮点数(float**
   - **字符串(str**
   - **元组(tuple**:当元组内只包含不可变元素时,整个元组是不可变的。

2. **用户自定义的不可变对象:**
   - 如果你定义的类实例是不可变的,那么这个类的实例也可以作为字典的键。


# 整数
dict_int = {1: 'one', 2: 'two'}

# 字符串
dict_str = {'apple': 1, 'banana': 2}

# 元组(包含不可变元素)
dict_tuple = {(1, 2): 'onetwo', (3, 4): 'threefour'}

# 自定义不可变对象
class MyKey:
    def __init__(self, key):
        self.key = key

    def __hash__(self):
        return hash(self.key)

    def __eq__(self, other):
        return self.key == other.key

obj = MyKey('example')
dict_custom = {obj: 'custom_key'}

print(dict_int)
print(dict_str)
print(dict_tuple)
print(dict_custom)

注意:列表(list)和字典(dict)是可变的,因此不能作为字典的键。


49 以下两段代码的输出一样吗, 占用系统资源一样吗, 什么时候要用xrange代替range

for i  in range(1): print i

for i in xrange(1): print i


在 Python 2 中,`range` 和 `xrange` 是有区别的,但在 Python 3 中,`xrange` 已经被移除,
而 `range` 的行为变得类似于 Python 2 中的 `xrange`。
**Python 2 中:**
# 使用 range
for i in range(5):
    print(i)

# 使用 xrange
for i in xrange(5):
    print(i)


在 Python 2 中,`range` 会创建一个列表对象,而 `xrange` 创建的是一个 xrange 对象,
它是一个生成器,用于按需产生值。当你使用 `range` 创建一个很大的范围时,它会占用较多的内存,
而 `xrange` 是一个节省内存的选择,因为它在迭代的过程中生成值。

**Python 3 中:**
# 使用 range
for i in range(5):
    print(i)

# Python 3 中已经没有 xrange,range 的行为类似于 Python 2 中的 xrange
for i in range(5):
    print(i)


在 Python 3 中,`range` 对象的行为更类似于 Python 2 中的 `xrange`,
即它返回的是一个类似生成器的对象,而不是直接生成一个列表。

**占用系统资源:**
在 Python 3 中,由于 `range` 对象的行为已经优化,占用的系统资源相对较小。
因此,在 Python 3 中,你一般不需要担心 `range` 的占用系统资源的问题。

**什么时候使用 `range` 或 `xrange`(仅在 Python 2 中使用):**
1. 在 Python 3 中,通常使用 `range`,因为它的行为更符合预期。
2. 在 Python 2 中,如果你知道你的范围很大,而且你希望避免创建一个大的列表,可以使用 `xrange`。

总体来说,在 Python 3 中,使用 `range` 就足够了。

50 如下代码段


请问a,b,c,d的值为?

import copy

a = [1, 2, 3, [4, 5], 6]
b = a
c = copy.copy(a)
d = copy.deepcopy(a)

b.append(10)
c[3].append(11)
d[3].append(12)

print("a:", a)  # [1, 2, 3, [4, 5, 11], 6, 10]
print("b:", b)  # [1, 2, 3, [4, 5, 11], 6, 10]
print("c:", c)  # [1, 2, 3, [4, 5, 11], 6, 10]
print("d:", d)  # [1, 2, 3, [4, 5, 12], 6]

结果:
- `a`: `[1, 2, 3, [4, 5, 11], 6, 10]`
- `b`: `[1, 2, 3, [4, 5, 11], 6, 10]`(b是a的引用,所以和a相同)
- `c`: `[1, 2, 3, [4, 5, 11], 6, 10]`(浅拷贝只复制了最外层对象,内部的列表还是共享的)
- `d`: `[1, 2, 3, [4, 5, 12], 6]`(深拷贝复制了所有层级的对象,所以修改d的内部列表不影响a)

说明:
- 对`a`的修改会影响`b`,因为它们引用同一对象。
- `c`是`a`的浅拷贝,因此对内部可变对象的修改会影响原始对象。
- `d`是`a`的深拷贝,因此对内部可变对象的修改不会影响原始对象。
- 

51 现有字典d={“a”:26,“g”:20,“e”:20,“c”:24,“d”:23,“f”:21,“b”:25} 请按照字段中的value字段进行排序。

你可以使用`sorted`函数来按照字典的值进行排序,并返回一个新的有序的列表。
以下是对字典按值排序的代码:
d = {"a": 26, "g": 20, "e": 20, "c": 24, "d": 23, "f": 21, "b": 25}
sorted_d = dict(sorted(d.items(), key=lambda item: item[1]))
print(sorted_d)

这里的`sorted(d.items(), key=lambda item: item[1])`将字典的键值对转换成元组,
然后按照元组的第二个元素(即值)进行排序。最后,`dict()`将排序后的元组列表转回字典。

上述代码的输出将是按值升序排序的字典。
如果你想要降序排序,可以在`sorted`函数中添加`reverse=True`参数:
sorted_d_desc = dict(sorted(d.items(), key=lambda item: item[1], reverse=True))
print(sorted_d_desc)
这将按值降序排序。

# 代码解释
"""
这段代码是对字典 `d` 中的项按照值进行降序排序,并将结果保存在 `sorted_d_desc` 中。
让我逐步解释:
1. `sorted(d.items(), key=lambda item: item[1], reverse=True)` 对字典的项进行排序。
	`items()` 方法返回一个包含字典所有项的列表,每个项是一个键值对,
	然后 `sorted` 函数按照这些项的值进行排序。
	`key=lambda item: item[1]` 表示排序的依据是每个项的第二个元素(也就是值),
	`reverse=True` 表示降序排序。
3. `dict(...)` 将排序后的列表转换回字典。

所以,最终,`sorted_d_desc` 将包含按值降序排列的字典项。
"""

52 给定两个listA,B,请用Python找出A,B中相同的元素,A,B中不同的元素

你可以使用集合(set)的操作来找出两个列表中的相同元素和不同元素。
以下是一个简单的例子:

listA = [1, 2, 3, 4, 5]
listB = [3, 4, 5, 6, 7]

setA = set(listA)
setB = set(listB)

# 相同的元素
common_elements = setA.intersection(setB)

# A 中不同于 B 的元素
unique_to_A = setA.difference(setB)

# B 中不同于 A 的元素
unique_to_B = setB.difference(setA)

print("相同的元素:", common_elements)
print("A 中不同于 B 的元素:", unique_to_A)
print("B 中不同于 A 的元素:", unique_to_B)

这将输出:
相同的元素: {3, 4, 5}
A 中不同于 B 的元素: {1, 2}
B 中不同于 A 的元素: {6, 7}
这里使用了集合的 `intersection`、`difference` 方法来执行相应的集合操作。

53. 下列叙述中错误的是

 A.  栈是线性结构
 B.  队列是线性结构
 C.  线性列表是线性结构
 D.  二叉树是线性结构

D. 二叉树是线性结构
解释:
- 栈和队列都是线性结构,因为它们的元素排成一条线的形式。
- 线性列表是线性结构的一种,它可以是数组或链表等形式,也是元素排成一条线的结构。
- 二叉树是一种非线性结构,因为树形结构不是排成一条线的形式。
	在二叉树中,每个节点最多有两个子节点,而不是像线性结构那样一个接一个地排列。

54 一个栈的输入序列为1,2,3,4,5, 则下列序列中不可能是栈的输出序列的是

栈的特点是先进后出(FILO),因此,对于输入序列1,2,3,4,5,合法的栈输出序列应该是从5开始逆序排列。
对于给定的选项:

A. 1 5 4 3 2 - 合法,因为栈的输出是逆序的。
B. 2 3 4 1 5 - 合法,因为栈的输出是逆序的。
C. 1 5 4 2 3 - 不合法,因为在5之后,应该是4而不是2。
D. 2 3 1 4 5 - 不合法,因为在3之后,应该是4而不是1。

所以,不可能是栈的输出序列的是 C. 1 5 4 2 3

55 下图那些PEP被认为涉及到了代码规范

1.  PEP7
2.  PEP8
3.  PEP20
4.  PEP257

PEP8 和 PEP257 被认为涉及到了代码规范。这两个PEP分别关注Python代码的编写风格和文档编写规范。
所以正确的选项是:
2. PEP8
4. PEP257

56 下面那些是Python合法的标识符?那些是Python的关键字?

1.  int32
2.  40XL
3.  saving$
4.  ptint
5.  this
6.  self
7.  0x40L
8.  true
9.  big-daddy
10.  True
11.  if
12.  do
13.  yield

合法的标识符是:
1. int32
2. this
3. self
4. 0x40L
5. True
6. do
7. yield

Python 的关键字是:
1. ptint (错误,正确拼写是 print)
2. true (小写,正确写法是 True)
3. big-daddy (连字符 "-" 不是合法标识符的一部分)
4. if
5. do (不是 Python 的关键字)
6. yield

57 从0-99这100个数中随机取出10个, 要求不能重复, 可以自己设计数据结构

你可以使用 Python 的 `random.sample()` 函数来实现从099100个数中随机取出10个不重复的数。
下面是一个简单的示例:
import random

random_numbers = random.sample(range(100), 10)
print(random_numbers)

这将输出一个包含10个不重复随机数的列表。

58 python 判断一个字典中是否有这些key: “AAA”,‘BB’,‘C’,“DD”,‘EEE’(不使用for while)

你可以使用 `all` 函数结合 `in` 操作符来检查字典中是否包含指定的多个键。
以下是一个例子:
my_dict = {'AAA': 1, 'BB': 2, 'C': 3, 'DD': 4}
keys_to_check = ["AAA", 'BB', 'C', "DD", 'EEE']

# 使用 all 函数检查所有键是否存在于字典中
keys_exist = all(key in my_dict for key in keys_to_check)
if keys_exist:
    print("所有键都存在于字典中")
else:
    print("有键不存在于字典中")

这里,`all(key in my_dict for key in keys_to_check)` 将检查所有指定的键是否都存在于字典中。
如果所有键都存在,则 `keys_exist` 将为 `True`,否则为 `False`。

59 有一个list[“This”,“is”,“a”,“Boy”,“!”], 所有元素都是字符串, 对他进行大小写无关的排序

要进行大小写无关的排序,可以使用 `sorted()` 函数,并设置 `key` 参数为 `str.lower`。
这样排序时会将字符串都转换成小写形式再进行比较。
my_list = ["This", "is", "a", "Boy", "!"]
sorted_list = sorted(my_list, key=str.lower)
print(sorted_list)

这会输出:['a', 'Boy', 'is', 'This', '!']

这样,列表中的元素按照字母顺序排列,而且是不区分大小写的。

"""
sorted() 是 Python 中的内置函数,用于对可迭代对象进行排序。
它返回一个新的已排序的列表,不修改原始对象。
sorted(iterable, key=None, reverse=False)
iterable: 待排序的可迭代对象,可以是列表、元组、字符串等。
key(可选): 用于指定一个用来从每个列表元素中提取比较键的函数。默认为 None,表示直接比较元素本身。
reverse(可选): 如果设置为 True,则进行降序排序;默认为 False,即升序排序。
"""

60 描述下dict的item()方法与iteritems()的不同

在 Python 2 中,`dict` 类有两个类似的方法:`items()` 和 `iteritems()`,
它们的主要区别在于返回的对象类型和内存占用。

1. **`items()` 方法**- 返回一个包含所有字典项(键-值对)的列表。该列表包含实际的键值对,占用额外的内存。
   - 返回类型是 `list`。
     my_dict = {'a': 1, 'b': 2, 'c': 3}
     items = my_dict.items()

2. **`iteritems()` 方法**- 返回一个迭代器对象,该对象生成字典的所有键-值对。
   - 不占用额外内存,因为它是惰性的,即只在需要时才生成值。
   - 返回类型是 `dictionary-itemiterator`。
     my_dict = {'a': 1, 'b': 2, 'c': 3}
     iteritems = my_dict.iteritems()

在 Python 3 中,由于 `items()` 返回的是视图对象(`dict_items` 类型),而不再是列表,
而且更加节省内存,因此 `iteritems()` 被废弃。因此,Python 3 中只有 `items()` 方法。

61 请列举你所知道的Python代码检测工具及他们间的区别?

在 Python 中,有一些常见的代码检测工具,用于帮助开发者发现潜在的问题、遵循编码规范等。
以下是一些常见的 Python 代码检测工具及它们之间的主要区别:

1. **Flake8**:
   - **检测内容**: Flake8 集成了三个工具,分别是 PyFlakes、mccabe 和 pycodestyle。
   		PyFlakes 用于静态代码分析,mccabe 用于检测复杂性,pycodestyle 用于检测 PEP 8 规范。
   - **安装**: `pip install flake8`
   - **使用**: 运行 `flake8` 命令。

2. **pylint**:
   - **检测内容**: Pylint 是一个更全面的工具,它执行静态代码分析、检查命名规范、查找代码错误等。
   - **安装**: `pip install pylint`
   - **使用**: 运行 `pylint your_code.py`

3. **black**:
   - **检测内容**: Black 主要用于代码格式化,可以保持一致的代码风格。
   - **安装**: `pip install black`
   - **使用**: 运行 `black your_code.py`

4. **mypy**:
   - **检测内容**: Mypy 是一个静态类型检查器,用于发现潜在的类型错误。
   - **安装**: `pip install mypy`
   - **使用**: 运行 `mypy your_code.py`

5. **Bandit**:
   - **检测内容**: Bandit 专注于安全性检查,用于查找代码中的安全漏洞。
   - **安装**: `pip install bandit`
   - **使用**: 运行 `bandit -r your_code_directory`

6. **isort**:
   - **检测内容**: isort 用于排序和格式化导入语句。
   - **安装**: `pip install isort`
   - **使用**: 运行 `isort your_code.py`

7. **Safety**:
   - **检测内容**: Safety 用于检查项目中使用的 Python 包是否存在已知的安全漏洞。
   - **安装**: `pip install safety`
   - **使用**: 运行 `safety check`

这些工具通常可以集成到编辑器或持续集成(CI)工具中,以便在编写代码或提交代码时自动运行。
选择使用哪个工具通常取决于项目的具体需求,有些项目可能会同时使用多个工具以确保代码的质量和安全性。

62 介绍一下try except的用法和作用?

`try` 和 `except` 是 Python 中用于异常处理的关键字。
异常处理允许你编写能够应对异常情况的代码,以避免程序在遇到错误时崩溃。

### 用法:
try:
    # 可能抛出异常的代码块
    result = some_operation()
except SomeException as e:
    # 处理特定异常的代码块
    handle_exception(e)
except AnotherException as e:
    # 处理另一种异常的代码块
    handle_another_exception(e)
else:
    # 如果没有异常发生时执行的代码块
    handle_no_exception()
finally:
    # 无论是否发生异常都会执行的代码块
    cleanup()


### 解释:
- `try` 块中包含可能会引发异常的代码。
- `except` 块用于捕获并处理 `try` 块中的异常。你可以指定要捕获的异常类型,并提供相应的处理逻辑。
- 如果 `try` 块中的代码引发了指定类型的异常,程序将跳转到匹配的 `except` 块,执行相应的处理逻辑。
- `else` 块包含在没有发生异常时要执行的代码。它是可选的。
- `finally` 块包含无论是否发生异常都会执行的代码,比如资源清理。

### 作用:
1. **异常处理**: 允许你在程序执行期间捕获和处理异常,防止程序因错误而崩溃。
2. **代码流程控制**: 允许你根据代码执行情况选择执行不同的代码路径。
3. **资源清理**: `finally` 块中的代码用于确保在发生异常时也能执行清理代码,比如关闭文件或释放资源。

### 示例:
try:
    x = 1 / 0
except ZeroDivisionError as e:
    print(f"Error: {e}")
else:
    print("No exception occurred.")
finally:
    print("This will be executed no matter what.")


在这个例子中,由于除以零是不合法的,它会引发 `ZeroDivisionError`。
`except` 块捕获了这个异常并打印错误信息,然后 `finally` 块中的代码会被执行,无论是否发生异常。

63 输入一个字符串, 返回倒序排列的结果 如: abcdef, 返回 fedcba

你可以使用 Python 中字符串的切片来实现字符串的倒序排列。
下面是一个简单的示例函数:

def reverse_string(input_str):
    return input_str[::-1]

# 示例
original_str = "abcdef"
result = reverse_string(original_str)
print(result)


在这个例子中,`[::-1]` 表示从字符串的末尾开始,每次步进为 -1,即倒序。
你可以将这个函数用于输入任何字符串,都会返回其倒序排列的结果。

64 阅读以下代码, 并写出程序的输出结果

alist = [2,4,5,6,7]
for var in alist:
    if var %2 ==0:
        alist.remove(var)
alist的最终结果是什么?

在 Python 中,当你在迭代列表的同时修改列表的大小时,可能会导致意外的结果。
这是因为 `for var in alist` 实际上会在迭代开始时确定要迭代的元素,而不会在迭代过程中动态更新。

在这个例子中,你试图删除 `alist` 中的偶数元素。
如果你运行这段代码,会得到 `alist` 的一个意外结果。
由于在迭代的同时修改了列表,可能导致某些元素被漏掉或重复。

最终的 `alist` 结果取决于 Python 解释器的具体实现,因为这种行为是未定义的。
可能的输出包括 `[4, 6]`、`[2, 5, 7]` 、 [4, 5, 7]或其他一些不稳定的结果。

为了避免这种问题,最好在迭代的时候创建一个新的列表,而不是修改原始列表。
例如:
alist = [2, 4, 5, 6, 7]
alist = [var for var in alist if var % 2 != 0]

这样你就能得到预期的结果。

65 现有列表alist=[3,1,-4,-2],按期元素的绝对值大小进行排序?

你可以使用 `sorted` 函数,并通过 `key` 参数指定排序的依据,
如下所示:
alist = [3, 1, -4, -2]
sorted_alist = sorted(alist, key=abs)
print(sorted_alist)

这会根据元素的绝对值大小进行排序,
输出结果为:`[-1, -2, 3, -4]`。

66 填空题

1. 表达式 `3<4<5` 是哪一个表达式的缩写___.
   - **答案:** 这是一个缩写形式的连续比较,相当于 `(3 < 4) and (4 < 5)`。

2. 获取Python解释器版本的方法是:____.
   - **答案:** `sys` 模块提供了 `sys.version` 属性,可以使用 `import sys` 和 `sys.version` 来获取 Python 解释器版本。

3. 如果模块是被导入的, `__name__` 的值是____, 如果模块是被直接执行的 `__name__` 的值是___.
   - **答案:** 当模块被导入时,`__name__` 的值是模块的名称;当模块被直接执行时,`__name__` 的值是 `'__main__'`。

4. Python的内存管理中, 为了追踪内存中的对象, 使用了____这一简单技术
   - **答案:** 引用计数是一种简单的技术,用于追踪内存中对象的引用次数。
   - 每当引用对象时,引用计数加一;每当解除对对象的引用时,引用计数减一。当引用计数为零时,对象的内存就会被释放。

5. Python的标准解释器是由C语言实现的, 称为____, 有Java实现的被称为___.
   - **答案:** Python 的标准解释器是由C语言实现的,称为 CPython。而有Java实现的Python解释器称为 Jython。

6. Python中, ___语句能直接显示的释放内存资源
   - **答案:** `del` 语句可以用于删除对象引用,从而释放内存。
   例如,`del some_variable` 可以删除对变量 `some_variable` 的引用,从而释放相关的内存。

7. Python的乘方运算符是__
   - **答案:** Python 的乘方运算符是 `**`。例如,`2 ** 3` 表示 23 次方。

67 现有字典mydict和变量onekey, 请写出从mydict中取出onekey值的方法(不止一种写法, 多写加分, 并请叙述不同写法的区别, mydict中是否存在onekey的键值, 不确定)

从字典 `mydict` 中取出键 `onekey` 对应的值有几种方法,其中一些方法如下:

1. **直接索引取值:**
    value = mydict[onekey]
   - **说明:** 这是最基本的方法,假定 `onekey` 存在于 `mydict` 中。
   - 如果 `onekey` 不存在,会抛出 `KeyError` 异常。

2. **get方法取值:**
    value = mydict.get(onekey)
   - **说明:** 使用 `get` 方法获取值,如果键不存在,返回 `None`,而不会抛出异常。

3. **使用setdefault方法:**
    value = mydict.setdefault(onekey, default_value)
   - **说明:** 如果 `onekey` 存在于 `mydict` 中,返回其对应的值;
   - 如果不存在,则将 `default_value` 设置为 `onekey` 的值,并返回 `default_value`。

4. **使用in判断键是否存在:**
    if onekey in mydict:
        value = mydict[onekey]
    else:
        value = None  # 或其他默认值
   - **说明:** 使用 `in` 判断 `onekey` 是否存在于字典中,然后再进行相应的操作。

这些方法的选择取决于具体的需求,如果确定键一定存在,直接索引是简洁的方式。
如果键可能不存在,使用 `get` 或 `setdefault` 可以提供默认值或避免异常。

68 现有一列表alist, 请写出两种去除alist中重复元素的方法, 其中:

- 要求保持原有列表中元素的排列顺序。
- 无需考虑原有列表中元素的排列顺序。
### 保持原有列表中元素的排列顺序
1. **使用循环和列表:**
   alist = [1, 2, 2, 3, 4, 4, 5]
   result = []
   for item in alist:
       if item not in result:
           result.append(item)
           
2. **使用列表推导式和集合(Python 2.7+):**
   alist = [1, 2, 2, 3, 4, 4, 5]
   result = list(dict.fromkeys(alist).keys())

3. **使用OrderedDict(Python 3.7+):**
   from collections import OrderedDict
   alist = [1, 2, 2, 3, 4, 4, 5]
   result = list(OrderedDict.fromkeys(alist))
"""

这行代码的目的是去除列表 `alist` 中的重复元素,
并将去重后的元素以列表的形式存储在 `result` 变量中。
下面对代码进行详细解释:
result = list(dict.fromkeys(alist).keys())

1. `dict.fromkeys(alist)`:使用列表 `alist` 中的元素作为字典的键(key),创建一个新的字典。
	由于字典的键是唯一的,这一步的效果是去除了 `alist` 中的重复元素。

2. `.keys()`:获取字典中的所有键(key)。

3. `list(...)`:将得到的键以列表的形式重新包装。

整体而言,这行代码的执行过程如下:
- `dict.fromkeys(alist)` 创建一个字典,字典中的键是 `alist` 中的元素,值为 `None`。
- 通过 `.keys()` 获取字典中的所有键。
- 最后,通过 `list(...)` 将键转换为列表,得到了去重后的列表 `result`。

这样,`result` 中包含了 `alist` 中去重后的元素,且保持了元素原有的顺序。
"""


### 无需考虑原有列表中元素的排列顺序
1. **使用集合:**
   alist = [1, 2, 2, 3, 4, 4, 5]
   result = list(set(alist))

2. **使用循环和列表(无序):**
   alist = [1, 2, 2, 3, 4, 4, 5]
   result = []
   for item in alist:
       if item not in result:
           result.append(item)

3. **使用列表推导式和集合(无序):**
   alist = [1, 2, 2, 3, 4, 4, 5]
   result = list({}.fromkeys(alist))

以上方法中,第一组适用于需要保持原有列表顺序的情况,而第二组则适用于无需考虑原有顺序的情况。
在 Python 3.7 及以上版本中,字典的实现是有序的,因此可以使用 `OrderedDict` 来保持顺序。

69 请描述Unicode,utf-8, gbk等编码之间的区别?

Unicode、UTF-8 和 GBK 是字符编码的不同方式,它们解决了字符在计算机内部存储和传输的方式。

1. **Unicode(统一码):**
   - Unicode 是一个国际标准,为文本编码提供了统一的编号,可以容纳世界上几乎所有的字符,每个字符都有唯一的 Unicode 编码。
   - Unicode 编码通常用 U+ 开头,后面跟着字符的十六进制表示,例如 U+0041 表示字符 'A'2. **UTF-8(Unicode Transformation Format - 8-bit):**
   - UTF-8 是 Unicode 的一种变长字符编码,它可以用来表示 Unicode 标准中的任何字符,使用 8 位(一个字节)或更多的字节。
   - UTF-8 是一种可变长的编码方式,对于 ASCII 字符,使用一个字节,而对于其他字符,使用多个字节。这样,它既保持了向后兼容性,又能够表示全球各种字符。

3. **GBK(汉字内码扩展规范):**
   - GBK 是对汉字编码的扩展,它包含了 Unicode 之外的一些汉字,是中文编码的一种。
   - GBK 通常使用 2 个字节来表示一个汉字,与 ASCII 兼容。

**区别总结:**
- **Unicode:** 提供了字符到数字的映射,是一种字符集,不关心如何存储。
- **UTF-8** 是 Unicode 的一种实现方式,它定义了如何存储 Unicode 字符。它是一种可变长编码,对于 ASCII 字符使用一个字节,对于其他字符使用多个字节。
- **GBK:** 是一种中文字符编码,通常使用 2 个字节表示一个字符。

在实际应用中,UTF-8 逐渐成为最常见的字符编码方式,因为它不仅能够表示全球各种字符,而且在存储和传输时更加高效。

70 哪些情况下, y != x - (x-y)会成立?

在浮点数的计算中,由于浮点数的精度限制,可能会导致 `y != x - (x - y)` 成立。
这是因为浮点数的表示是有限的,无法准确表示所有的实数,因此在计算中可能引入一些舍入误差。

这类误差通常在小数点后几位,但在某些情况下,它们可能会导致 `y != x - (x - y)` 的比较结果为真。
在实际编码中,比较浮点数时应该使用适当的误差范围
(例如,通过比较它们的差的绝对值是否小于某个很小的数值),而不是直接使用等号。

以下是一个例子,演示了浮点数精度引起的问题:
x = 0.1 + 0.2  # 0.1 + 0.2 的精确值应该是 0.3
y = 0.3

# 在浮点数计算中可能引入小的误差
result = y != x - (x - y)
print(result)  # 可能会输出 True,具体结果取决于浮点数的精度


在这个例子中,`x` 实际上不等于 `0.3`,因此 `y != x - (x - y)` 的结果可能为真。

71 用Python实现九九乘法表(用两种不同的方法实现)

# 方式一:
for i in range(1, 10):
    for j in range(1, i + 1):
        print(f'{j}x{i}={i * j}\t', end='')
    print()

# 方式二:
i = 1
while i <= 9:
    j = 1
    while(j <= i):    # j的大小是由i来控制的
        print(f'{i}*{j}={i*j}', end='\t')
        j += 1
    print('')
    i += 1

# 方式三:
i = 1
while i <= 9:
    for j in range(1, i+1):  # range()函数左闭右开
        print(f'{i}*{j}={i*j}', end=' ')
    i += 1
    print()
   
# 方式四:
for i in range(1, 10):
    j = 0
    while j < i:
        j += 1
        print(f"{i}*{j}={i*j}", end=' ')
    print()

72 获取list中的元素个数,和向末尾追加元素所用的方法分别是什么?

在 Python 中,获取列表中的元素个数可以使用 `len()` 函数,向列表末尾追加元素可以使用 `append()` 方法。
以下是简单的示例:

# 创建一个列表
my_list = [1, 2, 3, 4, 5]

# 获取列表中的元素个数
length = len(my_list)
print(f"列表中的元素个数: {length}")

# 向列表末尾追加元素
my_list.append(6)
print(f"追加元素后的列表: {my_list}")

上述代码中,`len(my_list)` 返回列表 `my_list` 中元素的个数,`append(6)` 向列表末尾追加了元素 `6`。

73 判断dict中有没有某个key用的方法是什么?

在Python中,可以使用`in`关键字来判断一个字典中是否包含某个键。
以下是一个例子:
my_dict = {'a': 1, 'b': 2, 'c': 3}

# 判断 'b' 是否是字典的键
if 'b' in my_dict:
    print('Key "b" exists in the dictionary.')
else:
    print('Key "b" does not exist in the dictionary.')


在上面的例子中,`'b' in my_dict` 返回 `True`,因为字典`my_dict`中存在键为 `'b'` 的键值对。

74 填空

l=range(100)

1.取第一到第三个元素可以使用切片操作:
first_three = list(l[:3])
print(first_three)  # [0, 1, 2]

2.取倒数第二个元素可以使用切片和负数索引:
second_last = l[-2]
print(second_last)  # 98

3.取后十个元素可以使用切片:
last_ten = list(l[-10:])
print(last_ten)  # [90, 91, 92, 93, 94, 95, 96, 97, 98, 99]

请注意,为了得到实际的列表,需要使用 `list()` 将 `range` 转换为列表。

75 如何判断一个变量是否是字符串?

可以使用 `isinstance()` 函数来判断一个变量是否是字符串。
下面是一个示例:
my_variable = "Hello, World!"

if isinstance(my_variable, str):
    print("my_variable 是字符串")
else:
    print("my_variable 不是字符串")


这里 `isinstance()` 函数接受两个参数,第一个参数是要检查的变量,第二个参数是要检查的类型。
上述示例中,它检查 `my_variable` 是否是字符串类型。如果是字符串类型,就会打印 "my_variable 是字符串"

76 list和tuple有什么不同?

`list` 和 `tuple` 是 Python 中两种不同的序列类型,它们有以下主要区别:

1. **可变性:**
   - **List(列表)** 是可变的,也就是说,你可以在创建之后修改列表,包括添加、删除和修改元素。
   - **Tuple(元组)** 是不可变的,一旦创建之后,不能对元组进行修改。不能添加、删除或修改元组的元素。

2. **语法表示:**
   - **List(列表)** 使用方括号 `[]` 表示。例如:`my_list = [1, 2, 3]`
   - **Tuple(元组)** 使用圆括号 `()` 表示。例如:`my_tuple = (1, 2, 3)`

3. **性能:**
   - 由于 `tuple` 是不可变的,它的操作速度比 `list` 稍微快一些。在某些情况下,使用元组可能比列表更有效。

4. **应用场景:**
   - 如果你需要一个可以动态改变的数据集,使用 `list`。
   - 如果你有一组常量值,并希望确保它在整个程序中不被修改,使用 `tuple`。

示例:

my_list = [1, 2, 3]
my_tuple = (1, 2, 3)

my_list[0] = 10  # 合法,可以修改列表
# my_tuple[0] = 10  # 不合法,元组是不可变的

# 创建空列表和空元组
empty_list = []
empty_tuple = ()


总的来说,选择使用 `list` 还是 `tuple` 取决于你的需求。
如果你需要一个可以随时修改的数据结构,选择列表;如果你想确保数据的不可变性,选择元组。

77 a = dict(zip((“a”,“b”,“c”,“d”,“e”),(1,2,3,4,5))) 请问a是什么?

在这个例子中,`zip` 函数用于将两个序列打包成一个元组的序列,
然后 `dict` 函数用于将这个元组的序列转换为字典。

a = dict(zip(("a", "b", "c", "d", "e"), (1, 2, 3, 4, 5)))
这将创建一个字典,键是("a", "b", "c", "d", "e")中的元素,对应的值是 (1, 2, 3, 4, 5)中的元素。
因此,`a` 的值将是:
{'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}
这是一个键值对应关系的字典。

78 一行代码生成列表 [1,4,9,16,25,36,49,64,81,100]

可以使用列表推导式一行代码生成该列表:
lst = [x**2 for x in range(1, 11)]
这会生成包含 110 的平方的列表。

79 以下叙述正确的是

A.  continue语句的作用是结束整个循环的执行
B.  只能在循环体和switch语句体内使用break语句
C.  在循环体内使用break语句或者continue语句的作用相同
D.  从多层循环嵌套中退出时, 只能使用goto语句

# 答案:
B. 只能在循环体和switch语句体内使用break语句

80. 读代码

for i in range(5,0,-1):
    print(i)
请在下面写出打印结果
5
4
3
2
1

81. 写结果

x= "foo"
y = 2
print x+y

A.  foo
B.  foo foo
C.  foo 2
D.  2
E.  An exception is thrown

这段代码存在一些错误,因为在 Python 3 中,`print` 是一个函数,而不再是语句。
正确的写法应该是 `print(x + y)`。

如果考虑这个修正,那么正确的选项应该是:
C. `foo 2`

其实也不正确,因为一个是字符串,一个整数,不可相加

82 求结果

kvps = {"1":1,"2":2}
theCopy = kvps
kvps["1"] = 5
sum = kvps["1"] + theCopy ["1"]
print sum

A.  1
B.  2
C.  7
D.  10


以下是逐步的解释:
1. `kvps` 是一个包含键值对 `{"1": 1, "2": 2}` 的字典。
2. `theCopy` 被赋予对同一字典的引用,因此对 `kvps` 的任何更改都会反映在 `theCopy` 中,反之亦然。
3. `kvps["1"]` 被更新为 `5`。
4. `sum` 被计算为 `kvps["1"] + theCopy["1"]`,即 `5 + 5`,结果为 `10`。

因此,最终的输出将是 `10`。

83 python里如何实现tuple和list的转化

在Python中,你可以使用 `list()` 和 `tuple()` 函数来实现 tuplelist 之间的转换。

1. **tuplelist**
    my_tuple = (1, 2, 3)
    my_list = list(my_tuple)

2. **listtuple**
    my_list = [1, 2, 3]
    my_tuple = tuple(my_list)

这两个函数分别接受一个可迭代对象作为参数,并返回一个新的列表或元组。

84 type(1+2L*3.14)的结果是

A.  int
B.  long
C.  float
D.  str

在 Python 2 中,`1` 是整数,`2L` 是长整数,而 `3.14` 是浮点数。
在这种情况下,整数与长整数的混合运算结果是长整数。
因此,`type(1+2L*3.14)` 的结果是 **long**。
选项 B。

值得注意的是,Python 3 已经不再使用 `L` 表示长整数。

85 若k为整型, 下列while循环执行的次数为

k = 1000
while k>1:
    print k
    k = k/2

这个循环会执行到 `k` 的值变为小于等于 1 时停止。
循环的次数取决于将 `k` 除以 2 的次数,直到结果小于等于 1 为止。

初始值 `k = 1000`,每次循环将 `k` 除以 2。
循环次数为将 1000 除以 2 的次数,即 \( \log_2 1000 \approx 9.97 \),向上取整为 10。

因此,这个循环将会执行 10 次。

86 以下何者是不合法的布尔表达式

A.  x in range(6)
B.  3 = a
C.  e>5 and 4==f
D.  (x-6)>5


在这个选项中:
B. `3 = a` 是不合法的布尔表达式。
在Python中,等号 (`=`) 用于赋值,而不是用于比较相等性。
正确的比较相等性的方式是使用 `==`。
因此,这个表达式应该是 `3 == a`。

87 python不支持的数据类型有

A.  char
B.  int
C.  float
D.  list

在 Python 中:
A. `char` 是不支持的数据类型。在 Python 中,字符类型是通过长度为 1 的字符串表示的。
所以,你会使用字符串 `'a'` 而不是 `'char'`。

其他选项 B (`int`)、C (`float`)、D (`list`) 在 Python 中都是支持的数据类型。

88 如何在Python中拷贝一个对象, 并说明他们之间的区别?

在 Python 中,有两种常见的拷贝对象的方式:浅拷贝和深拷贝。

1. **浅拷贝(Shallow Copy):**
   - 使用 `copy` 模块的 `copy()` 函数可以创建一个浅拷贝。
   - 浅拷贝创建了一个新的对象,但是对于对象内部的元素,它们只是引用原始对象中的元素。
   	 如果元素是可变对象,改变原始对象中的这些元素会影响浅拷贝,因为它们引用相同的对象。
   - `copy()` 函数只复制了对象的第一层,而没有递归地复制嵌套对象。
   import copy
   
   original_list = [1, [2, 3], 4]
   shallow_copy = copy.copy(original_list)


2. **深拷贝(Deep Copy):**
   - 使用 `copy` 模块的 `deepcopy()` 函数可以创建一个深拷贝。
   - 深拷贝创建了一个新的对象,并且递归地复制了对象内部的所有元素,包括嵌套的对象。
   	 因此,原始对象和深拷贝是相互独立的,改变一个不会影响另一个。
   import copy
   
   original_list = [1, [2, 3], 4]
   deep_copy = copy.deepcopy(original_list)


总体而言,浅拷贝适用于简单的对象结构,而深拷贝则适用于复杂对象结构或包含嵌套对象的情况。

89 99(10进制)的八进制表示是什么?

99(十进制)的八进制表示是143

9910进制)的八进制表示是:
\[ 99_{10} = 143_8 \]

运算原理:
1. 将十进制数除以8,得到商和余数。
2. 将商再次除以8,得到新的商和余数。
3. 重复这个过程,直到商为0为止。
4. 取余数的序列,从下往上读,即为八进制表示。

90 下列Python语句正确的是

1.  min = x is x<y=y
2.  max = x>y?x:y
3.  if(x>y) print x
4.  while True:pass

正确的是:
4. while True:pass

6. list对象 alist = [{‘name’:‘a’,‘age’:20},{‘name’:‘b’,‘age’:30},{‘name’:‘v’,‘age’:25},]按alist中元素的age由大到小排序。

你可以使用 `sorted` 函数并传递一个自定义的排序规则,如下:

alist = [{'name': 'a', 'age': 20}, {'name': 'b', 'age': 30}, {'name': 'v', 'age': 25}]
sorted_alist = sorted(alist, key=lambda x: x['age'], reverse=True)
print(sorted_alist)

这里,`key=lambda x: x['age']` 表示按照字典中 'age' 键对应的值进行排序,
`reverse=True` 表示按照降序排列。
以上代码执行后,`sorted_alist` 就是按照年龄由大到小排序的列表。

7. 关于Python程序的运行性能方面, 有什么手段能提升性能?

1. **使用适当的数据结构:** 选择适当的数据结构对于程序的性能至关重要。
	比如使用集合(set)来加速成员检查,使用字典(dict)来加速查找。

2. **利用编译器优化:** 使用最新版本的Python,并且尽量使用C扩展和编译过的库,
 	因为这些通常比纯Python代码运行得更快。

3. **使用内置函数和库:** 内置函数和库通常是用C实现的,因此它们比纯Python代码运行得更快。

4. **避免全局变量:** 全局变量的访问速度较慢,尽量使用局部变量。

5. **使用生成器:** 生成器允许你逐步产生结果,而不是一次性生成所有结果。
	这可以减小内存占用,并提高程序性能。

6. **使用多进程或多线程:** Python 中有 GIL(全局解释器锁),它限制了多线程的并行性。
	在某些情况下,使用多进程可能比多线程更有效。

7. **优化算法:** 使用更高效的算法通常比优化代码更有效。选择适当的算法对于程序的性能至关重要。

8. **使用 JIT 编译器:** 一些工具(如 PyPy)提供了即时编译器,可以显著提高运行速度。

9. **使用 Cython:** Cython 允许将 Python 代码转换为 C 代码,从而提高性能。

10. **进行性能分析:** 使用工具进行性能分析,例如 cProfile 或 line_profiler,以找到代码中的瓶颈。

11. **缓存中间结果:** 如果某些计算是昂贵的,可以考虑缓存中间结果,以避免重复计算。

12. **使用 NumPy:** 对于科学计算和数值操作,使用 NumPy 库通常比原生 Python 数组更高效。


请注意,性能优化通常是一种权衡,而不是一种单一的指导原则。在不同情况下,可能需要采用不同的优化策略。

8. Python是如何进行内存管理的? Python的程序会内存泄漏吗?说说有没有什么方面阻止或检测内存泄漏

*** Python使用自动内存管理 *** 即通过垃圾回收机制来管理内存。这意味着开发者无需手动分配或释放内存。Python的垃圾回收器主要通过引用计数和循环垃圾回收两种机制来管理内存。
1. **引用计数:** Python 中的每个对象都有一个引用计数。当对象被引用时,引用计数加一;
	当引用失效时,引用计数减一。当引用计数为零时,对象所占用的内存将被释放。
2. **循环垃圾回收:** 引用计数不能解决循环引用的问题。Python 的垃圾回收器使用循环垃圾回收
	来解决这个问题。通过周期性地检测和解决循环引用,垃圾回收器能够释放被循环引用的对象。

*** 关于内存泄漏:***
虽然 Python 具有自动内存管理,但仍然存在内存泄漏的可能性。
内存泄漏通常发生在开发者忽略了对不再使用的对象进行适当的引用计数或解决循环引用的情况下。

一些常见导致内存泄漏的情形包括:
- **循环引用:** 
	如果两个或多个对象互相引用,而且这些对象不再被程序所使用,垃圾回收器可能无法正确地回收它们。
- **全局变量:** 对象被赋值给全局变量后,它将一直存在于内存中,即使你认为不再需要这个对象。
- **未关闭的资源:** 如果程序使用了文件、网络连接或其他资源,而没有正确地关闭这些资源,可能导致内存泄漏。

为了防止和检测内存泄漏,可以采取以下措施:
- **使用上下文管理器(`with`语句):** 
	确保资源被适当地关闭,即使在发生异常的情况下也能够正确关闭。
- **使用内存分析工具:** 
	工具如 `memory_profiler`、`objgraph` 等可以帮助你分析程序的内存使用情况,找到潜在的内存泄漏。
- **避免循环引用:** 注意对象之间的引用关系,确保不再需要的对象能够被垃圾回收。
- **定期检查代码:** 定期审查代码,确保没有未关闭的资源、不必要的全局变量等。

总的来说,合理的编码习惯、使用工具进行分析和检测,以及定期审查代码,都是防止和检测内存泄漏的有效手段。

9. 详细说说tuple,list,dict的用法, 他们的特点

**Tuple(元组):**
- **定义:** 元组是不可变的序列,用圆括号 `()` 表示。可以包含不同类型的元素,也可以是嵌套的。
- **特点:**
  - 不可变性:一旦创建,元组的元素不可更改,不能增加或删除元素。
  - 有序性:元组中的元素有顺序,可以通过索引访问。
  - 可以包含任意类型的元素,包括其他元组。
  - **示例:**
	  my_tuple = (1, 2, "hello", (3, 4))

**List(列表):**
- **定义:** 列表是可变的序列,用方括号 `[]` 表示。与元组不同,列表的元素可以更改,可以增加或删除元素。
- **特点:**
  - 可变性:可以通过索引进行修改、添加、删除元素。
  - 有序性:列表中的元素有顺序,可以通过索引访问。
  - 可以包含任意类型的元素,包括其他列表。
  - **示例:**
	  my_list = [1, 2, "hello", [3, 4]]


**Dictionary(字典):**
- **定义:** 字典是一种键值对(key-value)的数据结构,用花括号 `{}` 表示。
	每个键(key)必须是唯一的,而值(value)可以是任意类型的对象。
- **特点:**
  - 无序性:字典中的元素没有顺序,不能通过索引访问。
  - 键值对:字典中的元素是由键和值组成的,可以通过键来访问对应的值。
  - 可以包含任意类型的值,包括其他字典。
  
- **示例:**
  my_dict = {"name": "John", "age": 30, "city": "New York"}


**比较:**
- 使用元组当你希望数据是不可变的,不希望被修改。
- 使用列表当你希望动态地修改数据,例如添加或删除元素。
- 使用字典当你需要通过键来访问数据,或者希望数据有一些描述性的标签。

总体来说,选择使用哪种数据类型取决于你的需求。在实际应用中,它们通常会一起使用,根据不同的情况选择不同的数据结构。

10. 一个大小为100G的文件etl_log.txt, 要读取文件中的内容, 写出具体过程代码?

处理大文件时,为了避免一次性将整个文件加载到内存中,通常使用逐行读取的方式。
以下是一个简单的示例代码,演示了如何逐行读取大文件内容:

# 打开文件
file_path = 'etl_log.txt'

with open(file_path, 'r') as file:
    # 逐行读取文件内容
    for line in file:
        # 处理每一行的内容,例如打印或进行其他操作
        print(line.strip())  # strip()用于去除行尾的换行符


这种方式适用于文件较大,不希望一次性加载到内存中的情况。
`open` 函数使用上下文管理器 `with`,它可以确保文件在使用完毕后被正确关闭,释放资源。

如果你需要在读取文件的同时对其进行写操作,你可以使用两个不同的文件句柄,一个用于读取,另一个用于写入。
例如:


input_file_path = 'etl_log.txt'
output_file_path = 'output.txt'

with open(input_file_path, 'r') as rf, open(output_file_path, 'w') as wf:
    for line in rf:
        # 处理每一行的内容
        processed_line = process_line(line)
        
        # 将处理后的内容写入新文件
        wf.write(processed_line + '\n')


在这个例子中,`process_line` 是一个你自定义的处理每一行内容的函数。
这样你就可以在读取大文件时,逐行处理并将结果写入到一个新的文件中。

11. 已知Alist=[1,2,3,1,2,1,3],如何根据Alist得到[1,2,3]

如果你想要从 `Alist` 中获取不重复的元素,并保持它们在原始列表中的顺序,你可以使用以下方法:
Alist = [1, 2, 3, 1, 2, 1, 3]
unique_elements = list(set(Alist))


这里使用 `set` 来去除重复元素,然后再通过 `list()` 转回列表。
需要注意的是,这种方法可能改变元素的顺序,因为集合是无序的。
如果需要保持元素的原始顺序,你可以使用前面提到的 `dict.fromkeys` 方法。

12. 已知stra = ‘wqedsfsdrfweedqwedqw’

1.  如何获取最后两个字符
2.  如何获取第二个和第三个字符

对于字符串 `stra = 'wqedsfsdrfweedqwedqw'`:
1. 获取最后两个字符:
last_two_chars = stra[-2:]

2. 获取第二个和第三个字符:
second_and_third_chars = stra[1:3]

这里使用的切片操作,`[-2:]` 表示从倒数第二个字符到字符串末尾,`[1:3]` 表示从索引 1 到索引 2 的字符。
需要注意,Python 中的切片是左闭右开的,所以第二个字符在切片范围内,但第三个字符不在。

13. 已知Alist = [“a”,“b”,"‘c’],将Alist转化为’a,b,c’的实现过程

已知 `Alist = ["a", "b", "'c']`,如果要将 `Alist` 转化为 `'a,b,c'`,
可以使用字符串的 `join` 方法。这方法需要一个字符串作为分隔符,然后将列表中的元素连接起来。

Alist = ["a", "b", "'c"]
result_str = ','.join([element.strip("'") for element in Alist])
print(result_str)

这里使用了列表推导式和 `strip` 方法,去掉了字符串 `'c'` 中的单引号。
最后,`','.join(...)` 将列表中的元素用逗号连接起来,得到 `'a,b,c'`。

14. 已知ip=‘192.168.0.100’ 代码实现提取各部分并写入列表。

可以使用 `split` 方法和列表解析来提取 IP 地址的各个部分。
例如:
ip = '192.168.0.100'
ip_parts = [int(part) for part in ip.split('.')]
print(ip_parts)


这里,`split('.')` 将 IP 地址按照点号分隔成一个字符串列表,
然后列表解析 `[int(part) for part in ...]` 将每个部分转换为整数。
最后,`ip_parts` 就是包含 IP 地址各个部分的整数列表。

15. python代码如何获取命令行参数?

在 Python 中,你可以使用 `sys.argv` 来获取命令行参数。这需要导入 `sys` 模块。
下面是一个简单的例子:

import sys

# 获取命令行参数
arguments = sys.argv

# 打印所有参数
print("Script name:", arguments[0])
print("Number of arguments:", len(arguments) - 1)
print("Arguments:", arguments[1:])

在上述例子中,sys.argv[0]包含脚本的名称,而sys.argv[1:]包含从命令行传递给脚本的所有其他参数。

16. 写代码

 tupleA = ("a","b","c","d","e")
 tupleB = (1,2,3,4,5)
 RES = {"a":1,"b":2,"c":3,"d":4,"e":5}
 
 写出由tupleA和tupleB得到res的及具体实现过程
 
你可以使用 `zip` 函数将两个元组合并为一个元组对的列表,然后使用字典推导式将其转换为字典。
以下是具体的实现过程:


tupleA = ("a", "b", "c", "d", "e")
tupleB = (1, 2, 3, 4, 5)

# 使用 zip 将两个元组合并为元组对的列表
pairs = zip(tupleA, tupleB)

# 使用字典推导式将元组对的列表转换为字典
res = {key: value for key, value in pairs}

# 打印结果
print(res)


这将输出: {'a': 1, 'b': 2, 'c': 3, 'd': 4, 'e': 5}


这里 zip(tupleA, tupleB) 会生成一个迭代器,它产生元组对 `("a", 1)`, `("b", 2)`,
 然后使用字典推导式 `{key: value for key, value in pairs}` 将其转换为字典。

17. 选出一下表达式表述正确的选项

 A.  {1:0,2:0,3:0}
 B.  {'1':0,'2':0,'3':0}
 C.  {(1,2):0,(4,3):0}
 D.  {[1,2]:0,[4,3]:0}
 E.  {{1,2}:0,{4,3}:0}

正确的选项是:
A. {1:0, 2:0, 3:0}
B. {'1':0, '2':0, '3':0}
C. {(1, 2):0, (4, 3):0}

这些都是合法的字典定义。在 Python 中,字典的键可以是不可变的数据类型,例如整数、字符串和元组。
选项D和E中使用的是可变的列表和集合,因此它们不是合法的字典键。

18. what gets printde() ?

 kvps = {"1":1,'2':2}
 theCopy = kvps.copy()
 kvps["1"] = 5
 sum = kvps["1"] + theCopy["1"]
 print sum
 
 A.  1
 B.  2
 C.  6
 D.  10
 E.  An execption is thrown

 C.  6

19. what gets printde() ?

 numbers = [1,2,3,4]
 numbers.append([5,6,7,8])
 print len(numbers)
 
 A.  4
 B.  5
 C.  8
 D.  12
 E.  An exception is thrown

 B.  5

20. what getsprintde() ?

 names1 = ["Amir","Barry","Chaies","Dao"]
 if "amir" in names1:
    print 1
 else:
    print 2
 
 A.  1
 B.  2
 C.  An exception is thrown

21. what getsprintde() ? Assuming ptrhon version2.x()

 print(type(1/2))
 
 A.  int
 B.  float
 C.  0
 D.  1
 E.  0.5

22. 以下用来管理Python库管理工具的是

 A.  APT
 B.  PIP
 C.  YUM
 D.  MAVEN

 B.  PIP

23. which numbers are printed ()?

 for i in range(2):
     print i
 
 for i in range(4,6):
     print i
 
 A.  2,4,6
 B.  0,1,2,4,5,6
 C.  0,1,4,5
 D.  0,1,4,5,6,7,8,9
 E.  1,2,4,5,6

 C.  0,1,4,5

24. 求结果

 import math
 print (math.floor(5.5))
 
 A.  5
 B.  5.0
 C.  5.5
 D.  6
 E.  6.0


 A.  5

25. 关于Python的内存管理, 下列说法错误的是

 A.  变量不必事先声明
 B.  变量无需先创建和赋值而直接使用
 C.  变量无需指定类型
 D.  可以使用del释放资源

B. 变量无需先创建和赋值而直接使用

26. 下面那个不是Python合法的标识符

 A.  int32
 B.  40xl
 C.  self
 D.  name

B. 40xl

27. 下列哪种说法是错误的

 A.  除字典类型外, 所有标准对象均可用于布尔测试
 B.  空字符串的布尔值是False
 C.  空列表对象的布尔值是False
 D.  值为0的任何数字对象的布尔值是False

 D.  值为0的任何数字对象的布尔值是False

28. 下列表达是的值为True的是

 A.  5+4j >2-3j
 B.  3>2>2
 C.  (3,2)<("a","b")
 D.  " abc" > 'xyz'

B. 3>2>2

29. 关于Python的复数, 下列说法错误的是

 A.  表示复数的语法是 real+imagej
 B.  实部和虚部都是浮点数
 C.  虚部后缀必须是j, 且必须小写
 D.  方法conjugate返回复数的共轭复数

A. 表示复数的语法是 real+imagej
实际上,Python 中表示复数的语法是 `real + imag * j`,其中 `real` 为实部,`imag` 为虚部。

30. 关于字符串下列说法错误的是

 A.  字符应视为长度为1的字符串
 B.  字符串以\0标志字符串的结束
 C.  既可以用单引号, 也可以用双引号创建字符串
 D.  在三引号字符串中可以包含换行回车等特殊字符



B. 字符串以\0标志字符串的结束

在 Python 中,字符串并不是以`\0`标志字符串的结束,而是使用字符串长度信息来确定字符串的结束。
字符串在内部是以字符数组的形式存储的,长度信息会跟踪字符串的实际长度。

31. 以下不能创建一个字典的语句是

 A.  dic1 = {}
 B.  dic2 = {3:5}
 C.  dic3 = {[1,2,3]:"usetc"}
 D.  dic4 = {(1,2,3):"usetc"}

C.  dic3 = {[1,2,3]:"usetc"}

32. python里面如何拷贝一个对象?(赋值,浅拷贝,深拷贝的区别)

在Python中,有三种常见的拷贝方式:赋值、浅拷贝和深拷贝。

1. **赋值(Shallow Copy):**
   original_list = [1, 2, 3]
   copied_list = original_list
   
   这实际上是将新变量指向了原始对象。如果对原始对象进行修改,新变量也会受到影响,因为它们共享相同的内存。

2. **浅拷贝(Shallow Copy):**
   import copy

   original_list = [1, [2, 3], 4]
   copied_list = copy.copy(original_list)


   浅拷贝创建一个新的对象,但它只复制了原始对象中的引用。
   这意味着,如果原始对象包含可变对象(例如列表),它们仍然会被共享。

3. **深拷贝(Deep Copy):**
   import copy

   original_list = [1, [2, 3], 4]
   deep_copied_list = copy.deepcopy(original_list)

   深拷贝创建一个全新的对象,包括原始对象内部的所有对象,而不仅仅是引用。
   这意味着原始对象和深拷贝之间没有共享对象。

**总结:**
- 赋值是对象引用的简单复制,两个变量指向同一块内存。
- 浅拷贝创建一个新对象,但内部对象(如列表)的引用仍然是共享的。
- 深拷贝创建一个完全独立的新对象,包括所有内部对象。

选择使用哪一种方式取决于你的需求。如果原始对象不包含可变对象,赋值或浅拷贝可能足够;
但如果原始对象包含嵌套的可变对象,你可能需要使用深拷贝以确保彻底的复制。

33. 描述在python中的元祖,列表,字典的区别,并且分别写一段定义,添加,删除操作的代码片段。

在Python中,元组(Tuple)、列表(List)和字典(Dictionary)是三种不同的数据结构,它们各自有着不同的特点和用途。

### 元组(Tuple):
- **特点:** 不可变的有序序列,用圆括号表示。
- **定义:**
  my_tuple = (1, 2, 'a', 3.14)


- **添加和删除操作:** 由于元组是不可变的,无法直接进行增删元素的操作。你只能通过创建一个新的元组来包含原始元组的元素。

### 列表(List):
- **特点:** 可变的有序序列,用方括号表示。
- **定义:**
  my_list = [1, 2, 'a', 3.14]


- **添加操作:**
  my_list.append(4)  # 在末尾添加元素
  my_list.insert(2, 'b')  # 在指定位置插入元素

- **删除操作:**
  my_list.remove('a')  # 删除指定值的元素
  del my_list[0]  # 删除指定索引位置的元素

### 字典(Dictionary):
- **特点:** 无序的键值对集合,用花括号表示。
- **定义:**
  my_dict = {'name': 'John', 'age': 25, 'city': 'New York'}

- **添加操作:**
  my_dict['gender'] = 'Male'  # 添加新的键值对

- **删除操作:**
  del my_dict['age']  # 删除指定键的键值对


总体而言:
- 使用元组当你希望数据是不可变的,而且你不需要进行增删操作。
- 使用列表当你需要一个可以修改的有序序列。
- 使用字典当你需要一个无序的键值对集合。

根据具体需求选择适当的数据结构,这有助于提高代码的效率和可读性。

34. 选择结果

names1 = ["Amir", "Barry", "Chales", "Dao"]
names2 = names1
names3 = names1[:]

names2[0] = "Alice"
names3[1] = "Bob"

sum = 0
for ls in (names1, names2, names3):
    if ls[0] == "Alice":
        sum += 1
    if ls[1] == "Bob":
        sum += 10

print(sum)

 A.  11
 B.  12
 C.  21
 D.  22
 E.  23

最终的打印结果会是 `11`,因为 `names2[0]` 被修改为 "Alice",而 `names3[1]` 被修改为 "Bob"

35. 下面程序的输出结果是

 x = True
 y = False
 z = False
 
 if x or y and z:
     print 'yes'
 else:
     print 'no'

在 Python 中,`and` 运算符的优先级高于 `or` 运算符。
因此,`y and z` 部分会先被计算,然后再和 `x` 进行 `or` 运算。

所以,上述代码等效于:

if x or (y and z):
    print('yes')
else:
    print('no')


如果 `x` 为真,整个条件表达式就为真,会执行 `print('yes')`。
如果 `x` 为假,那么需要 `y` 和 `z` 同时为真,整个条件表达式才为真,此时也会执行`print('yes')`。
如果 `x` 为假,而且 `y` 或 `z` 任意一个为假,整个条件表达式就为假,会执行 `print('no')`。

请注意,代码中的 `print` 应该使用括号,因为你的代码看起来更像是 Python 2 的语法,
而在 Python 3 中 `print` 是一个函数。

36. 1 or 2 和1 and 2输出分别是什么? 为什么

在 Python 中,`or` 和 `and` 运算符是短路运算符,它们返回的是第一个为真(对于 `or`)或假(对于 `and`)的值。

- 对于 `1 or 2`,因为 `or` 是逻辑或运算符,它会返回第一个为真的值。在这里,`1` 是真,所以整个表达式的值是 `1`。

- 对于 `1 and 2`,因为 `and` 是逻辑与运算符,它会返回第一个为假的值。在这里,`1` 是真,所以它会继续判断第二个值。因为 `2` 也是真,所以整个表达式的值是 `2`。

所以,结果是:

- `1 or 2` 的值是 `1`
- `1 and 2` 的值是 `2`

37 1 <(22)和1 <22的结果分别是什么, 为什么

在 Python 中,比较运算符的优先级高于布尔运算符。
因此,这两个表达式会先进行比较运算,然后再进行布尔运算。

1. 对于 `1 < (2 == 2)`:
   - 首先,`(2 == 2)` 的结果是 `True`。
   - 然后,`1 < True` 中的 `True` 会被转换为 `1`,
   	因此整个表达式的结果是 `1 < 1`,这是一个假的表达式,结果是 `False`。

2. 对于 `1 < 2 == 2`:
   - 首先,`1 < 2` 为 `True`。
   - 然后,`True == 2`,Python 中 `True` 在参与数值比较时会被当作 `1`,
   	因此这个比较相当于 `1 == 2`,这是一个假的表达式,结果是 `False`。

所以,两个表达式的结果都是 `False`。

38. 如何打乱一个排好序的list对象alist

要打乱一个排好序的列表,你可以使用 `random.shuffle()` 函数。
这个函数会在原地打乱列表的顺序。
以下是一个例子:
import random

alist = [1, 2, 3, 4, 5]
random.shuffle(alist)

print(alist)
这会输出 `alist` 的一个随机排列。请注意,`shuffle` 函数是原地操作,所以不需要重新赋值。

39. 如何查找一个字符串中特定的字符?find和index的差异?

在 Python 中,你可以使用 `find()` 和 `index()` 方法来查找一个字符串中特定字符或子字符串的位置。
这两个方法的用法类似,但有一些关键的区别:

### 使用 `find()` 方法:
str1 = "Hello, World!"

# 查找 'World' 在字符串中的位置
position = str1.find('World')
if position != -1:
    print(f"'World' found at index {position}")
else:
    print("'World' not found")

- 如果找到了子字符串,`find()` 返回第一个匹配的子字符串的起始位置(索引)。
- 如果没有找到子字符串,`find()` 返回 -1### 使用 `index()` 方法:
str1 = "Hello, World!"

# 查找 'World' 在字符串中的位置
position = str1.index('World')
print(f"'World' found at index {position}")


- 如果找到了子字符串,`index()` 返回第一个匹配的子字符串的起始位置(索引)。
- 如果没有找到子字符串,`index()` 抛出一个 `ValueError` 异常。

所以,主要区别在于 `find()` 在未找到时返回 -1,而 `index()` 会抛出异常。
如果你不确定是否会找到子字符串,你可以使用 `find()` 并检查返回值是否为 -1,而不是处理异常。

40. 把aaabbcccd这种形式的字符串压缩成a3b2c3d1这种形式。

你可以使用一个循环来遍历字符串并计算每个字符的重复次数,然后构建压缩后的字符串。
下面是一个示例代码:
def compress_string(s):
    compressed = ""
    count = 1
    for i in range(1, len(s)):
        if s[i] == s[i - 1]:
            count += 1
        else:
            compressed += s[i - 1] + str(count)
            count = 1
            
	# 处理最后一个字符
    compressed += s[-1] + str(count) 
    
    return compressed

# 示例
original_string = "aaabbcccd"
compressed_result = compress_string(original_string)
print(compressed_result)


这段代码遍历输入字符串,计算每个字符的重复次数,并将字符及其重复次数添加到压缩字符串中。
输出将是 `a3b2c3d1`。
请注意,最后一个字符也需要特殊处理。

41 Python 一个数如果恰好等于它的因子之和,这个数就称为"完数"。例如6=1+2+3.编程找出1000以内的所有完数。

以下是一个找出1000以内所有完数的Python程序:

def find_perfect_numbers(limit):
    perfect_numbers = []

    for num in range(2, limit + 1):
        divisors = [1]  # 1 总是一个因子

        for i in range(2, int(num ** 0.5) + 1):
            if num % i == 0:
                divisors.extend([i, num // i])

        if sum(divisors) == num:
            perfect_numbers.append(num)

    return perfect_numbers

limit = 1000
perfect_numbers = find_perfect_numbers(limit)
print("Perfect numbers up to", limit, "are:", perfect_numbers)

### 代码解释
"""
这段代码定义了一个函数 `find_perfect_numbers`,用于找到给定范围内的所有完数(Perfect Number)。
1. **外层循环:** 通过 `for num in range(2, limit + 1)` 遍历给定范围内的每个数。
2. **找因子:** 对于每个数 `num`,通过内层循环 `for i in range(2, int(num ** 0.5) + 1)` 
	找到它的因子。这里采用了一个常见的优化,即只需搜索到 num 的平方根即可找到全部的因子。
3. **计算因子和:** 将所有的因子(包括1但不包括自身)加在一起,得到因子和。
4. **判断完数:** 如果因子和等于原始数 `num`,则它是一个完数,将其添加到 `perfect_numbers` 列表中。
5. **返回结果:** 返回找到的所有完数。

这个算法的思想是通过遍历每个数,找到它的因子,再判断因子和是否等于该数。
找因子的时候,通过遍历到平方根的方式,减少了计算量。
"""

这个程序定义了一个函数 `find_perfect_numbers`,它接受一个上限参数 `limit`,然后找到在给定范围内的所有完数。在主程序中,我们调用该函数并打印结果。输出将包含所有1000以内的完数。

42. 输入一个字符串, 输出该字符串中字符的所有组合.

 例如: 输入字符串"1,2,3", 则输出为1,2,3,12,13,23,123(组合数, 不考虑顺序, 所以1221是等价的)

生成字符串的所有组合是一个经典的组合问题,可以使用递归来解决。
以下是一个Python程序,它能够生成输入字符串的所有组合:

这段代码使用了递归来生成输入字符串的所有组合。以下是对代码的解释:

# current_index` 表示当前处理的字符索引,`current_combination` 是当前已生成的组合,
# `all_combinations` 存储所有组合。
def generate_combinations(input_str, current_index, current_combination, all_combinations):
    # 如果当前索引达到字符串长度,将当前组合添加到所有组合列表中
    if current_index == len(input_str):
        all_combinations.append(current_combination)
        return

    # 包含当前字符在组合中
    generate_combinations(input_str, current_index + 1, current_combination + input_str[current_index], all_combinations)

    # 不包含当前字符在组合中
    generate_combinations(input_str, current_index + 1, current_combination, all_combinations)

def get_all_combinations(input_str):
    all_combinations = []
    generate_combinations(input_str, 0, "", all_combinations)
    return all_combinations

# 示例:
input_string = "123"
combinations = get_all_combinations(input_string)
print(combinations)

"""
1. `generate_combinations` 函数是递归函数,用于生成字符串的所有组合。
	`current_index` 表示当前处理的字符索引,`current_combination` 是当前已生成的组合,
	`all_combinations` 存储所有组合。
2. 在 `generate_combinations` 中,对于当前字符,有两种选择:包含或不包含。
	递归调用会分别考虑这两种情况。
3. `get_all_combinations` 函数初始化空列表 `all_combinations`,然后调用 
	`generate_combinations` 开始递归过程。
5. 示例中,输入字符串是 "123",最后打印所有生成的组合。
"""
在这个程序中,`generate_combinations` 函数是递归的,它根据当前索引,
生成包含或不包含当前字符的组合。主函数 `get_all_combinations` 
调用 `generate_combinations` 并返回所有组合。

请注意,这样的实现可能生成大量的组合,尤其是对于较长的输入字符串。

43. 执行以下代码后, i和n的值为

 int i=10;
 int n=i++%5
 
 
 A.  10, 0
 B.  10, 1
 C.  11, 0
 B.  11, 1

这段代码使用了后缀自增运算符 `i++`,该运算符的行为是先返回原始值,然后再进行自增。
1. `n = i++ % 5;`: 首先 `i` 被赋给 `n`,然后 `i` 自增。因为开始时 `i` 是 10,所以此时 `n` 的值是 10,然后 `i` 变成 11。

因此,执行后的结果是:
- `i` 的值是 11
- `n` 的值是 10

44. 执行以下代码段后,x的值为

 int x=10;
 x+=x-=x-x;
 
 A.  10
 B.  20
 C.  30
 D.  40
 
让我们逐步分析这个代码段:
1. `x -= x - x`: 在这一步中,`x - x` 的结果是 0,所以 `x -= 0` 相当于 `x = x - 0`,
	也就是 `x` 保持不变。
2. `x += x`: 这一步相当于 `x = x + x`,即 `x` 的值加倍。

因此,整个代码段的效果是将 `x` 的值翻倍。开始时 `x` 是 10,所以执行后 `x` 的值将是 20

45. 对于一个非空字符串,判断其是否可以有一个子字符串重复多次组成,字符串只包含小写字母且长度不超过10000

 示例1:
 1.  输入"abab"
 2.  输出True
 3.  样例解释: 输入可由"ab"重复两次组成
 
 示例2:
 1.  输入"abcabcabc"
 2.  输出True
 3.  样例解释: 输入可由"abc"重复三次组成
 
 示例3:
 1.  输入"aba"
 2.  输出False
这是一个常见的字符串问题。可以通过一些巧妙的方法解决。
一个直观的方法是检查字符串是否可以由其子字符串重复多次组成。
下面是一个可能的解决方案:

def repeated_substring_pattern(s):
    length = len(s)
    
    for i in range(1, length // 2 + 1):
        if length % i == 0:
            substring = s[:i]
            if substring * (length // i) == s:
                return True

    return False

#### 解释代码:
"""
这段代码定义了一个函数 `repeated_substring_pattern(s)`,用于判断字符串 `s` 是否可以由其子字符串重复多次组成。
1. `length = len(s)`: 获取字符串 `s` 的长度。
2. `for i in range(1, length // 2 + 1)`: 遍历 `1` 到 `length // 2` 的范围,这是因为重复的子字符串长度不能超过原字符串的一半。
3. `if length % i == 0:`: 检查当前子字符串长度 `i` 是否为字符串长度的因子。
4. `substring = s[:i]`: 提取当前子字符串。
5. `if substring * (length // i) == s:`: 检查当前子字符串重复多次是否等于原字符串。
6. 如果找到符合条件的子字符串,返回 `True`,表示字符串可以由其子字符串重复多次组成。
7. 如果遍历完所有可能的子字符串长度都没有找到符合条件的,返回 `False`,表示字符串不能由其子字符串重复多次组成。
这个算法的时间复杂度是 O(n^2),其中 n 是字符串的长度。
"""

# 示例
print(repeated_substring_pattern("abab"))       # 输出 True
print(repeated_substring_pattern("abcabcabc"))  # 输出 True
print(repeated_substring_pattern("aba"))        # 输出 False


这里的思路是遍历字符串的长度的一半(因为重复的子字符串不能超过长度的一半),检查是否可以通过
某个子字符串重复多次组成。如果找到了符合条件的子字符串,就返回 `True`,否则返回 `False`。

请注意,这只是其中一种解决方案,可能有其他更高效的方法。
  • 9
    点赞
  • 7
    收藏
    觉得还不错? 一键收藏
  • 0
    评论
编译原理龙书答案 完整性高 第二章 2.2 Exercises for Section 2.2 2.2.1 Consider the context-free grammar: S -> S S + | S S * | a Show how the string aa+a* can be generated by this grammar. Construct a parse tree for this string. What language does this grammar generate? Justify your answer. answer S -> S S * -> S S + S * -> a S + S * -> a a + S * -> a a + a * L = {Postfix expression consisting of digits, plus and multiple signs} 2.2.2 What language is generated by the following grammars? In each case justify your answer. S -> 0 S 1 | 0 1 S -> + S S | - S S | a S -> S ( S ) S | ε S -> a S b S | b S a S | ε ⧗ S -> a | S + S | S S | S * | ( S ) answer L = {0n1n | n>=1} L = {Prefix expression consisting of plus and minus signs} L = {Matched brackets of arbitrary arrangement and nesting, includes ε} L = {String has the same amount of a and b, includes ε} ? 2.2.3 Which of the grammars in Exercise 2.2.2 are ambiguous answer No No Yes Yes Yes 2.2.4 Construct unambiguous context-free grammars for each of the following languages. In each case show that your grammar is correct. Arithmetic expressions in postfix notation. Left-associative lists of identifiers separated by commas. Right-associative lists of identifiers separated by commas. Arithmetic expressions of integers and identifiers with the four binary operators +, - , *, /. answer 1. E -> E E op | num 2. list -> list , id | id 3. list -> id , list | id 4. expr -> expr + term | expr - term | term term -> term * factor | term / factor | factor factor -> id | num | (expr) 5. expr -> expr + term | expr - term | term term -> term * unary | term / unary | unary unary -> + factor | - factor factor - > id | num | (expr) 2.2.5 Show that all binary strings generated by the following grammar have values divisible by 3. Hint. Use induction on the number of nodes in a parse tree. num -> 11 | 1001 | num 0 | num num Does the grammar generate all binary strings with values divisible by 3? answer prove any string derived from the grammar can be considered to be a sequence consisting of 11, 1001 and 0, and not prefixed with 0. the sum of this string is: sum = Σn (21 + 20) * 2 n + Σm (23 + 20) * 2m = Σn 3 * 2 n + Σm 9 * 2m It is obviously can divisible by 3. No. Consider string "10101", it is divisible by 3, but cannot derived from the grammar. Question: any general prove? 2.2.6 Construct a context-free grammar for roman numerals. Note: we just consider a subset of roman numerals which is less than 4k. answer wikipedia: Roman_numerals via wikipedia, we can categorize the single noman numerals into 4 groups: I, II, III | I V | V, V I, V II, V III | I X then get the production: digit -> smallDigit | I V | V smallDigit | I X smallDigit -> I | II | III | ε and we can find a simple way to map roman to arabic numerals. For example: XII => X, II => 10 + 2 => 12 CXCIX => C, XC, IX => 100 + 90 + 9 => 199 MDCCCLXXX => M, DCCC, LXXX => 1000 + 800 + 80 => 1880 via the upper two rules, we can derive the production: romanNum -> thousand hundred ten digit thousand -> M | MM | MMM | ε hundred -> smallHundred | C D | D smallHundred | C M smallHundred -> C | CC | CCC | ε ten -> smallTen | X L | L smallTen | X C smallTen -> X | XX | XXX | ε digit -> smallDigit | I V | V smallDigit | I X smallDigit -> I | II | III | ε 2.3 Exercises for Section 2.3 2.3.1 Construct a syntax-directed translation scheme that trans­ lates arithmetic expressions from infix notation into prefix notation in which an operator appears before its operands; e.g. , -xy is the prefix notation for x - y . Give annotated parse trees for the inputs 9-5+2 and 9-5*2.。 answer productions: expr -> expr + term | expr - term | term term -> term * factor | term / factor | factor factor -> digit | (expr) translation schemes: expr -> {print("+")} expr + term | {print("-")} expr - term | term term -> {print("*")} term * factor | {print("/")} term / factor | factor factor -> digit {print(digit)} | (expr) 2.3.2 Construct a syntax-directed translation scheme that trans­ lates arithmetic expressions from postfix notation into infix notation. Give annotated parse trees for the inputs 95-2* and 952*-. answer productions: expr -> expr expr + | expr expr - | expr expr * | expr expr / | digit translation schemes: expr -> expr {print("+")} expr + | expr {print("-")} expr - | {print("(")} expr {print(")*(")} expr {print(")")} * | {print("(")} expr {print(")/(")} expr {print(")")} / | digit {print(digit)} Another reference answer E -> {print("(")} E {print(op)} E {print(")"}} op | digit {print(digit)} 2.3.3 Construct a syntax-directed translation scheme that trans­ lates integers into roman numerals answer assistant function: repeat(sign, times) // repeat('a',2) = 'aa' translation schemes: num -> thousand hundred ten digit { num.roman = thousand.roman || hundred.roman || ten.roman || digit.roman; print(num.roman)} thousand -> low {thousand.roman = repeat('M', low.v)} hundred -> low {hundred.roman = repeat('C', low.v)} | 4 {hundred.roman = 'CD'} | high {hundred.roman = 'D' || repeat('X', high.v - 5)} | 9 {hundred.roman = 'CM'} ten -> low {ten.roman = repeat('X', low.v)} | 4 {ten.roman = 'XL'} | high {ten.roman = 'L' || repeat('X', high.v - 5)} | 9 {ten.roman = 'XC'} digit -> low {digit.roman = repeat('I', low.v)} | 4 {digit.roman = 'IV'} | high {digit.roman = 'V' || repeat('I', high.v - 5)} | 9 {digit.roman = 'IX'} low -> 0 {low.v = 0} | 1 {low.v = 1} | 2 {low.v = 2} | 3 {low.v = 3} high -> 5 {high.v = 5} | 6 {high.v = 6} | 7 {high.v = 7} | 8 {high.v = 8} 2.3.4 Construct a syntax-directed translation scheme that trans­ lates roman numerals into integers. answer productions: romanNum -> thousand hundred ten digit thousand -> M | MM | MMM | ε hundred -> smallHundred | C D | D smallHundred | C M smallHundred -> C | CC | CCC | ε ten -> smallTen | X L | L smallTen | X C smallTen -> X | XX | XXX | ε digit -> smallDigit | I V | V smallDigit | I X smallDigit -> I | II | III | ε translation schemes: romanNum -> thousand hundred ten digit {romanNum.v = thousand.v || hundred.v || ten.v || digit.v; print(romanNun.v)} thousand -> M {thousand.v = 1} | MM {thousand.v = 2} | MMM {thousand.v = 3} | ε {thousand.v = 0} hundred -> smallHundred {hundred.v = smallHundred.v} | C D {hundred.v = smallHundred.v} | D smallHundred {hundred.v = 5 + smallHundred.v} | C M {hundred.v = 9} smallHundred -> C {smallHundred.v = 1} | CC {smallHundred.v = 2} | CCC {smallHundred.v = 3} | ε {hundred.v = 0} ten -> smallTen {ten.v = smallTen.v} | X L {ten.v = 4} | L smallTen {ten.v = 5 + smallTen.v} | X C {ten.v = 9} smallTen -> X {smallTen.v = 1} | XX {smallTen.v = 2} | XXX {smallTen.v = 3} | ε {smallTen.v = 0} digit -> smallDigit {digit.v = smallDigit.v} | I V {digit.v = 4} | V smallDigit {digit.v = 5 + smallDigit.v} | I X {digit.v = 9} smallDigit -> I {smallDigit.v = 1} | II {smallDigit.v = 2} | III {smallDigit.v = 3} | ε {smallDigit.v = 0} 2.3.5 Construct a syntax-directed translation scheme that trans­ lates postfix arithmetic expressions into equivalent prefix arithmetic expressions. answer production: expr -> expr expr op | digit translation scheme: expr -> {print(op)} expr expr op | digit {print(digit)} Exercises for Section 2.4 2.4.1 Construct recursive-descent parsers, starting with the follow­ ing grammars: S -> + S S | - S S | a S -> S ( S ) S | ε S -> 0 S 1 | 0 1 Answer 1) S -> + S S | - S S | a void S(){ switch(lookahead){ case "+": match("+"); S(); S(); break; case "-": match("-"); S(); S(); break; case "a": match("a"); break; default: throw new SyntaxException(); } } void match(Terminal t){ if(lookahead = t){ lookahead = nextTerminal(); }else{ throw new SyntaxException() } } 2) S -> S ( S ) S | ε void S(){ if(lookahead == "("){ S(); match("("); S(); match(")"); S(); } } 3) S -> 0 S 1 | 0 1 void S(){ switch(lookahead){ case "0": match("0"); S(); match("1"); break; case "1": // match(epsilon); break; default: throw new SyntaxException(); } } Exercises for Section 2.6 2.6.1 Extend the lexical analyzer in Section 2.6.5 to remove com­ ments, defined as follows: A comment begins with // and includes all characters until the end of that line. A comment begins with /* and includes all characters through the next occurrence of the character sequence */. 2.6.2 Extend the lexical analyzer in Section 2.6.5 to recognize the relational operators <, =, >. 2.6.3 Extend the lexical analyzer in Section 2.6.5 to recognize float­ ing point numbers such as 2., 3.14, and . 5. Answer Source code: commit 8dd1a9a Code snippet(src/lexer/Lexer.java): public Token scan() throws IOException, SyntaxException{ for(;;peek = (char)stream.read()){ if(peek == ' ' || peek == '\t'){ continue; }else if(peek == '\n'){ line = line + 1; }else{ break; } } // handle comment if(peek == '/'){ peek = (char) stream.read(); if(peek == '/'){ // single line comment for(;;peek = (char)stream.read()){ if(peek == '\n'){ break; } } }else if(peek == '*'){ // block comment char prevPeek = ' '; for(;;prevPeek = peek, peek = (char)stream.read()){ if(prevPeek == '*' && peek == '/'){ break; } } }else{ throw new SyntaxException(); } } // handle relation sign if("".indexOf(peek) > -1){ StringBuffer b = new StringBuffer(); b.append(peek); peek = (char)stream.read(); if(peek == '='){ b.append(peek); } return new Rel(b.toString()); } // handle number, no type sensitive if(Character.isDigit(peek) || peek == '.'){ Boolean isDotExist = false; StringBuffer b = new StringBuffer(); do{ if(peek == '.'){ isDotExist = true; } b.append(peek); peek = (char)stream.read(); }while(isDotExist == true ? Character.isDigit(peek) : Character.isDigit(peek) || peek == '.'); return new Num(new Float(b.toString())); } // handle word if(Character.isLetter(peek)){ StringBuffer b = new StringBuffer(); do{ b.append(peek); peek = (char)stream.read(); }while(Character.isLetterOrDigit(peek)); String s = b.toString(); Word w = words.get(s); if(w == null){ w = new Word(Tag.ID, s); words.put(s, w); } return w; } Token t = new Token(peek); peek = ' '; return t; } Exercises for Section 2.8 2.8.1 For-statements in C and Java have the form: for ( exprl ; expr2 ; expr3 ) stmt The first expression is executed before the loop; it is typically used for initializ­ ing the loop index. The second expression is a test made before each iteration of the loop; the loop is exited if the expression becomes O. The loop itself can be thought of as the statement {stmt expr3 ; }. The third expression is executed at the end of each iteration; it is typically used to increment the loop index. The meaning of the for-statement is similar to expr1 ; while ( expr2 ) {stmt expr3 ; } Define a class For for for-statements, similar to class If in Fig. 2.43. Answer class For extends Stmt{ Expr E1; Expr E2; Expr E3; Stmt S; public For(Expr expr1, Expr expr2, Expr expr3, Stmt stmt){ E1 = expr1; E2 = expr2; E3 = expr3; S = stmt; } public void gen(){ E1.gen(); Label start = new Lable(); Lalel end = new Lable(); emit("ifFalse " + E2.rvalue().toString() + " goto " + end); S.gen(); E3.gen(); emit("goto " + start); emit(end + ":") } } 2.8.2 The programming language C does not have a boolean type. Show how a C compiler might translate an if-statement into three-address code. Answer Replace emit("isFalse " + E.rvalue().toString() + " goto " + after); with emit("ifNotEqual " + E.rvalue().toString() + " 0 goto " + after); or emit("isNotEqualZero " + E.rvalue().toString() + " goto " + after);
第1章 声明和初始化 基本类型 1.1 我该如何决定使用哪种整数类型? 1.2 为什么不精确定义标准类型的大小? 1.3 因为C语言没有精确定义类型的大小,所以我一般都用typedef定义int16和int32。然后根据实际的机器环境把它们定义为int、short、long等类型。这样看来,所有的问题都解决了,是吗? 1.4 新的64位机上的64位类型是什么样的? 指针声明 1.5 这样的声明有什么问题?char*p1,p2;我在使用p2的时候报错了。 1.6 我想声明一个指针,并为它分配一些空间,但却不行。这样的代码有什么问题?char*p;*p=malloc(10); 声明风格 1.7 怎样声明和定义全局变量和函数最好? 1.8 如何在C中实现不透明(抽象)数据类型? 1.9 如何生成“半全局变量”,就是那种只能被部分源文件中的部分函数访问的变量? 存储类型 1.10 同一个静态(static)函数或变量的所有声明都必需包含static存储类型吗? 1.11 extern在函数声明中是什么意思? 1.12 关键字auto到底有什么用途? 类型定义(typedef) 1.13 对于用户定义类型,typedef和#define有什么区别? 1.14 我似乎不能成功定义一个链表。我试过typedefstruct{char*item;NODEPTRnext;}*NODEPTR;但是编译器报了错误信息。难道在C语言中结构不能包含指向自己的指针吗? 1.15 如何定义一对相互引用的结构? 1.16 Struct{ }x1;和typedefstruct{ }x2;这两个声明有什么区别? 1.17 “typedefint(*funcptr)();”是什么意思? const限定词 1.18 我有这样一组声明:typedefchar*charp;constcharpp;为什么是p而不是它指向的字符为const? 1.19 为什么不能像下面这样在初始式和数组维度值中使用const值?constintn=5;inta[n]; 1.20 constchar*p、charconst*p和char*constp有什么区别? 复杂的声明 1.21 怎样建立和理解非常复杂的声明?例如定义一个包含N个指向返回指向字符的指针的函数的指针的数组? 1.22 如何声明返回指向同类型函数的指针的函数?我在设计一个状态机,用函数表示每种状态,每个函数都会返回一个指向下一个状态的函数的指针。可我找不到任何方法来声明这样的函数——感觉我需要一个返回指针的函数,返回的指针指向的又是返回指针的函数……,如此往复,以至无穷。 数组大小 1.23 能否声明和传入数组大小一致的局部数组,或者由其他参数指定大小的参数数组? 1.24 我在一个文件中定义了一个extern数组,然后在另一个文件中使用,为什么sizeof取不到数组的大小? 声明问题 1.25 函数只定义了一次,调用了一次,但编译器提示非法重声明了。 *1.26 main的正确定义是什么?voidmain正确吗? 1.27 我的编译器总在报函数原型不匹配的错误,可我觉得没什么问题。这是为什么? 1.28 文件中的第一个声明就报出奇怪的语法错误,可我看没什么问题。这是为什么? 1.29 为什么我的编译器不允许我定义大数组,如doublearray[256][256]? 命名空间 1.30如何判断哪些标识符可以使用,哪些被保留了? 初始化 1.31 对于没有显式初始化的变量的初始值可以作怎样的假定?如果一个全局变量初始值为“零”,它可否作为空指针或浮点零? 1.32 下面的代码为什么不能编译?intf(){chara[]="Hello,world!";} *1.33 下面的初始化有什么问题?编译器提示“invalidinitializers”或其他信息。char*p=malloc(10); 1.34 chara[]="stringliteral";和char*p="stringliteral";初始化有什么区别?当我向p[i]赋值的时候,我的程序崩溃了。 1.35 chara{[3]}="abc";是否合法? 1.36 我总算弄清楚函数指针的声明方法了,但怎样才能初始化呢? 1.37 能够初始化联合吗? 第2章 结构、联合和枚举 结构声明 2.1 structx1{ };和typedefstruct{ }x2;有什么不同? 2.2 这样的代码为什么不对?structx{ };xthestruct; 2.3 结构可以包含指向自己的指针吗? 2.4 在C语言中用什么方法实现抽象数据类型最好? *2.5 在C语言中是否有模拟继承等面向对象程序设计特性的好方法? 2.6 为什么声明externf(structx*p);给我报了一个晦涩难懂的警告信息? 2.7 我遇到这样声明结构的代码:structname{intnamelen;charnamestr[1];};然后又使用一些内存分配技巧使namestr数组用起来好像有多个元素,namelen记录了元素个数。它是怎样工作的?这样是合法的和可移植的吗? 2.8 我听说结构可以赋给变量也可以对函数传入和传出。为什么K&R1却明确说明不能这样做? 2.9 为什么不能用内建的==和!=操作符比较结构? 2.10结构传递和返回是如何实现的? 2.11 如何向接受结构参数的函数传入常量值?怎样创建无名的中间的常量结构值? 2.12 怎样从/向数据文件读/写结构? 结构填充 2.13 为什么我的编译器在结构中留下了空洞?这导致空间浪费而且无法与外部数据文件进行“二进制”读写。能否关掉填充,或者控制结构域的对齐方式? 2.14 为什么sizeof返回的值大于结构大小的期望值,是不是尾部有填充? 2.15 如何确定域在结构中的字节偏移量? 2.16 怎样在运行时用名字访问结构中的域? 2.17 C语言中有和Pascal的with等价的语句吗? 2.18 既然数组名可以用作数组的基地址,为什么对结构不能这样? 2.19 程序运行正确,但退出时却“coredump”(核心转储)了,怎么回事? 联合 2.20 结构和联合有什么区别? 2.21 有办法初始化联合吗? 2.22 有没有一种自动方法来跟踪联合的哪个域在使用? 枚举 2.23 枚举和一组预处理的#define有什么不同? 2.24 枚举可移植吗? 2.25 有什么显示枚举值符号的容易方法吗? 位域 2.26 一些结构声明中的这些冒号和数字是什么意思? 2.27 为什么人们那么喜欢用显式的掩码和位操作而不直接声明位域? 第3章 表达式 求值顺序 3.1 为什么这样的代码不行?a[i]=i++; 3.2 使用我的编译器,下面的代码inti=7;printf("%d\n",i++*i++);打印出49。不管按什么顺序计算,难道不该是56吗? 3.3 对于代码inti=3;i=i++;不同编译器给出不同的i值,有的为3,有的为4,哪个是正确的? *3.4 有这样一个巧妙的表达式:a^=b^=a^=b;它不需要临时变量就可以交换a和b的值。 3.5 可否用显式括号来强制执行我所需要的计算顺序并控制相关的副作用?就算括号不行,操作符优先级是否能够控制计算顺序呢? 3.6 可是&&和||操作符呢?我看到过类似while((c=getchar())!=EOF&&c!='\n')的代码…… 3.7 是否可以安全地认为,一旦&&和||左边的表达式已经决定了整个表达式的结果,则右边的表达式不会被求值? 3.8 为什么表达式printf("%d%d",f1(),f2());先调用了f2?我觉得逗号表达式应该确保从左到右的求值顺序。 3.9 怎样才能理解复杂表达式并避免写出未定义的表达式?“序列点”是什么? 3.10在a[i]=i++;中,如果不关心a[]的哪一个分量会被写入,这段代码就没有问题,i也的确会增加1,对吗? 3.11 人们总是说i=i++的行为是未定义的。可我刚刚在一个ANSI编译器上尝试过,其结果正如我所期望的。 3.12 我不想学习那些复杂的规则,怎样才能避免这些未定义的求值顺序问题呢? 其他的表达式问题 *3.13 ++i和i++有什么区别? 3.14 如果我不使用表达式的值,那我应该用i++还是++i来做自增呢? 3.15 我要检查一个数是不是在另外两个数之间,为什么if(abc)不行? 3.16 为什么如下的代码不对?inta=1000,b=1000;longintc=a*b; 3.17 为什么下面的代码总是给出0?doubledegC,degF;degC=5.0/9*(degF-32); 3.18 需要根据条件把一个复杂的表达式赋给两个变量中的一个。可以用下面这样的代码吗?((condition)?a:b)=complicated_expression; 3.19 我有些代码包含这样的表达式。a?b=c:d有些编译器可以接受,有些却不能。为什么? 保护规则 3.20 “semanticsof‘’changeinANSIC”的警告是什么意思? 3.21 “无符号保护”和“值保护”规则的区别在哪里? 第4章 指针 基本的指针应用 4.1 指针到底有什么好处? 4.2 我想声明一个指针并为它分配一些空间,但却不行。这些代码有什么问题呢?char*p;*p=malloc(10); 4.3 *p++自增p还是p所指向的变量? 指针操作 4.4 我用指针操作int数组的时候遇到了麻烦。 4.5 我有一个char*型指针碰巧指向一些int型变量,我想跳过它们。为什么((int*)p)++;这样的代码不行? 4.6 为什么不能对void*指针进行算术操作? 4.7 我有些解析外部结构的代码,但是它却崩溃了,显示出了“unalignedaccess”(未对齐的访问)的信息。这是什么意思? 作为函数参数的指针 4.8 我有个函数,它应该接受并初始化一个指针:voidf(int*ip){staticintdummy=5;ip=&dummy;}但是当我如下调用时:int*ip;f(ip);调用者的指针没有任何变化。 4.9 能否用void**通用指针作为参数,使函数模拟按引用传递参数? 4.10 我有一个函数externintf(int*);,它接受指向int型的指针。我怎样用引用方式传入一个常数?调用f(&5);似乎不行。 4.11 C语言可以“按引用传参”吗? 其他指针问题 4.12 我看到了用指针调用函数的不同语法形式。到底怎么回事? 4.13 通用指针类型是什么?当我把函数指针赋向void*类型的时候,编译通不过。 4.14 怎样在整型和指针之间进行转换?能否暂时把整数放入指针变量中,或者相反? *4.15 我怎样把一个int变量转换为char*型?我试了类型转换,但是不行。 第5章 空指针 空指针和空指针常量 5.1 臭名昭著的空指针到底是什么? 5.2 怎样在程序里获得一个空指针? 5.3 用缩写的指针比较“if(p)”检查空指针是否有效?如果空指针的内部表达不是0会怎样? NULL宏 5.4 NULL是什么,它是怎么定义的? 5.5 在使用非零位模式作为空指针的内部表示的机器上,NULL是如何定义的? 5.6 如果NULL定义成#defineNULL((char*)0),不就可以向函数传入不加转换的NULL了吗? 5.7 我的编译器提供的头文件中定义的NULL为0L。为什么? 5.8 NULL可以合法地用作函数指针吗? 5.9 如果NULL和0作为空指针常量是等价的,那我到底该用哪一个呢? 5.10但是如果NULL的值改变了,比如在使用非零内部空指针的机器上,用NULL(而不是0) 不是更好吗? 5.11 我曾经使用过一个编译器,不使用NULL就不能编译。 5.12 我用预处理宏#defineNullptr(type)(type*)0帮助创建正确类型的空指针。 回顾 59 5.13 这有点奇怪:NULL可以确保是0,但空(null)指针却不一定? 5.14 为什么有那么多关于空指针的疑惑?为什么这些问题如此频繁地出现? 5.15 有没有什么简单点儿的办法理解所有这些与空指针有关的东西呢? 5.16 考虑到有关空指针的所有这些困惑,要求它们的内部表示都必须为0不是更简单吗? 5.17 说真的,真有机器用非零空指针吗,或者不同类型用不同的表示? 地址0上到底有什么? 5.18 运行时的整数值0转换为指针以后一定是空指针吗? 5.19 如何访问位于机器地址0处的中断向量?如果我将指针值设为0,编译器可能会自动将它转换为非零的空指针内部表示。 5.20运行时的“nullpointerassignment”错误是什么意思?应该怎样捕捉它? 第6章 数组和指针 数组和指针的基本关系 6.1 我在一个源文件中定义了chara[6],在另一个源文件中声明了externchar*a。为什么不行? 6.2 可是我听说chara[]和char*a是等价的。是这样的吗? 6.3 那么,在C语言中“指针和数组等价”到底是什么意思? 6.4 既然它们这么不同,那为什么作为函数形参的数组和指针声明可以互换呢? 数组不能被赋值 6.5 为什么不能这样向数组赋值?externchar*getpass();charstr[10];str=getpass("Enterpassword:"); 6.6 既然不能向数组赋值,那这段代码为什么可以呢?intf(charstr[]){if(str[0]=='\0')str="none";…} 6.7 如果你不能给它赋值,那么数组如何能成为左值呢? 回顾 6.8 现实地讲,数组和指针的区别是什么? 6.9 有人跟我讲,数组不过是常指针。这样讲准确吗? 6.10 我还是很困惑。到底指针是一种数组,还是数组是一种指针? 6.11 我看到一些“搞笑”的代码,包含5["abcdef"]这样的“表达式”。这为什么是合法的C语言表达式呢? 数组的指针 6.12 既然数组引用会退化为指针,如果array是数组,那么array和&array又有什么区别呢? 6.13 如何声明一个数组的指针? 动态数组分配 6.14 如何在运行时设定数组的大小?怎样才能避免固定大小的数组? 6.15 我如何声明大小和传入的数组一样的局部数组? 6.16 如何动态分配多维数组? 6.17 有个很好的窍门,如果我这样写:intrealarray[10];int*array=&realarray[-1];我就可以把“array”当作下标从1 开始的数组。 函数和多维数组 6.18 当我向一个接受指针的指针的函数传入二维数组的时候,编译器报错了。 6.19 我怎样编写接受编译时宽度未知的二维数组的函数? 6.20 我怎样在函数参数传递时混用静态和动态多维数组? 数组的大小 6.21 当数组是函数的参数时,为什么sizeof不能正确报告数组的大小? 6.22 如何在一个文件中判断声明为extern的数组的大小(例如,数组定义和大小在另一个文件中)?sizeof操作符似乎不行。 6.23 sizeof返回的大小是以字节计算的,怎样才能判断数组中有多少个元素呢? 第7章 内存分配 基本的内存分配问题 7.1 为什么这段代码不行?char*answer;printf("Typesomething:\n");gets(answer);printf("Youtyped\"%s\"\n",answer); 7.2 我的strcat()不行。我试了下面的代码:char*s1="Hello,";char*s2="world!";char*s3=strcat(s1,s2);但是我得到了奇怪的结果。 7.3 但是strcat的文档说它接受两个char*型参数。我怎么知道(空间)分配的事情呢? *7.4 我刚才试了这样的代码:char*p;strcpy(p,"abc");它运行正常。怎么回事?为什么它没有出错? *7.5 一个指针变量分配多少内存? 7.6 我使用fgets将文件的所有行读入一个数组,为什么读入的每一行都是最后一行的内容呢? 7.7 我有个函数,本该返回一个字符串,但当它返回调用者的时候,返回的字符串却是垃圾信息。 为什么? *7.8 那么返回字符串或其他聚集的正确方法是什么呢? 调用malloc 7.9 为什么在调用malloc()时报出了“waring:assignmentofpointerfromintegerlacksacast”? 7.10为什么有些代码小心翼翼地把malloc返回的值转换为分配的指针类型? *7.11 在调用malloc()的时候,错误“不能把void*转换为int*”是什么意思? 7.12 我看到下面这样的代码:char*p=malloc(strlen(s)+1);strcpy(p,s);难道不应该是malloc((strlen(s)+1)*sizeof(char))吗? 7.13 我为malloc写了一个小小的封装函数。它为什么不行? 7.14 我想声明一个指针并向它分配一些内存,但是不行。这样的代码有什么问题?char*p;*p=malloc(10); 7.15 我如何动态分配数组? 7.16 怎样判断还有多少内存? 7.17 malloc(0)是返回空指针还是指向0个字节的指针? 7.18 我听说有的操作系统在程序使用的时候才真正分配malloc申请的内存。这合法吗? 有关malloc的问题 7.19 为什么malloc返回了离谱的指针值?我的确读过问题7.9,而且也在调用之前包含了externvoid*malloc();声明。 7.20 我用一行这样的代码分配一个巨大的数组,用于数值运算:double*array=malloc(256 *256 *sizeof(double));malloc()并没有返回空指针,但是程序运行得有些奇怪,好像改写了某些内存,或者malloc()并没有分配我申请的那么多内存。为什么? 7.21 我的PC机有8兆内存。为什么我只能分配640K左右的内存? 7.22 我的应用程序非常依赖数据结构的节点的动态分配,而malloc/free的代价成了瓶颈。我该怎么做? 7.23 我的程序总是崩溃,显然发生在malloc内部的某个地方。但是我看不出哪里有问题。是malloc有bug吗? 释放内存 7.24 动态分配的内存一旦释放之后就不能再使用,是吧? 7.25 为什么在调用free()之后指针没有变空?使用(赋值、比较)释放之后的指针有多么不安全? 7.26 当我调用malloc()为一个函数的局部指针分配内存时,我还需要用free()显式地释放吗? 7.27 我在分配一些结构,它们包含指向其他动态分配的对象的指针。我在释放结构的时候,还需要释放每一个下级指针吗? 7.28 我必须在程序退出之前释放分配的所有内存吗? 7.29 我有个程序分配了大量的内存,然后又释放了。但是从操作系统看,内存的占用率却并没有变回去。 分配内存块的大小 7.30 free()怎么知道有多少字节需要释放? 7.31 那么我能否查询malloc包,以查明可分配的最大块是多大? 7.32 为什么sizeof不能告诉我它所指的内存块的大小? 其他分配函数 7.33 (像问题6.14中那样)动态分配数组之后,还能改变它的大小吗? 7.34 向realloc()的第一个参数传入空指针合法吗?你为什么要这样做? 7.35 calloc()和malloc()有什么区别?应该用哪一个?利用calloc的零填充功能安全吗?free()可以释放calloc()分配的内存吗,还是需要一个cfree()? 7.36 alloca是什么?为什么不提倡使用它? 第8章 字符和字符串 8.1 为什么strcat(string,'!');不行? 8.2 我想检查一个字符串是否跟某个值匹配。为什么这样不行?if(string=="value") 8.3 如果我可以写chara[]="Hello,world!";那为什么不能写chara[14];a="Hello,world!"; 8.4 为什么我的strcat不行?我试了char*s1="Hello,";char*s2="world!";char*s3 =strcat(s1,s2);可得到的结果很奇怪。 8.5 chara[]="stringliteral";和char*p="stringliteral";初始化有什么区别?当我对p[i]赋值的时候,程序崩溃了。 8.6 我怎么得到与字符相对应的数字(即ASCII或其他字符集下的)值?反过来又该怎么做? 8.7 C语言有类似其他语言的"substr"(提取子串)这样的函数吗? 8.8 我将用户键入的字符串读入数组,然后再显示出来。当用户键入\n这样的序列时,为什么不能正确处理呢? 8.9 我注意到sizeof('a')是2而不是1(即不是sizeof(char)),是不是我的编译器有问题? 8.10 我正开始考虑多语言字符集的问题。是否有必要担心sizeof(char)会被定义为2,以便表达16位的字符集呢? 第9章 布尔表达式和变量 9.1 C语言中布尔值该用什么类型?为什么它不是一个标准类型?我应该用#define或enum定义真值和假值吗? 9.2 既然在C语言中所有的非零值都被看作“真”,那是不是把TRUE定义为1很危险?如果某个内建的函数或关系操作符“返回”不是1的其他值怎么办? 9.3 当p是指针时,if(p)是合法的条件表达式吗? 9.4 我该使用像TRUE和FALSE这样的符号名称还是直接用1和0来作布尔常量? 9.5 我准备使用的一个第三方头文件定义了自己的TRUE和FALSE,它们跟我已经开发的部分不兼容。我该怎么办? 第10章 C预处理器 宏定义 10.1 我想定义一些函数式的宏,例如:#definesquare(x)x*x但它们并不总是正确的。为什么? 10.2 这里有一些的预处理宏,使用它们,我可以写出更像Pascal的C代码。你觉得怎么样? 10.3 怎么写一个交换两个值的通用宏? 10.4 书写多语句宏的最好方法是什么? 10.5 用typdef和预处理宏生成用户定义类型有什么区别? 头文件 10.6 我第一次把一个程序分成多个源文件,我不知道该把什么放到.c文件,把什么放到.h文件。(“.h”到底是什么意思?) 10.7 可以在一个头文件中包含另一头文件吗? 10.8 完整的头文件搜索规则是怎样的? 10.9 我在文件的第一个声明就遇到奇怪的语法错误,但是看上去没什么问题。 10.10 我使用了来自两个不同的第三方库的头文件,它们都定义了相同的宏,如TRUE、FALSE、Min()和Max()等,但是它们的定义相互冲突,而且跟我在自己的头文件中的定义也有冲突。我该怎么办? 10.11 我在编译一个程序,看起来我好像缺少需要的一个或多个头文件。谁能发给我一份? 条件编译 10.12 怎样构造比较字符串的#if预处理表达式? 10.13 sizeof操作符可以用在#if预处理指令中吗? 10.14 我可以像这样在#define行里使用#ifdef来定义两个不同的东西吗? 10.15 对typedef的类型定义有没有类似#ifdef的东西? 10.16 我如何用#if表达式来判断机器是高字节在前还是低字节在前? 10.17 为什么在我用#ifdef关掉的代码行中报出了奇怪的语法错误? 10.18 我拿到了一些代码,里边有太多的#ifdef。我不想使用预处理器把所有的#include和#ifdef都扩展开,有什么办法只保留一种条件的代码呢? 10.19 如何列出所有的预定义宏? 奇异的处理 10.20 我有些旧代码,试图用这样的宏来构造标识符:#definePaste(a,b)a/**/b但是不行了。为什么? 10.21 我有一个旧宏:#defineCTRL(c)('c'&037)不能用了。为什么? 10.22 为什么宏#defineTRACE(n)printf("TRACE:\%d\n",n)报出警告“macroreplacementwithinastringliteral”?它似乎把TRACE(count);扩展成了printf("TRACE:\%d\count",count); 10.23 如何在宏扩展的字符串字面量中使用宏参数? 10.24 我想用ANSI的“字符串化”预处理操作符#将符号常量的值放入消息中,但它总是对宏名称而不是它的值进行字符串化。这是什么原因? 10.25 我想用预处理器做某件事情,但却不知道如何下手。 可变参数列表的宏 10.26 怎样写可变参数宏?如何用预处理器“关掉”具有可变参数的函数调用? 10.27 如何在通用的调试宏中包含__FILE__和__LINE__宏? 第11章 ANSI/ISO标准C 标准 11.1 什么是“ANSIC标准”? 11.2 如何得到一份标准的副本? *11.3 我在哪里可以找到标准的更新? 函数原型 11.4 为什么我的ANSI编译器对用float声明的参数会警告类型不匹配? 11.5 能否混用旧式的和新型的函数语法? *11.6 为什么下述声明报出了一个奇怪的警告信息“StructXdeclaredinsideparameterlist”?externintf(structx*p); 11.7 有个问题一直困扰着我,它是由这一行printf("%d",n);导致的,因为n是个longint型。难道ANSI的函数原型不能检查这种函数的参数不匹配问题吗? 11.8 我听说必须在调用printf之前包含stdio.h。为什么? const限定词 11.9 为什么不能在初始化和数组维度中使用const值?例如constintn=5;inta[n]; 11.10“constchar*p”、“charconst*p”和“char*constp”有何区别? 11.11 为什么不能向接受constchar**的函数传入char**? 11.12 我这样声明:typedefchar*charp;constcharpp;为什么是p而不是它所指向的字符为const? main()函数的使用 11.13 能否通过将main声明为void来关掉“main没有返回值”的警告? 11.14 main()的第3个参数envp是怎么回事? 11.15 我觉得把main()声明为void也不会失败,因为我调用了exit()而不是return,况且我的操作系统也忽略了程序的退出/返回状态。 *11.16 那么到底会出什么问题?真的有什么系统不支持voidmain()吗? 11.17 为什么以前流行的那些C语言书总是使用voidmain()? 11.18 在main()中调用exit(status)和返回同样的status真的等价吗? 预处理功能 11.19 我试图用ANSI“字符串化”预处理操作符'#'向信息中插入符号常量的值,但它字符串化的总是宏的名字而不是它的值。为什么? 11.20 警告信息“warning:macroreplacementwithinastringliteral”是什么意思? 11.21 为什么在我用#ifdef去掉的代码里出现了奇怪的语法错误? 11.22 #pragma是什么,有什么用? 11.23 “#pragmaonce”什么意思?我在一些头文件中看到了它。 其他的ANSIC问题 11.24 chara[3]="abc";合法吗?它是什么意思? 11.25 既然对数组的引用会退化为指针,那么,如果array是数组,array和&array之间有什么区别呢? 11.26 为什么我不能对void*指针进行算术运算? 11.27 memcpy()和memmove()有什么区别? 11.28 malloc(0)有什么用?返回一个空指针还是指向0字节的指针? 11.29 为什么ANSI标准规定了外部标识符的长度和大小写限制? 11.30 noalias是怎么回事?在它身上发生了什么? 老的或非标准的编译器 11.31 为什么我的编译器对最简单的测试程序都报出了一大堆的语法错误?对这段代码的第一行就报错了:main(intargc.char**argv){return0;} 11.32 为什么有些ASNI/ISO标准库函数未定义?我明明使用的就是ANSI编译器。 11.33 谁有可以在旧的C程序和ANSIC之间相互转换的工具,或者自动生成原型的工具? 11.34 为什么声称兼容ANSI的编译器不能编译这些代码?我知道这些代码是ANSI的,因为gcc可以编译。 兼容性 11.35 人们好像有些在意实现定义的(implementation-defined)、不确定的(unspecified)和未定义的(undefined)行为的区别。它们的区别到底在哪里? *11.36 一个程序“合法(legal)”、“有效(valid)”或“符合标准的”(conforming)到底是什么意思? 11.37 我很吃惊,ANSI标准竟然有那么多未定义的东西。标准的唯一任务不就是让这些东西标准化吗? 11.38 有人说i=i++的行为是未定义的,但是我刚在一个兼容ANSI的编译器上测试,得到了我希望的结果。它真的是未定义的吗? 第12章 标准输入输出库 基本输入输出 12.1 这样的代码有什么问题?charc;while((c=getchar())!=EOF) 12.2 我有个读取直到EOF的简单程序,但是我如何才能在键盘上输入那个“\EOF”呢?我看stdio.h中定义的EOF是-1,是不是说我该输入-1? 12.3 为什么这些代码把最后一行复制了两遍?while(!feof(infp)){fgets(buf,MAXLINE,infp);fputs(buf,outfp);} 12.4 我用fgets将文件的每行内容读入指针数组。为什么结果所有的行都是最后一行的内容呢? 12.5 我的程序的屏幕提示和中间输出有时没有在屏幕上显示,尤其是当我用管道通过另一个程序输出的时候。为什么? 12.6 我怎样才能不等待回车键而一次输入一个字符? printf格式 12.7 如何在printf的格式串中输出一个'%'字符?我试过\%,但是不行。 12.8 为什么这么写不对?longintn=123456;printf("%d\n",n); 12.9 有人告诉我不能在printf中使用%lf。为什么printf()用%f输出double型,而scanf却用%lf呢? *12.10 对于size_t那样的类型定义,当我不知道它到底是long还是其他类型的时候,我应该使用什么样的printf格式呢? 12.11 如何用printf实现可变的域宽度?就是说,我想在运行时确定宽度而不是使用%8d? 12.12 如何输出在千位上用逗号隔开的数字?货币格式的数字呢? 12.13 为什么scanf("%d",i)调用不行? *12.14 为什么chars[30];scamf("%s",s);不用&也可以?我原以为传给scanf的每个变量都要带&。 12.15 为什么这些代码不行?doubled;scanf("%f",&d); 12.16 为什么这段代码不行?shortints;scanf("%d",&s); 12.17 怎样在scanf格式串中指定可变的宽度? 12.18 怎样从特定格式的数据文件中读取数据?怎样读入10个float而不用使用包含10次%f的奇怪格式?如何将一行的任意多个域读入一个数组中? scanf问题 12.19 我像这样用"%d\n"调用scanf从键盘读取数字:intn;scanf("%d\n",&n);printf("youtyped%d\n",n);好像要多输入一行才返回。为什么? 12.20 我用scanf和%d读取一个数字,然后再用gets()读取字符串,但是编译器好像跳过了gets()调用! 12.21 我发现如果坚持检查返回值以确保用户输入的是我期待的数值,则scanf的使用会安全很多。但有的时候好像会陷入无限循环。为什么? 12.22 为什么大家都说不要使用scanf?那我该用什么来代替呢? 其他stdio函数 12.23 我怎样才知道对于任意的sprintf调用需要多大的目标缓冲区?怎样才能避免sprintf目标缓冲区溢出? 12.24 sprintf的返回值是什么?是int还是char*? 12.25 为什么大家都说不要使用gets? 12.26 我觉得我应该在一长串的printf调用之后检查errno,以确定是否有失败的调用。为什么当我将输出重定向到文件的时候会输出奇怪的“printffailed:Notatypewriter”信息? 12.27 fgetops/fsetops和ftell/fseek之间有什么区别?fgetops和fsetops到底有什么用处? 12.28 如何清除用户的多余输入,以防止在下一个提示符下读入?用fflush(stdin)可以吗? 打开和操作文件 12.29 我写了一个函数用来打开文件:myfopen(char*filename,FILE*fp){fp=fopen(filename,"r");}可我这样调用的时候:FILE*infp;myfopen("filename.dat",infp);,infp指针并没有正确设置。为什么? 12.30 连一个最简单的fopen调用都不成功!这个调用有什么问题?FILE*fp=fopen(filename,'r'); 12.31 为什么我不能用完整路径名打开一个文件?这个调用总是失败:fopen("c:\newdir\file.dat","r"); 12.32 我想用fopen模式"r+"打开一个文件,读出一个字符串,修改之后再写入,从而就地更新一个文件。可是这样不行。为什么? 12.33 如何在文件中间插入或删除一行(一条记录)? 12.34 怎样从打开的流中恢复文件名? 重定向stdin和stdout 12.35 怎样在程序里把stdin或stdout重定向到文件? 12.36 一旦使用freopen之后,怎样才能恢复原来的stdout(或stdin)? 12.37 如何判断标准输入或输出是否经过了重定向,即是否在命令行上使用了“”或“”? 12.38 我想写个像"more"那样的程序。怎样才能在stdin被重定向之后再回到交互键盘? *12.39 怎样同时向两个地方输出,如同时输出到屏幕和文件? “二进制”输入输出 12.40 我希望按字节在内存和文件之间直接读写数字,而不像fprintf和fscanf进行格式化。我该怎么办? 12.41 怎样正确地读取二进制文件?有时看到0x0a和0x0d容易混淆,而且如果数据中包含0x1a的话,我好像会提前遇到EOF。 12.42 我在写一个二进制文件的“过滤器”,但是stdin和stdout却被作为文本流打开了。怎样才能把它们的模式改为二进制? 12.43 文本和二进制输入输出有什么区别? 12.44 如何在数据文件中读写结构? 12.45 怎样编写符合旧的二进制数据格式的代码? 第13章 库函数 字符串函数 13.1 怎样把数字转为字符串(与atoi相反)?有itoa函数吗? 13.2 为什么strncpy不能总在目标串放上终止符'\0'? 13.3 C语言有类似于其他语言中的“substr”(取出子串)的例程吗? 13.4 怎样把一个字符串中所有字符转换成大写或小写? 13.5 为什么有些版本的toupper对大写字符会有奇怪的反应?为什么有的代码在调用toupper前先调用islower? 13.6 怎样将字符串分割成用空白分隔的字段?怎样实现类似main处理argc和argv的过程? 13.7 哪里可以找到处理正则表达式或通配符匹配的代码? 排序 13.8 我想用strcmp作为比较函数,调用qsort对一个字符串数组排序,但是不行。为什么? 13.9 我想用qsort()对一个结构数组排序。我的比较函数接受结构指针,但是编译器认为这个函数不是qsort需要的类型。我要怎样转换这个函数指针才能避免这样的警告? 13.10 怎样对一个链表排序? 13.11 怎样对大于内存容量的数据排序? 日期和时间 13.12 怎样在C程序中取得当前日期或时间? 13.13 我知道库函数localtime可以把time_t转换成结构structtm,而ctime可以把time_t转换成为可打印的字符串。怎样才能进行反向操作,把structtm或一个字符串转换成time_t? 13.14 怎样在日期上加n天?怎样取得两个日期的时间间隔? 随机数 13.15 怎么生成一个随机数? 13.16 怎样获得某一范围内的随机整数? 13.17 每次执行程序,rand都返回相同的数字序列。为什么? 13.18 我需要随机的真/假值,所以我就直接用rand()%2,可是我得到交替的0,1,0,1,0…。为什么? 164 13.19 如何获取根本不重复的随机数? 13.20 怎样产生正态分布或高斯分布的随机数? 13.21 我在移植一个程序,里边调用了一个函数drand48 ,而我的库又没有这个。这是个什么函数? 其他库函数 13.22 exit(status)是否真的跟从main函数返回status等价? 13.23 memcpy和memmove有什么区别? 13.24 我想移植这个旧程序。为什么报出这些“undefinedexternal”错误:index?、rindex?、bcopy?、bcmp?、bzero?? 13.25 我不断得到库函数未定义错误,但是我已经包含了所有用到的头文件了。 13.26 虽然我在连接时明确地指定了正确的函数库,我还是得到库函数未定义错误。 13.27 一个最简单的程序,不过在一个窗口里打印出“Hello,World”,为什么会编译出巨大的可执行代码(数百K)?我该少包含一些头文件吗? 13.28 连接器报告_end未定义代表什么意思? *13.29 我的编译器提示printf未定义!这怎么可能? 第14章 浮点运算 14.1 一个float变量赋值为3.1时,为什么printf输出的值为3.0999999? 14.2 我想计算一些平方根,我把程序简化成这样:main(){printf("%f\h",sqrt(144.));可得到的结果却是疯狂的数字。为什么? 14.3 我想做一些简单的三角函数运算,也包含了math.h,但连接器总是提示sin、cos这样的函数未定义。为什么? 14.4 我的浮点数计算程序表现得很奇怪,在不同的机器上给出了不同的结果。为什么? 14.5 有什么好的方法来检查浮点数在“足够接近”情况下的相等? 14.6 怎样取整? 14.7 为什么C语言不提供乘幂的操作符? 14.8 为什么我机器上的math.h没有预定义常量M_PI? 14.9 怎样将变量置为IEEENaN(“NotaNumber”)或检测变量是否为NaN及其他特殊值? 14.10 如何简洁地处理浮点异常? 14.11 在C语言中如何很好地实现复数? 14.12 我要寻找一些实现以下功能的程序源代码:快速傅立叶变换(FFT)、矩阵算术(乘法、求逆等函数)、复数算术。 14.13 TurboC的程序崩溃,显示错误为“floatingpointformatsnotlinked”(浮点格式未连接)。我还缺点儿什么呢? 第15章 可变参数列表 调用变参函数 15.1 为什么调用printf前必须要包含stdio.h? 15.2 为什么%f可以在printf参数中同时表示float和double?它们难道不是不同类型吗? 15.3 我遇到了一个令人十分受挫的问题,后来发现是这行代码造成的:printf("%d",n);原来n是longint型。难道ANSI的函数原型不就是用来防止这类的参数类型不匹配吗? 15.4 怎样写一个接受可变参数的函数? 15.5 怎样写一个函数,像printf那样接受一个格式串和可变参数,然后再把参数传给printf去完成大部分工作? 15.6 怎样写类似scanf的函数,再把参数传给scanf去完成大部分工作? 15.7 我用的是ANSI前的编译器,没有stdarg.h文件。我该怎么办? 提取可变参数 15.8 怎样知道实际上有多少个参数传入函数? 15.9 为什么编译器不允许我定义一个没有固定参数项的可变参数函数? 15.10 我有个接受float型的变参函数,为什么va_arg(argp,float)却不行? 15.11 为什么va_arg不能得到类型为函数指针的参数? 困难的问题 15.12 怎样实现一个可变参数函数,它把参数再传给另一个可变参数函数? 15.13 怎样调用一个在运行时才构建参数列表的函数? 第16 章奇怪的问题 16.1 为什么这个循环只执行了一次?for(i=start;iend;i++);{printf("%d\n",i);} *16.2 遇到不可理解的不合理语法错误,似乎大段的程序没有编译。 *16.3 为什么过程调用不起作用?编译器似乎直接跳过去了。 16.4 程序在执行之前就崩溃了!(用调试器单步跟踪,在main函数的第一个语句之前就死了。)为什么? 16.5 程序执行正确,但退出时在main函数的最后一个语句之后崩溃了。为什么会这样? 16.6 程序在一台机器上运行完美,但在另一台上却得到怪异的结果。更奇怪的是,增加或去除调试的打印语句,就改变了症状…… 16.7 为什么下面的代码会崩溃?char*p="hello,world!";p[0]='H'; 16.8 我有些代码是用来解析外部结构的,但它却崩溃了,报了“unalignedaccess”(未对齐的访问)错误。这是什么意思? 16.9 “Segmentationviolation”、“Buserror”和“Generalprotectionfault”是什么意思? 第17章 风格 17.1 什么是C最好的代码布局风格? 17.2 如何在源文件中合理分配函数? 17.3 用if(!strcmp(s1,s2))比较两个字符串是否相等是个好风格吗? 17.4 为什么有的人用if(0==x)而不是if(x==0)? 17.5 为什么有些代码在每次调用printf前增加了类型转换(void)? 17.6 既然NULL和0都是空指针常量,我到底该用哪一个? 17.7 是该用TRUE和FALSE这样的符号名称还是直接用1和0来作布尔常量? 17.8 什么是“匈牙利表示法”(HungarianNotation)?是否值得一试? 17.9 哪里可以找到“IndianHillStyleGuide”及其他编码标准? 17.10 有人说goto是邪恶的,永远都不该用它。这是否太极端了? 17.11 人们总是说良好的风格很重要,但当他们使用良好的风格写出清晰易读的程序后,又发现程序的效率似乎降低了。既然效率那么重要,是否可以为了效率牺牲一些风格和可读性呢? 第18章 工具和资源 18.1 能否列一个常用工具列表? 18.2 怎样捕获棘手的malloc问题? 18.3 有什么免费或便宜的编译器可以使用? lint 18.4 刚刚输入完一个程序,但它表现得很奇怪。你能发现有什么错误的地方吗? 18.5 如何关掉lint对每个malloc调用报出的“warning:possiblepointeralignmentproblem”警告消息? 18.6 哪里可以找到兼容ANSI的lint? 18.7 难道ANSI函数原型说明没有使lint过时吗? 资源 18.8 网上有哪些C语言的教程或其他资源? *18.9 哪里可以找到好的源代码实例,以供研究和学习? 18.10 有什么好的学习C语言的书?有哪些高级的书和参考? 18.11 哪里能找到K&R的练习答案? 18.12 哪里能找到NumericalRecipesinC、Plauger的TheStandardCLibrary或Kernighan和Pike的TheUNIXProgrammingEnviroment等书里的源码? 18.13 哪里可以找到标准C函数库的源代码? 18.14 是否有一个在线的C参考指南? 18.15 我需要分析和评估表达式的代码。从哪里可以找到? 18.16 哪里可以找到C的BNF或YACC语法? *18.17 谁有C编译器的测试套件? *18.18 哪里有一些有用的源代码片段和例子的收集? *18.19 我需要执行多精度算术的代码。 18.20 在哪里和怎样取得这些可自由发布的程序? 第19章 系统依赖 键盘和屏幕I/O 19.1 怎样从键盘直接读入字符而不用等回车键?怎样防止字符输入时的回显? 19.2 怎样知道有未读的字符(如果有,有多少)?另外,如何在没有字符的时候不阻塞读入? 19.3 怎样显示一个在原地更新自己的百分比或“旋转棒”的进度指示器? 19.4 怎样清屏?怎样反色输出?怎样把光标移动到指定的x,y位置? 19.5 怎样读入方向键、功能键? 其他I/O 19.6 怎样读入鼠标输入? 19.7 怎样做串口(“comm”)的输入输出? 19.8 怎样直接输出到打印机? 19.9 怎样发送转义字符序列控制终端或其他设备? 19.10 怎样做图形? *19.11 怎样显示GIF和JPEG图像? 文件和目录 19.12 怎样检验一个文件是否存在?如果请求的输入文件不存在,我希望向用户提出警告。 19.13 怎样在读入文件前,知道文件大小? *19.14 怎样得到文件的修改日期和时间? 19.15 怎样原地缩短一个文件而不用清除或重写? 19.16 怎样在文件中插入或删除一行(或一条记录)? 19.17 怎样从一个打开的流或文件描述符得到文件名? 19.18 怎样删除一个文件? *19.19 怎样复制文件? 19.20 为什么用了详尽的路径还不能打开文件?下面的代码会返回错误。Fopen("c:\newdir\file.dat","r") *19.21 fopen不让我打开文件"$HOME/.profile"和"~~/.myrcfile"。 *19.22 怎样制止MS-DOS下令人恐怖的“Abort,Retry,Ignore?”信息? 19.23 遇到“Toomanyopenfiles(打开文件太多)”的错误,怎样增加同时打开文件的允许数目? 19.24 如何得到磁盘的可用空间大小? 19.25 怎样在C语言中读入目录? 19.26 如何创建目录?如何删除目录(及其内容)? 访问原始内存 19.27 怎样找出系统还有多少内存可用? 19.28 怎样分配大于64K的数组或结构? 19.29 错误信息“DGROUPdataallocationexceeds64K(DGROUP数据分配内存超过64K)”什么意思?我应该怎么做?我以为使用了大内存模型,就可以使用大于64K的数据! 19.30 怎样访问位于某特定地址的内存(内存映射的设备或图形显示内存)? 19.31 如何访问机器地址0处的中断向量?如果将指针设为0,编译器可能把它转成一个非零的内部空指针值。 “系统”命令 19.32 怎样在一个C程序中调用另一个程序(独立可执行的程序或系统命令)? 19.33 如果运行时才知道要执行的命令的参数(文件名等),应该如何调用system? 19.34 在MS-DOS上如何得到system返回的准确错误状态? 19.35 怎样调用另一个程序或命令,然后获取它的输出? 进程环境 19.36 怎样才能发现程序自己的执行文件的全路径? 19.37 怎样找出和执行文件在同一目录的配置文件? 19.38 进程如何改变它的调用者的环境变量? 19.39 如何打开命令行给出的文件并解析选项? 19.40 exit(status)是否真的和从main函数返回同样的status等价? 19.41 怎样读入一个对象文件并跳跃到其中的函数? 其他系统相关的操作 19.42 怎样以小于1秒的精度延时或计算用户响应时间? 19.43 怎样捕获或忽略control-C这样的键盘中断? 19.44 怎样简洁地处理浮点异常? 19.45 怎样使用socket?如何联网?如何写客户/服务器程序? *19.46 怎样调用BIOS函数?如何写ISR?如何创建TSR? *19.47 什么是“near”和“far”指针? 回顾 19.48 我不能使用这些非标准、依赖系统的函数,程序需要兼容ANSI! 19.49 为什么这些内容没有在C语言中进行标准化?任何现实程序都会用到这些东西。 第20章 杂项 20.1 怎样从函数返回多个值? 20.2 用什么数据结构存储文本行最好?我开始用固定大小的char型数组的数组,但是有很多局限。 20.3 怎样打开命令行提到的文件并处理参数? 20.4 如何正确地使用errno? 20.5 怎样写数据文件,使之可以在不同字大小、字节顺序或浮点格式的机器上读入? 20.6 怎样用char*指针指向的函数名调用函数? 位和字节 20.7 如何操作各个位? 20.8 怎样实现位数组或集合? 234 20.9 怎样判断机器的字节顺序是高字节在前还是低字节在前? *20.10 怎样调换字节? 20.11 怎样将整数转换到二进制或十六进制? 20.12 可以使用二进制常数(类似0b101010这样的东西)吗?printf有二进制的格式说明符吗? 效率 20.13 用什么方法计算整数中为1的位的个数最高效? 20.14 怎样提高程序的效率? 20.15 指针真的比数组快吗?函数调用会拖慢程序多少?++i比i=i+1快吗? 20.16 用移位操作符替换乘法和除法是否有价值? *20.17 人们说编译器优化得很好,我们不再需要为速度而写汇编了,但我的编译器连用移位代替i/=2都做不到。 *20.18 怎样不用临时变量而交换两个值? switch语句 20.19 switch语句和if/else链哪个更高效? 20.20 是否有根据字符串进行条件切换的方法? 20.21 是否有使用非常量case行标的方法(如范围或任意的表达式)? 各种语言功能 20.22 return语句外层的括号是否真的可选择? 20.23 为什么C语言的注释不能嵌套?怎样注释掉含有注释的代码?引号包含的字符串内的注释是否合法? 20.24 为什么C语言的操作符不设计得更全面一些?好像还缺了一些^^、&&=和-=这样的操作符。 *20.25 C语言有循环移位操作符吗? *20.26 C是个伟大的语言还是别的什么东西?哪个其他语言可以写出像a+++++b这样的代码? 20.27 如果赋值操作符是:=,是不是就不容易意外地写出if(a=b)了? 20.28 C语言有和Pascal的with等价的语句吗? 20.29 为什么C语言没有嵌套函数? *20.30 assert是什么?如何使用? 其他语言 20.31 怎样从C中调用FORTRAN(C++、BASIC、Pascal、Ada、LISP)的函数?反之如何? 20.32 有什么程序可以将Pascal或FORTRAN(或LISP、Ada、awk、“老”C)程序转化为C程序? 20.33 C++是C的超集吗?可以用C++编译器来编译C代码吗? 20.34 我需要用到“近似”的strcmp例程,比较两个字符串的近似度,并不需要完全一样。有什么好办法? 20.35 什么是散列法? 20.36 如何生成正态或高斯分布的随机数? 20.37 如何知道某个日期是星期几? 20.38 (year%4==0)是否足以判断闰年?2000年是闰年吗? 20.39 为什么tm结构中的tm_sec的范围是0到61,暗示一分钟有62秒? 琐事 20.40 一个难题:怎样写一个输出自己源代码的程序? 20.41 什么是“达夫设备”(Duff’sDevice)? 20.42 下届国际C语言混乱代码竞赛(InternationalObfuscatedCCodeContest,IOCCC)什么时候进行?哪里可以找到当前和以前的获胜代码? 20.43 K&R1提到的关键字entry是什么? 20.44 C的名字从何而来? 20.45 “char”如何发音? *20.46 “lvalue”和“rvalue”代表什么意思? 20.47 哪里可以获得本书的在线版? 术语表 参考文献
基于c#CP3平面网严密平差数据处理 using System; using System.Collections.Generic; using System.Collections;//使用动态数组需要添加的语句 using System.ComponentModel; using System.Data; using System.Drawing; using System.Linq; using System.Text; using System.Windows.Forms; using System.IO; using ParaSet; using CSAccelerateMatrix; using Trans; using CSUsualFun; namespace FreeStaAdj { public partial class Form1 : Form { static string Path = "C:\\Documents and Settings\\HB\\桌面\\春儿数据-120907"; string[] KPName;//存储已知点点号 double[,] KPXYZ;//存储已知点三维坐标 string[] StaKName;//存储测站点点号 double[,] StaKXYZ;//存储测站点已知三维坐标 public class StaData { public string StaName;//测站名 public int Num;//观测的CPIII点数 public string[] CP3Name = new string[12];//CPIII自由测站学习点数一般不会超过12个,此处也可用动态数组存储 public double[,] LVS = new double[12, 3]; }; ArrayList StaList = new ArrayList(); public struct DLVS//用于存储方差分量估计各次的方差估值 { public double DL,DV,DS; }; //以下为默认先验平差参数 double PriLm=0.5,PriSa=1.0,PriSb=1.0;//水平方向中误差,测距固定误差和比例误差 int DMaxNum = 10;//最大方差分量估计次数 double DLimitValue = 0.01;//方差分量估计默认收敛阀值 bool IsD=true;//true表示进行方差分量估计 bool SP = true;//true表示A+B*S bool Ma = true;//true表示验后单位权中误差 double LVRatio = 2.0;//水平方向 和 天顶距 权的比值 string AdjMethord = "普通";//三维平差方法 const double Pe = 0.0174532925199433;//Math.PI/180.0,便于后面简化运算 public Form1() { InitializeComponent(); } public double Cal_DRatio(double a,double b,double c) { double x, y; if (a>=b) { x=a; y =b; } else { x = b; y=a; } if (x<c) { x=c; } if (y>c) { y=c; } return x / y;//三个数中的最大值:最小值 } public double atan(double y, double x)//Math.Atan2的返回值区间(-PI,PI] { double p = Math.Atan2(y, x); if (p<0) { return p+2*Math.PI; } else { return p; } } public double SubRad(double y, double x)//返回两个弧度(角度)的差值 { double p =y-x; if (p < 0) { return p + 6.28318530717959; } else { return p; } } public void GetXYZ(string PName,ref double x,ref double y,ref double z,string[] KPName, double[,] KPXYZ) { for (int i=0;i<KPName.Length;i++) { if (PName==KPName[i]) { x=KPXYZ[i,0]; y=KPXYZ[i,1]; z=KPXYZ[i,2]; break; } } } public double GetlL(double Ljk,double z0,double ajk) { double ljk =Ljk+z0-ajk; if (ljk>3.14)//出现359 59 59的情况 { ljk -= 2 * Math.PI; } return ljk * 206264.8062471; } public void Cal_LVk(double[] LV, double[,] BL, double[] lL, double[] X, int n) { for (int i = 0; i < n; i++) { LV[i] = -1.0 + BL[i, 0] * X[2] + BL[i, 1] * X[3] - lL[i]; } } public void Cal_LV(double[] LV,double[,] BL, double[] lL,double[] X,int n) { for(int i=0;i<n;i++) { LV[i] = -1.0 + BL[i, 0] * X[1]+BL[i,1] * X[2]-lL[i]; } } public void Cal_SVk(double[] SV, double[,] BS, double[] lS, double[] X, int n) { for (int i = 0; i < n; i++) { SV[i] = BS[i, 0] * X[2] + BS[i, 1] * X[3] + BS[i, 2] * X[4] - lS[i]; } } public void Cal_SVab(double[] SV, double[,] BS, double[] lS, double[] X, int n) { for (int i = 0; i < n; i++) { SV[i] = -( X[4]+BS[i, 3] * X[5])+BS[i, 0] * X[1] + BS[i, 1] * X[2] + BS[i, 2] * X[3] - lS[i]; } } public void Cal_SV(double[] SV, double[,] BS, double[] lS, double[] X, int n) { for (int i = 0; i < n; i++) { SV[i] = BS[i, 0] * X[1] + BS[i, 1] * X[2] + BS[i, 2] * X[3] - lS[i]; } } public void Cal_VVk(double[] VV, double[,] BV, double[] lV, double[] X, int n) { for (int i = 0; i < n; i++) { VV[i] = BV[i, 0] * X[1]+BV[i, 1] * X[2] + BV[i, 2] * X[3] + BV[i, 3] * X[4] - lV[i]; } } public void Cal_VVabk(double[] VV, double[,] BV, double[] lV, double[] X, int n) { for (int i = 0; i < n; i++) { VV[i] = BV[i, 0] * X[1] + BV[i, 1] * X[2] + BV[i, 2] * X[3] + BV[i, 3] * X[6] - lV[i]; } } public void Cal_VV(double[] VV, double[,] BV, double[] lV, double[] X, int n) { for (int i = 0; i < n; i++) { VV[i] = BV[i, 0] * X[1] + BV[i, 1] * X[2] + BV[i, 2] * X[3] - lV[i]; } } public double Cal_LD0(double[] LV,int n,double[] InvN,double[] NL,int r) { double v2 = 0; for (int i = 0; i < n;i++ ) { v2 +=LV[i]*LV[i]; } AccelerateMatrix A = new AccelerateMatrix(); return v2/(n-A.Tr_TwoPSMatrix(InvN, NL, r)); } public double Cal_VD0(double[] VV, double LVRatio, int n, double[] InvN, double[] NV, int r) { double v2 = 0; for (int i = 0; i < n; i++) { v2 += VV[i] * VV[i] / LVRatio; } AccelerateMatrix A = new AccelerateMatrix(); return v2 / (n - A.Tr_TwoPSMatrix(InvN, NV, r)); } public double Cal_SD0(double[] SV, double[] PS, int n, double[] InvN, double[] NS, int r) { double v2 = 0; for (int i = 0; i < n; i++) { v2 += SV[i] * SV[i]*PS[i]; } AccelerateMatrix A = new AccelerateMatrix(); return v2 / (n - A.Tr_TwoPSMatrix(InvN, NS, r)); } public void FillNVk(double[] NV, double[] WV, int Index, StaData D,//Index表示第几个测站 double LVRatio, string[] KPName, double[,] KPXYZ, double[,] StaAppXYZ, double[,] BV, double[] lV) { //此函数考虑大气折光影响 //先计算天顶距的初始权,水平方向权的默认值为1 double PV = 1.0 / LVRatio; //用天顶距观测值填充NV和WV矩阵 double Stax = StaAppXYZ[Index, 0]; double Stay = StaAppXYZ[Index, 1]; double Staz = StaAppXYZ[Index, 2]; double x = 0, y = 0, z = 0, dx, dy, dz, a, b, c,d, Sij, S2, lv; for (int i = 0; i < D.Num; i++) { GetXYZ(D.CP3Name[i], ref x, ref y, ref z, KPName, KPXYZ); dx = x - Stax; dy = y - Stay; dz = z - Staz; Sij = Math.Pow(dx, 2) + Math.Pow(dy, 2); S2 = Sij + Math.Pow(dz, 2); Sij = Math.Sqrt(Sij); lv = 206264.8062471 * (D.LVS[i, 1] * Pe - Math.Atan2(Sij, dz));//常数项 a = 206.2648062471 * dz / (Sij * S2); b = -a * dy; a *= -dx; c = 206.2648062471 * Sij / S2; d = 206.2648062471 * Sij / 6371;//大气折光系数k在误差方程式中的系数 BV[i, 0] = d;//未知数顺序k,X,Y,Z BV[i, 1] = a; BV[i, 2] = b; BV[i, 3] = c; lV[i] = lv; NV[2] += PV * d * d; NV[4] += PV * d * a; NV[7] += PV * d * b; NV[11] +=PV * d * c; NV[5] += PV * a * a; NV[8] += PV * a * b; NV[9] += PV * b * b; NV[12] += PV * a * c; NV[13] += PV * b * c; NV[14] += PV * c * c; lv *= PV; WV[1] += d * lv; WV[2] += a * lv; WV[3] += b * lv; WV[4] += c * lv; } } public void FillNVabk(double[] NV, double[] WV, int Index, StaData D,//Index表示第几个测站 double LVRatio, string[] KPName, double[,] KPXYZ, double[,] StaAppXYZ, double[,] BV, double[] lV) { //此函数考虑大气折光影响,并估计距离的 固定误差 和 比例误差 //先计算天顶距的初始权 double PV = 1.0 / LVRatio; //用天顶距观测值填充NV和WV矩阵 double Stax = StaAppXYZ[Index, 0]; double Stay = StaAppXYZ[Index, 1]; double Staz = StaAppXYZ[Index, 2]; double x = 0, y = 0, z = 0, dx, dy, dz, a, b, c,d, Sij, S2, lv; for (int i = 0; i < D.Num; i++) { GetXYZ(D.CP3Name[i], ref x, ref y, ref z, KPName, KPXYZ); dx = x - Stax; dy = y - Stay; dz = z - Staz; Sij = Math.Pow(dx, 2) + Math.Pow(dy, 2); S2 = Sij + Math.Pow(dz, 2); Sij = Math.Sqrt(Sij); lv = 206264.8062471 * (D.LVS[i, 1] * Pe - Math.Atan2(Sij, dz));//常数项 a = 206.2648062471 * dz / (Sij * S2); b = -a * dy; a *= -dx; c = 206.2648062471 * Sij / S2; d = 206.2648062471 * Sij / 6371; BV[i, 0] = a; BV[i, 1] = b; BV[i, 2] = c; BV[i, 3] = d; lV[i] = lv; NV[2] += PV * a * a; NV[4] += PV * a * b; NV[5] += PV * b * b; NV[7] += PV * a * c; NV[8] += PV * b * c; NV[9] += PV * c * c; NV[22] += PV * a * d; NV[23] += PV * b * d; NV[24] += PV * c * d; NV[27] += PV * d * d; lv *= PV; WV[1] += a * lv; WV[2] += b * lv; WV[3] += c * lv; WV[6] += d * lv; } } public void FillNV(double[] NV, double[] WV, int Index, StaData D,//Index表示第几个测站 double LVRatio,string[] KPName, double[,] KPXYZ, double[,] StaAppXYZ, double[,] BV, double[] lV) { //此函数不考虑大气折光影响 //先计算天顶距的初始权 double PV = 1.0 / LVRatio; //用天顶距观测值填充NV和WV矩阵 double Stax = StaAppXYZ[Index, 0]; double Stay = StaAppXYZ[Index, 1]; double Staz = StaAppXYZ[Index, 2]; double x=0,y=0,z=0,dx,dy,dz,a,b,c, Sij,S2, lv;//dx,dy方向的坐标差,近似距离,水平方向常数项 for (int i = 0; i < D.Num; i++) { GetXYZ(D.CP3Name[i], ref x, ref y, ref z, KPName, KPXYZ); dx = x - Stax; dy = y - Stay; dz = z - Staz; Sij = Math.Pow(dx, 2) + Math.Pow(dy, 2); S2 = Sij + Math.Pow(dz, 2); Sij = Math.Sqrt(Sij); lv = 206264.8062471*(D.LVS[i, 1] * Pe - Math.Atan2(Sij, dz));//常数项 a = 206.2648062471 * dz / (Sij * S2); b = -a *dy; a *= -dx; c = 206.2648062471 * Sij / S2; BV[i, 0] = a; BV[i, 1] = b; BV[i, 2] = c; lV[i] =lv; NV[2] += PV * a * a; NV[4] += PV * a * b; NV[5] += PV * b * b; NV[7] += PV * a * c; NV[8] += PV * b * c; NV[9] += PV * c * c; lv *= PV; WV[1] += a * lv; WV[2] += b * lv; WV[3] += c * lv; } } public void FillNLk(double[] NL, double[] WL, int Index, StaData D,//Index表示第几个测站 ref double z0, string[] KPName, double[,] KPXYZ, double[,] StaAppXYZ, double[,] BL, double[] lL) { //z0定向角未知数 //用方向观测值填充NL和WL矩阵 double Stax = StaAppXYZ[Index, 0];//测站近似坐标 double Stay = StaAppXYZ[Index, 1]; double Staz = StaAppXYZ[Index, 2]; //先计算测站的定向角未知数 double x = 0, y = 0, z = 0; z0 = 0;//初始化为0 for (int i = 0; i < D.Num; i++) { GetXYZ(D.CP3Name[i], ref x, ref y, ref z, KPName, KPXYZ); z0 += SubRad(atan(y - Stay, x - Stax), D.LVS[i, 0] * Pe); } z0 /= D.Num;//求平均值,单位为弧度[0,2*PI] double dx, dy, a, b, S02, ljk;//dx,dy方向的坐标差,近似距离,水平方向常数项 for (int i = 0; i < D.Num; i++) { GetXYZ(D.CP3Name[i], ref x, ref y, ref z, KPName, KPXYZ); dx = x - Stax; dy = y - Stay; S02 = Math.Pow(dx, 2) + Math.Pow(dy, 2); ljk = GetlL(D.LVS[i, 0] * Pe, z0, atan(dy, dx)); a = 206.2648062471 * dy / S02; b = -206.2648062471 * dx / S02; BL[i, 0] = a; BL[i, 1] = b; lL[i] = ljk; //水平方向观测值的权为1.0 NL[0] += 1.0; NL[3] -= a; NL[5] += a * a; NL[6] -= b; NL[8] += a * b; NL[9] += b * b; WL[0] -= ljk; WL[2] += a * ljk; WL[3] += b * ljk; } } public void FillNL(double[] NL, double[] WL, int Index, StaData D,//Index表示第几个测站 ref double z0,string[] KPName, double[,] KPXYZ, double[,] StaAppXYZ, double[,] BL,double[] lL) { //z0定向角未知数 //用方向观测值填充NL和WL矩阵 double Stax = StaAppXYZ[Index, 0];//测站近似坐标 double Stay = StaAppXYZ[Index, 1]; double Staz = StaAppXYZ[Index, 2]; //先计算测站的定向角未知数 double x = 0, y = 0, z = 0; z0 = 0;//初始化为0 for (int i = 0; i < D.Num; i++) { GetXYZ(D.CP3Name[i], ref x, ref y, ref z, KPName, KPXYZ); z0+=SubRad(atan(y-Stay,x-Stax),D.LVS[i,0]*Pe); } z0 /= D.Num;//求平均值,单位为弧度[0,2*PI] double dx,dy,a, b,S02, ljk;//dx,dy方向的坐标差,近似距离,水平方向常数项 for (int i = 0; i < D.Num; i++) { GetXYZ(D.CP3Name[i], ref x, ref y, ref z, KPName, KPXYZ); dx =x-Stax; dy =y-Stay; S02 =Math.Pow(dx, 2) + Math.Pow(dy, 2); ljk=GetlL(D.LVS[i, 0] * Pe,z0,atan(dy, dx)); a = 206.2648062471 * dy / S02; b = -206.2648062471 * dx / S02; BL[i, 0] = a; BL[i, 1] = b; lL[i] = ljk; //水平方向观测值的权为1.0 NL[0] += 1.0; NL[1] -= a; NL[2] += a * a; NL[3] -= b; NL[4] += a * b; NL[5] += b * b; WL[0] -= ljk; WL[1] += a * ljk; WL[2] += b * ljk; } } public void PrintResultk( double[,] AppXYZ, double[,] AdjXYZ, double[] StaZ, double[] StaAppZ, double[] K, ArrayList StaList, ArrayList D0List, bool IsD0, string[] StaKName, double[,] StaKXYZ) { richTextBox1.Clear(); int i, j; //先输出定向角未知数计算结果 richTextBox1.Text += "测站 定向角近似值(°′″) 定向角平差值(°′″) 改正数(″)\n"; for (i = 0; i < StaList.Count; i++) { StaData D = (StaData)StaList[i];//获取各测站的数据,需要强制类型转换获取StaList中的数据 richTextBox1.Text += string.Format("{0,4}", D.StaName) + string.Format("{0,17:f4}", StaAppZ[i]) + string.Format("{0,23:f4}", StaZ[i]) + string.Format("{0,17:f2}", (StaZ[i] - StaAppZ[i]) * 10000) + "\n"; } richTextBox1.Text += "\n-------------------------------------------------\n\n"; //输出大气折光系数估值 richTextBox1.Text += "测站 大气折光系数估值\n"; for (i = 0; i < StaList.Count; i++) { StaData D = (StaData)StaList[i];//获取各测站的数据,需要强制类型转换获取StaList中的数据 richTextBox1.Text += string.Format("{0,4}", D.StaName) + string.Format("{0,14:f2}", K[i]) +"\n"; } richTextBox1.Text += "\n-------------------------------------------------\n\n"; richTextBox1.Text += " 既有坐标(0) | 近似坐标(1) | 平差坐标(2) | 坐标较差[(1)-(0)] | 坐标较差[(2)-(0)]\n"; richTextBox1.Text += "点名 | X(m) Y(m) Z(m) | X(m) Y(m) Z(m) | X(m) Y(m) Z(m) | dx(mm) dy(mm) dz(mm) | dx(mm) dy(mm) dz(mm)\n"; for (i = 0; i < StaKName.Length; i++) { richTextBox1.Text += string.Format("{0,4}", StaKName[i]) + " | " + string.Format("{0:0.0000}", StaKXYZ[i, 0]) + " " + string.Format("{0:0.0000}", StaKXYZ[i, 1]) + " " + string.Format("{0:0.0000}", StaKXYZ[i, 2]) + " | "; for (j = 0; j < StaList.Count; j++) { StaData D = (StaData)StaList[j]; if (D.StaName == StaKName[i]) { richTextBox1.Text += string.Format("{0:0.0000}", AppXYZ[j, 0]) + " " + string.Format("{0:0.0000}", AppXYZ[j, 1]) + " " + string.Format("{0:0.0000}", AppXYZ[j, 2]) + " | "; richTextBox1.Text += string.Format("{0:0.0000}", AdjXYZ[j, 0]) + " " + string.Format("{0:0.0000}", AdjXYZ[j, 1]) + " " + string.Format("{0:0.0000}", AdjXYZ[j, 2]) + " |"; richTextBox1.Text += string.Format("{0,6:f1}", (AppXYZ[j, 0] - StaKXYZ[i, 0]) * 1000) + string.Format("{0,7:f1}", (AppXYZ[j, 1] - StaKXYZ[i, 1]) * 1000) + string.Format("{0,7:f1}", (AppXYZ[j, 2] - StaKXYZ[i, 2]) * 1000) + " |"; richTextBox1.Text += string.Format("{0,6:f1}", (AdjXYZ[j, 0] - StaKXYZ[i, 0]) * 1000) + string.Format("{0,7:f1}", (AdjXYZ[j, 1] - StaKXYZ[i, 1]) * 1000) + string.Format("{0,7:f1}", (AdjXYZ[j, 2] - StaKXYZ[i, 2]) * 1000) + "\n"; break; } } } //以下输出方差分量估计信息 richTextBox1.Text += "\n-------------------------------------------------------------\n"; if (IsD0) { for (i = 0; i < D0List.Count; i++) { StaData D = (StaData)StaList[i]; richTextBox1.Text += "测站 " + D.StaName + " 各次方差分量估计 各类观测值(L V S)的方差估值如下:\n"; richTextBox1.Text += "第*次 水平方向L 天顶距V 斜距S\n"; ArrayList Di = (ArrayList)D0List[i]; for (j = 0; j < Di.Count; j++) { DLVS dvs = (DLVS)Di[j]; richTextBox1.Text += string.Format("{0,3}", j + 1); richTextBox1.Text += string.Format("{0,12:f3}", dvs.DL); richTextBox1.Text += string.Format("{0,12:f3}", dvs.DV); richTextBox1.Text += string.Format("{0,12:f3}", dvs.DS) + "\n"; } richTextBox1.Text += "\n------------------------------------------------------\n"; } } else { richTextBox1.Text += "未进行方差分量估计!\n"; } } public void PrintResultabk( double[,] AppXYZ, double[,] AdjXYZ, double[] StaZ, double[] StaAppZ, double[,] AB, double[] K, ArrayList StaList, ArrayList D0List, bool IsD0, string[] StaKName, double[,] StaKXYZ) { richTextBox1.Clear(); int i, j; //先输出定向角未知数计算结果 richTextBox1.Text += "测站 定向角近似值(°′″) 定向角平差值(°′″) 改正数(″)\n"; for (i = 0; i < StaList.Count; i++) { StaData D = (StaData)StaList[i];//获取各测站的数据,需要强制类型转换获取StaList中的数据 richTextBox1.Text += string.Format("{0,4}", D.StaName) + string.Format("{0,17:f4}", StaAppZ[i]) + string.Format("{0,23:f4}", StaZ[i]) + string.Format("{0,17:f2}", (StaZ[i] - StaAppZ[i]) * 10000) + "\n"; } richTextBox1.Text += "\n-------------------------------------------------\n\n"; //输出 固定误差 和 比例误差 richTextBox1.Text += "测站 斜距固定误差(mm) 斜距比例误差(mm/km)\n"; for (i = 0; i < StaList.Count; i++) { StaData D = (StaData)StaList[i];//获取各测站的数据,需要强制类型转换获取StaList中的数据 richTextBox1.Text += string.Format("{0,4}", D.StaName) + string.Format("{0,13:f2}", AB[i, 0]) + string.Format("{0,19:f2}", AB[i, 1]) + "\n"; } richTextBox1.Text += "\n-------------------------------------------------\n\n"; //输出大气折光系数估值 richTextBox1.Text += "测站 大气折光系数估值\n"; for (i = 0; i < StaList.Count; i++) { StaData D = (StaData)StaList[i];//获取各测站的数据,需要强制类型转换获取StaList中的数据 richTextBox1.Text += string.Format("{0,4}", D.StaName) + string.Format("{0,14:f2}", K[i]) + "\n"; } richTextBox1.Text += "\n-------------------------------------------------\n\n"; richTextBox1.Text += " 既有坐标(0) | 近似坐标(1) | 平差坐标(2) | 坐标较差[(1)-(0)] | 坐标较差[(2)-(0)]\n"; richTextBox1.Text += "点名 | X(m) Y(m) Z(m) | X(m) Y(m) Z(m) | X(m) Y(m) Z(m) | dx(mm) dy(mm) dz(mm) | dx(mm) dy(mm) dz(mm)\n"; for (i = 0; i < StaKName.Length; i++) { richTextBox1.Text += string.Format("{0,4}", StaKName[i]) + " | " + string.Format("{0:0.0000}", StaKXYZ[i, 0]) + " " + string.Format("{0:0.0000}", StaKXYZ[i, 1]) + " " + string.Format("{0:0.0000}", StaKXYZ[i, 2]) + " | "; for (j = 0; j < StaList.Count; j++) { StaData D = (StaData)StaList[j]; if (D.StaName == StaKName[i]) { richTextBox1.Text += string.Format("{0:0.0000}", AppXYZ[j, 0]) + " " + string.Format("{0:0.0000}", AppXYZ[j, 1]) + " " + string.Format("{0:0.0000}", AppXYZ[j, 2]) + " | "; richTextBox1.Text += string.Format("{0:0.0000}", AdjXYZ[j, 0]) + " " + string.Format("{0:0.0000}", AdjXYZ[j, 1]) + " " + string.Format("{0:0.0000}", AdjXYZ[j, 2]) + " |"; richTextBox1.Text += string.Format("{0,6:f1}", (AppXYZ[j, 0] - StaKXYZ[i, 0]) * 1000) + string.Format("{0,7:f1}", (AppXYZ[j, 1] - StaKXYZ[i, 1]) * 1000) + string.Format("{0,7:f1}", (AppXYZ[j, 2] - StaKXYZ[i, 2]) * 1000) + " |"; richTextBox1.Text += string.Format("{0,6:f1}", (AdjXYZ[j, 0] - StaKXYZ[i, 0]) * 1000) + string.Format("{0,7:f1}", (AdjXYZ[j, 1] - StaKXYZ[i, 1]) * 1000) + string.Format("{0,7:f1}", (AdjXYZ[j, 2] - StaKXYZ[i, 2]) * 1000) + "\n"; break; } } } //以下输出方差分量估计信息 richTextBox1.Text += "\n-------------------------------------------------------------\n"; if (IsD0) { for (i = 0; i < D0List.Count; i++) { StaData D = (StaData)StaList[i]; richTextBox1.Text += "测站 " + D.StaName + " 各次方差分量估计 各类观测值(L V S)的方差估值如下:\n"; richTextBox1.Text += "第*次 水平方向L 天顶距V 斜距S\n"; ArrayList Di = (ArrayList)D0List[i]; for (j = 0; j < Di.Count; j++) { DLVS dvs = (DLVS)Di[j]; richTextBox1.Text += string.Format("{0,3}", j + 1); richTextBox1.Text += string.Format("{0,12:f3}", dvs.DL); richTextBox1.Text += string.Format("{0,12:f3}", dvs.DV); richTextBox1.Text += string.Format("{0,12:f3}", dvs.DS) + "\n"; } richTextBox1.Text += "\n------------------------------------------------------\n"; } } else { richTextBox1.Text += "未进行方差分量估计!\n"; } } public void PrintResultab( double[,] AppXYZ, double[,] AdjXYZ, double[] StaZ, double[] StaAppZ,double[,] AB, ArrayList StaList, ArrayList D0List, bool IsD0, string[] StaKName, double[,] StaKXYZ) { richTextBox1.Clear(); int i, j; //先输出定向角未知数计算结果 richTextBox1.Text += "测站 定向角近似值(°′″) 定向角平差值(°′″) 改正数(″)\n"; for (i = 0; i < StaList.Count; i++) { StaData D = (StaData)StaList[i];//获取各测站的数据,需要强制类型转换获取StaList中的数据 richTextBox1.Text += string.Format("{0,4}", D.StaName) + string.Format("{0,17:f4}", StaAppZ[i]) + string.Format("{0,23:f4}", StaZ[i]) + string.Format("{0,17:f2}", (StaZ[i] - StaAppZ[i]) * 10000) + "\n"; } richTextBox1.Text += "\n-------------------------------------------------\n\n"; //输出 固定误差 和 比例误差 richTextBox1.Text += "测站 斜距固定误差(mm) 斜距比例误差(mm/km)\n"; for (i = 0; i < StaList.Count; i++) { StaData D = (StaData)StaList[i];//获取各测站的数据,需要强制类型转换获取StaList中的数据 richTextBox1.Text += string.Format("{0,4}", D.StaName) + string.Format("{0,13:f2}", AB[i,0]) + string.Format("{0,19:f2}", AB[i,1]) +"\n"; } richTextBox1.Text += "\n-------------------------------------------------\n\n"; richTextBox1.Text += " 既有坐标(0) | 近似坐标(1) | 平差坐标(2) | 坐标较差[(1)-(0)] | 坐标较差[(2)-(0)]\n"; richTextBox1.Text += "点名 | X(m) Y(m) Z(m) | X(m) Y(m) Z(m) | X(m) Y(m) Z(m) | dx(mm) dy(mm) dz(mm) | dx(mm) dy(mm) dz(mm)\n"; for (i = 0; i < StaKName.Length; i++) { richTextBox1.Text += string.Format("{0,4}", StaKName[i]) + " | " + string.Format("{0:0.0000}", StaKXYZ[i, 0]) + " " + string.Format("{0:0.0000}", StaKXYZ[i, 1]) + " " + string.Format("{0:0.0000}", StaKXYZ[i, 2]) + " | "; for (j = 0; j < StaList.Count; j++) { StaData D = (StaData)StaList[j]; if (D.StaName == StaKName[i]) { richTextBox1.Text += string.Format("{0:0.0000}", AppXYZ[j, 0]) + " " + string.Format("{0:0.0000}", AppXYZ[j, 1]) + " " + string.Format("{0:0.0000}", AppXYZ[j, 2]) + " | "; richTextBox1.Text += string.Format("{0:0.0000}", AdjXYZ[j, 0]) + " " + string.Format("{0:0.0000}", AdjXYZ[j, 1]) + " " + string.Format("{0:0.0000}", AdjXYZ[j, 2]) + " |"; richTextBox1.Text += string.Format("{0,6:f1}", (AppXYZ[j, 0] - StaKXYZ[i, 0]) * 1000) + string.Format("{0,7:f1}", (AppXYZ[j, 1] - StaKXYZ[i, 1]) * 1000) + string.Format("{0,7:f1}", (AppXYZ[j, 2] - StaKXYZ[i, 2]) * 1000) + " |"; richTextBox1.Text += string.Format("{0,6:f1}", (AdjXYZ[j, 0] - StaKXYZ[i, 0]) * 1000) + string.Format("{0,7:f1}", (AdjXYZ[j, 1] - StaKXYZ[i, 1]) * 1000) + string.Format("{0,7:f1}", (AdjXYZ[j, 2] - StaKXYZ[i, 2]) * 1000) + "\n"; break; } } } //以下输出方差分量估计信息 richTextBox1.Text += "\n-------------------------------------------------------------\n"; if (IsD0) { for (i = 0; i < D0List.Count; i++) { StaData D = (StaData)StaList[i]; richTextBox1.Text += "测站 " + D.StaName + " 各次方差分量估计 各类观测值(L V S)的方差估值如下:\n"; richTextBox1.Text += "第*次 水平方向L 天顶距V 斜距S\n"; ArrayList Di = (ArrayList)D0List[i]; for (j = 0; j < Di.Count; j++) { DLVS dvs = (DLVS)Di[j]; richTextBox1.Text += string.Format("{0,3}", j + 1); richTextBox1.Text += string.Format("{0,12:f3}", dvs.DL); richTextBox1.Text += string.Format("{0,12:f3}", dvs.DV); richTextBox1.Text += string.Format("{0,12:f3}", dvs.DS) + "\n"; } richTextBox1.Text += "\n------------------------------------------------------\n"; } } else { richTextBox1.Text += "未进行方差分量估计!\n"; } } public void PrintResult( double[,] AppXYZ, double[,] AdjXYZ, double[] StaZ, double[] StaAppZ, ArrayList StaList,ArrayList D0List,bool IsD0, string[] StaKName, double[,] StaKXYZ) { richTextBox1.Clear(); int i,j; //先输出定向角未知数计算结果 richTextBox1.Text += "测站 定向角近似值(°′″) 定向角平差值(°′″) 改正数(″)\n"; for (i = 0; i < StaList.Count; i++) { StaData D = (StaData)StaList[i];//获取各测站的数据,需要强制类型转换获取StaList中的数据 richTextBox1.Text += string.Format("{0,4}",D.StaName) + string.Format("{0,17:f4}",StaAppZ[i])+ string.Format("{0,23:f4}",StaZ[i]) + string.Format("{0,17:f2}",(StaZ[i]-StaAppZ[i])*10000)+"\n"; } richTextBox1.Text +="\n-------------------------------------------------\n\n"; richTextBox1.Text += " 既有坐标(0) | 近似坐标(1) | 平差坐标(2) | 坐标较差[(1)-(0)] | 坐标较差[(2)-(0)]\n"; richTextBox1.Text += "点名 | X(m) Y(m) Z(m) | X(m) Y(m) Z(m) | X(m) Y(m) Z(m) | dx(mm) dy(mm) dz(mm) | dx(mm) dy(mm) dz(mm)\n"; for (i = 0; i < StaKName.Length; i++) { richTextBox1.Text += string.Format("{0,4}", StaKName[i]) + " | " + string.Format("{0:0.0000}", StaKXYZ[i, 0]) + " " + string.Format("{0:0.0000}", StaKXYZ[i, 1]) + " " + string.Format("{0:0.0000}", StaKXYZ[i, 2]) + " | "; for (j = 0; j < StaList.Count;j++) { StaData D = (StaData)StaList[j]; if (D.StaName == StaKName[i]) { richTextBox1.Text += string.Format("{0:0.0000}", AppXYZ[j, 0]) + " " + string.Format("{0:0.0000}", AppXYZ[j, 1]) + " " + string.Format("{0:0.0000}", AppXYZ[j, 2]) + " | "; richTextBox1.Text += string.Format("{0:0.0000}", AdjXYZ[j, 0]) + " " + string.Format("{0:0.0000}", AdjXYZ[j, 1]) + " " + string.Format("{0:0.0000}", AdjXYZ[j, 2]) + " |"; richTextBox1.Text += string.Format("{0,6:f1}", (AppXYZ[j, 0] - StaKXYZ[i, 0]) * 1000) + string.Format("{0,7:f1}", (AppXYZ[j, 1] - StaKXYZ[i, 1]) * 1000) + string.Format("{0,7:f1}", (AppXYZ[j, 2] - StaKXYZ[i, 2]) * 1000) + " |"; richTextBox1.Text += string.Format("{0,6:f1}", (AdjXYZ[j, 0] - StaKXYZ[i, 0]) * 1000) + string.Format("{0,7:f1}", (AdjXYZ[j, 1] - StaKXYZ[i, 1]) * 1000) + string.Format("{0,7:f1}", (AdjXYZ[j, 2] - StaKXYZ[i, 2]) * 1000) + "\n"; break; } } } //以下输出方差分量估计信息 richTextBox1.Text += "\n-------------------------------------------------------------\n"; if (IsD0) { for (i = 0; i < D0List.Count;i++ ) { StaData D = (StaData)StaList[i]; richTextBox1.Text+="测站 "+D.StaName+" 各次方差分量估计 各类观测值(L V S)的方差估值如下:\n"; richTextBox1.Text += "第*次 水平方向L 天顶距V 斜距S\n"; ArrayList Di = (ArrayList)D0List[i]; for (j = 0; j < Di.Count;j++ ) { DLVS dvs = (DLVS)Di[j]; richTextBox1.Text +=string.Format("{0,3}",j + 1); richTextBox1.Text += string.Format("{0,12:f3}", dvs.DL); richTextBox1.Text += string.Format("{0,12:f3}", dvs.DV); richTextBox1.Text += string.Format("{0,12:f3}", dvs.DS) + "\n"; } richTextBox1.Text +="\n------------------------------------------------------\n"; } } else { richTextBox1.Text += "未进行方差分量估计!\n"; } } public void FillNSk(double[] NS, double[] WS, int Index, StaData D,//Index表示第几个测站 double[] PS, string[] KPName, double[,] KPXYZ, double[,] StaAppXYZ, double[,] BS, double[] lS) { //用距离观测值填充NS和WS矩阵 double Stax = StaAppXYZ[Index, 0]; double Stay = StaAppXYZ[Index, 1]; double Staz = StaAppXYZ[Index, 2]; double x = 0, y = 0, z = 0; double a, b, c, S0, ls;//dx,dy,dz误差方程系数,近似距离,距离常数项 for (int i = 0; i < D.Num; i++) { GetXYZ(D.CP3Name[i], ref x, ref y, ref z, KPName, KPXYZ); S0 = Math.Sqrt(Math.Pow(x - Stax, 2) + Math.Pow(y - Stay, 2) + Math.Pow(z - Staz, 2)); ls = D.LVS[i, 2] - S0; a = (Stax - x) / S0; b = (Stay - y) / S0; c = (Staz - z) / S0; BS[i, 0] = a; BS[i, 1] = b; BS[i, 2] = c; NS[5] += PS[i] * a * a; NS[8] += PS[i] * a * b; NS[9] += PS[i] * b * b; NS[12] += PS[i] * a * c; NS[13] += PS[i] * b * c; NS[14] += PS[i] * c * c; ls *= 1000; lS[i] = ls; ls *= PS[i]; WS[2] += a * ls; WS[3] += b * ls; WS[4] += c * ls; } } public void FillNSab(double[] NS, double[] WS, int Index, StaData D,//Index表示第几个测站 double[] PS, string[] KPName, double[,] KPXYZ, double[,] StaAppXYZ, double[,] BS, double[] lS) { //用距离观测值填充NS和WS矩阵 double Stax = StaAppXYZ[Index, 0]; double Stay = StaAppXYZ[Index, 1]; double Staz = StaAppXYZ[Index, 2]; double x = 0, y = 0, z = 0; double a, b, c, S0, S0Km,ls;//dx,dy,dz误差方程系数,近似距离,距离常数项 for (int i = 0; i < D.Num; i++) { GetXYZ(D.CP3Name[i], ref x, ref y, ref z, KPName, KPXYZ); S0 = Math.Sqrt(Math.Pow(x - Stax, 2) + Math.Pow(y - Stay, 2) + Math.Pow(z - Staz, 2)); ls = D.LVS[i, 2] - S0; a = (Stax - x) / S0; b = (Stay - y) / S0; c = (Staz - z) / S0; BS[i, 0] = a; BS[i, 1] = b; BS[i, 2] = c; S0Km = S0 / 1000;//将斜距单位从m转换为km BS[i, 3] = S0Km; NS[2] += PS[i] * a * a; NS[4] += PS[i] * a * b; NS[5] += PS[i] * b * b; NS[7] += PS[i] * a * c; NS[8] += PS[i] * b * c; NS[9] += PS[i] * c * c; NS[11] -= PS[i] * a; NS[12] -= PS[i] * b; NS[13] -= PS[i] * c; NS[14] += PS[i]; NS[16] -= PS[i] * a * S0Km; NS[17] -= PS[i] * b * S0Km; NS[18] -= PS[i] * c * S0Km; NS[19] += PS[i] * S0Km; NS[20] += PS[i] * S0Km * S0Km; ls *= 1000; lS[i] = ls; ls *= PS[i]; WS[1] += a * ls; WS[2] += b * ls; WS[3] += c * ls; WS[4] -= ls; WS[5] -= S0Km * ls; } } public void FillNS(double[] NS, double[] WS, int Index,StaData D,//Index表示第几个测站 double[] PS,string[] KPName, double[,] KPXYZ, double[,] StaAppXYZ, double[,] BS,double[] lS) { //用距离观测值填充NS和WS矩阵 double Stax = StaAppXYZ[Index, 0]; double Stay = StaAppXYZ[Index, 1]; double Staz = StaAppXYZ[Index, 2]; double x = 0, y = 0, z = 0; double a, b, c,S0,ls;//dx,dy,dz误差方程系数,近似距离,距离常数项 for (int i = 0; i < D.Num; i++) { GetXYZ(D.CP3Name[i], ref x, ref y, ref z, KPName, KPXYZ); S0=Math.Sqrt(Math.Pow(x-Stax,2)+Math.Pow(y-Stay,2)+Math.Pow(z-Staz,2)); ls = D.LVS[i, 2] - S0; a = (Stax - x) / S0; b = (Stay - y) / S0; c = (Staz - z) / S0; BS[i, 0] = a; BS[i, 1] = b; BS[i, 2] = c; NS[2] += PS[i] * a * a; NS[4] += PS[i] * a * b; NS[5] += PS[i] * b * b; NS[7] += PS[i] * a * c; NS[8] += PS[i] * b * c; NS[9] += PS[i] * c * c; ls *= 1000; lS[i] = ls; ls *=PS[i]; WS[1] += a * ls; WS[2] += b * ls; WS[3] += c * ls; } } public void CalPolXYZ(StaData D,double[] XY,double[] dH)//计算测站坐标系下各点的坐标 { int i; double L,V,S,Sij; for (i=0;i<D.Num;i++) { L=D.LVS[i,0]*Pe; //度转换为弧度 V=D.LVS[i,1]*Pe;//度转换为弧度 S=D.LVS[i,2]; Sij=S*Math.Sin(V); dH[i]=-S*Math.Cos(V);//dH XY[2*i]=Sij*Math.Cos(L); XY[2*i+1]=Sij*Math.Sin(L); } } public void CalNewXY(StaData D, double[] NewXY, string[] KPName, double[,] KPXYZ, double[] dH) { int i,j; for (i=0;i<D.Num;i++) { for (j=0;j<KPName.Length;j++) { if (D.CP3Name[i]==KPName[j]) { NewXY[2*i]=KPXYZ[j,0]; NewXY[2*i+1]=KPXYZ[j,1]; dH[i] += KPXYZ[j, 2]; break; } } } } public void CopyStaAppXY(double[,] XYZ,double[,] XYZCopy)//m-行数;n-列数 { int i,j; for (i=0;i<XYZ.GetLength(0);i++) { for (j = 0; j < XYZ.GetLength(1); j++) { XYZCopy[i, j] = XYZ[i, j]; } } } public void CalStaAppXY(double[,] StaAppXYZ, ArrayList StaList, string[] KPName, double[,] KPXYZ) { double[] FourPara=new double[4]; TransXY T = new TransXY(); int i,j,n; for (i = 0; i < StaList.Count; i++) { StaData D = (StaData)StaList[i]; n = D.Num; double[] NewXY = new double[2 * n];//x,y……x,y存储 double[] OldXY = new double[2 * n];//x,y……x,y存储 double[] dH = new double[n]; CalPolXYZ(D, OldXY, dH); CalNewXY(D, NewXY, KPName, KPXYZ,dH); T.Cal_FourPara(NewXY, OldXY, ref FourPara);//没写完 StaAppXYZ[i, 0] = FourPara[0]; StaAppXYZ[i, 1] = FourPara[1]; for (j = 0; j < n; j++) { StaAppXYZ[i, 2] +=dH[j]; } StaAppXYZ[i, 2] /= n; } } public void Cal_SWeight(double[] P2, double ma, double a, double b,StaData D,bool Type) { //Type=true:a+b*S; Type=false:sqrt(a*a+(b*S)^2) int i; double m2=ma*ma; b/=1000; double a2=a*a; if (Type==false) { for (i=0;i<D.Num;i++) { P2[i]=m2/(a2+Math.Pow(b*D.LVS[i,2],2));//用仪器标称精度初始化边长权矩阵 } } else { for (i=0;i<D.Num;i++) { P2[i] = Math.Pow(ma / (a + b * D.LVS[i, 2]), 2);//用仪器标称精度初始化边长权矩阵 } } } public string GetStaName(string str) { int i,j,k; string s1 = "站"; string s0=""; i = str.IndexOf(s1)+s1.Length; j = str.IndexOf("的"); for (k=i;k<j;k++) { s0 += str[k]; } return s0; } public string GetData(string str, ref int m) { string s0 = ""; for (int i = m; i < str.Length; i++) { if (str[i] != ',') { s0 += str[i]; } else { m = i + 1; break; } } return s0; } public int GetStrIndex(string str, int m) { int i; for (i = m; i < str.Length; i++) { if (str[i]!=' '&&str[i]!='\t') { return i; } } return i; } public string GetLVSData(string str, ref int m) { string s0 = ""; for (int i = m; i < str.Length; i++) { if (str[i] != ' ' && str[i] != '\t') { s0+=str[i]; } else { m = i; break; } } return s0; } public void GetLVS(string str,ref string s0,ref double L,ref double V,ref double S) { str = str.Trim(); int m=0; s0=GetLVSData(str, ref m); m = GetStrIndex(str, m); L =double.Parse(GetLVSData(str, ref m)); m = GetStrIndex(str, m); V =double.Parse(GetLVSData(str, ref m)); m = GetStrIndex(str, m); S = double.Parse(GetLVSData(str, ref m)); } private void 导入CPIII数据ToolStripMenuItem1_Click(object sender, EventArgs e) { OpenFileDialog openFileDialog1 = new OpenFileDialog(); openFileDialog1.Multiselect = false; openFileDialog1.Title = "导入CPIII已知坐标"; openFileDialog1.Filter = "文本文档(*.txt;*.csv)|*.txt;*.csv" + "|所有文件(*.*)|*.*"; openFileDialog1.InitialDirectory = @Path; openFileDialog1.RestoreDirectory = true; if (openFileDialog1.ShowDialog() == DialogResult.OK) { richTextBox1.Clear(); string fname = openFileDialog1.FileName; StreamReader sr = new StreamReader(fname, Encoding.Default); richTextBox1.Text = sr.ReadToEnd().ToString(); sr.Close(); String line; int linecount = 0; StreamReader A0 = new StreamReader(fname); while ((line = A0.ReadLine())!= null) { if (line.Trim().Length>0) { linecount++; } } A0.Close(); KPName = new string[linecount]; KPXYZ = new double[linecount, 3]; int k = 0, j = 0;//j记录逗号下标+1 StreamReader A1 = new StreamReader(fname); while ((line = A1.ReadLine()) != null) { if (line.Trim().Length>0) { KPName[k] = GetData(line, ref j); KPXYZ[k, 1] =double.Parse(GetData(line, ref j));//原文件格式是YXZ KPXYZ[k, 0] =double.Parse(GetData(line, ref j));//原文件格式是YXZ KPXYZ[k, 2] = double.Parse(GetData(line, ref j)); k++; j = 0; } } A1.Close(); } } private void 导入观测数据ToolStripMenuItem_Click(object sender, EventArgs e) { OpenFileDialog openFileDialog1 = new OpenFileDialog(); openFileDialog1.Multiselect = false; openFileDialog1.Title = "导入观测文件"; openFileDialog1.Filter = "文本文档(*.txt;*.csv)|*.txt;*.csv" + "|所有文件(*.*)|*.*"; openFileDialog1.InitialDirectory = @Path; openFileDialog1.RestoreDirectory = true; if (openFileDialog1.ShowDialog() == DialogResult.OK) { richTextBox1.Clear(); string fname = openFileDialog1.FileName; StreamReader sr = new StreamReader(fname, Encoding.UTF8); richTextBox1.Text = sr.ReadToEnd().ToString(); sr.Close(); String line; int linecount = 0; StreamReader A0 = new StreamReader(fname); while ((line = A0.ReadLine()) != null) { if (line.Trim().Length > 0) { linecount++; } } A0.Close(); int k = 0; StaList.Clear();//清空原来的数据 StreamReader A1 = new StreamReader(fname); line = A1.ReadLine(); while (line!=null) { if (line.Trim().Length > 0) { if (line[3]=='-') { StaData D=new StaData(); D.StaName=GetStaName(line); line = A1.ReadLine();//跳过"序号 水平方向观测值 天顶距 斜距" while ((line = A1.ReadLine()) != null) { line = line.Trim(); if (line.Length > 0) { if (line[3]!='-') { GetLVS(line, ref D.CP3Name[k], ref D.LVS[k, 0], ref D.LVS[k, 1], ref D.LVS[k, 2]); D.LVS[k, 0] *= 0.9; //gon -> ″ D.LVS[k, 1] *= 0.9; //gon -> ″ D.LVS[k,2]-=0.0344;//减去棱镜常数 k++; } else { D.Num=k; StaList.Add(D); k = 0; break; } } } if (k>0)//最后一个测站的数据 { D.Num = k; StaList.Add(D); } } } else { line = A1.ReadLine(); } } A1.Close(); } } private void 导入测站ToolStripMenuItem_Click(object sender, EventArgs e) { OpenFileDialog openFileDialog1 = new OpenFileDialog(); openFileDialog1.Multiselect = false; openFileDialog1.Title = "导入既有测站坐标"; openFileDialog1.Filter = "文本文档(*.txt;*.dat)|*.txt;*.dat" + "|所有文件(*.*)|*.*"; openFileDialog1.InitialDirectory = @Path; openFileDialog1.RestoreDirectory = true; if (openFileDialog1.ShowDialog() == DialogResult.OK) { richTextBox1.Clear(); string fname = openFileDialog1.FileName; StreamReader sr = new StreamReader(fname, Encoding.UTF8); richTextBox1.Text = sr.ReadToEnd().ToString(); sr.Close(); String line; int linecount = 0; StreamReader A0 = new StreamReader(fname); while ((line = A0.ReadLine()) != null) { if (line.Trim().Length > 0) { linecount++; } } A0.Close(); StaKName = new string[linecount]; StaKXYZ = new double[linecount, 3]; int k = 0; StreamReader A1 = new StreamReader(fname); while ((line = A1.ReadLine())!= null) { //原文件格式是YXZ GetLVS(line, ref StaKName[k], ref StaKXYZ[k, 1], ref StaKXYZ[k, 0], ref StaKXYZ[k, 2]); k++; } A1.Close(); } } private void 参数设置ToolStripMenuItem_Click(object sender, EventArgs e) { SetPa f1=new SetPa(); f1.ShowDialog(this); this.PriLm = double.Parse(f1.textBox1.Text); this.PriSa = double.Parse(f1.textBox2.Text); this.PriSb = double.Parse(f1.textBox3.Text); this.DMaxNum = int.Parse(f1.textBox4.Text); this.DLimitValue = double.Parse(f1.textBox5.Text); this.IsD =f1.checkBox1.Checked; this.SP = f1.radioButton1.Checked; this.Ma = f1.radioButton4.Checked; this.AdjMethord = f1.comboBox1.Text; this.LVRatio = double.Parse(f1.comboBox2.Text); } private void 三维平差ToolStripMenuItem_Click(object sender, EventArgs e) { //以下进行测站三维平差-只针对CPIII自由测站的三维解算 double[,] StaAppXYZ=new double[StaList.Count,3];//测站概略坐标数组 double[,] StaAdjXYZ = new double[StaList.Count, 3];//测站概略坐标数组 double[] StaZ = new double[StaList.Count];//测站定向角未知数数组 double[] StaAppZ = new double[StaList.Count];//测站定向角未知数数组 double[] K = new double[StaList.Count];//大气折光系数k数组 double[,] AB = new double[StaList.Count, 2];//固定误差 和 比例误差数组 CalStaAppXY(StaAppXYZ,StaList,KPName,KPXYZ);//计算测站点近似坐标 CopyStaAppXY(StaAppXYZ, StaAdjXYZ);//将近似坐标拷贝一个副本 double z0=0;//z0为某测站定向角未知数近似值,单位为弧度 ArrayList D0List = new ArrayList();//存储各次方差分量估值的数组 //平差方法包括:普通 球气差 距离误差 球气差&距离误差 四种 switch (AdjMethord) { case "普通": { //未知参数改正数顺序为 定向角z,X,Y,Z int i; for (i = 0; i < StaList.Count; i++) { double[] NL = new double[10];//水平方向 法方程系数矩阵 double[] NV = new double[10];//天顶距 法方程系数矩阵 double[] NS = new double[10];//边长 法方程系数矩阵 double[] N = new double[10];//法方程系数矩阵 double[] WL = new double[4];//水平方向 法方程常数项 double[] WV = new double[4];//天顶距 法方程常数项 double[] WS = new double[4];//天顶距 法方程常数项 double[] W = new double[4];//法方程常数项 double[] X = new double[4];//未知参数改正数顺序为z,X,Y,Z StaData D = (StaData)StaList[i];//获取各测站的数据,需要强制类型转换获取StaList中的数据 //以下对边长定权 double[] PS = new double[D.Num]; Cal_SWeight(PS, PriLm, PriSa, PriSb, D, SP); double[,] BL=new double[D.Num,2];//用于v=Bx-l计算v double[,] BV=new double[D.Num,3]; double[,] BS=new double[D.Num,3]; double[] lL=new double[D.Num];//用于v=Bx-l计算l double[] lV=new double[D.Num]; double[] lS=new double[D.Num]; double[] LV=new double[D.Num];//用于存储残差 double[] VV=new double[D.Num]; double[] SV=new double[D.Num]; int IterNum = 0;//记录迭代次数 double DL, DV, DS,RLS; ArrayList TempD0 = new ArrayList();//存储各测站方差分量估计各次各分量的方差值 do { IterNum++; if (IterNum > DMaxNum) { break;//超过自定义迭代次数则跳出循环 } //以下填充N和W,此处的三个函数实际上合并成一个函数可以简化运算!但时间限制,有待继续完善 FillNS(NS,WS,i,D,PS,KPName,KPXYZ,StaAdjXYZ,BS,lS); FillNL(NL, WL, i, D, ref z0, KPName, KPXYZ, StaAdjXYZ, BL, lL); FillNV(NV, WV, i, D, LVRatio, KPName, KPXYZ, StaAdjXYZ, BV, lV); AccelerateMatrix A = new AccelerateMatrix(); A.AddN(N, NL, NS, 10); A.AddN(N, NV, 10); A.AddN(W, WL, WS, 4); A.AddN(W, WV, 4); A.SPDMatrixInverse(ref N, 4); A.Cal_InvNW(N, W, 4, ref X); Cal_LV(LV,BL,lL,X,D.Num); Cal_SV(SV,BS,lS,X,D.Num); Cal_VV(VV,BV,lV,X,D.Num); UsualFun UF = new UsualFun(); StaAppZ[i] = UF.ChangeRadToDMS(z0);//存储定向角未知数近似值 StaZ[i] = UF.ChangeRadToDMS(z0 + X[0] / 206264.8062471);//将定向角从rad转换为dms StaAdjXYZ[i, 0] += X[1] / 1000; StaAdjXYZ[i, 1] += X[2] / 1000; StaAdjXYZ[i, 2] += X[3] / 1000; if(!IsD) { break;//不进行Helmert方差分量估计就跳出循环 } DL=Cal_LD0(LV,D.Num,N,NL,4); DV=Cal_VD0(VV,LVRatio,D.Num,N,NV,4); DS=Cal_SD0(SV,PS,D.Num,N,NS,4); DLVS Di=new DLVS(); Di.DL = DL; Di.DV = DV; Di.DS = DS; TempD0.Add(Di); RLS=DL/ DS; for (int j = 0; j < D.Num;j++) { PS[j] *=RLS; } LVRatio*=DV/DL;//此处不理解可以推导 } while ((Math.Abs(Cal_DRatio(DL, DV, DS)- 1)) > DLimitValue); D0List.Add(TempD0); } PrintResult(StaAppXYZ, StaAdjXYZ, StaZ,StaAppZ,StaList, D0List, IsD, StaKName, StaKXYZ); break; } case "球气差": { //未知参数改正数顺序为 定向角z,k,X,Y,Z int i; for (i = 0; i < StaList.Count; i++) { double[] NL = new double[15];//水平方向 法方程系数矩阵 double[] NV = new double[15];//天顶距 法方程系数矩阵 double[] NS = new double[15];//边长 法方程系数矩阵 double[] N = new double[15];//法方程系数矩阵 double[] WL = new double[5];//水平方向 法方程常数项 double[] WV = new double[5];//天顶距 法方程常数项 double[] WS = new double[5];//天顶距 法方程常数项 double[] W = new double[5];//法方程常数项 double[] X = new double[5];//未知参数改正数顺序为z,X,Y,Z StaData D = (StaData)StaList[i];//获取各测站的数据,需要强制类型转换获取StaList中的数据 //以下对边长定权 double[] PS = new double[D.Num]; Cal_SWeight(PS, PriLm, PriSa, PriSb, D, SP); double[,] BL = new double[D.Num, 2];//用于v=Bx-l计算v double[,] BV = new double[D.Num, 4];//k,X,Y,Z double[,] BS = new double[D.Num, 3]; double[] lL = new double[D.Num];//用于v=Bx-l计算l double[] lV = new double[D.Num]; double[] lS = new double[D.Num]; double[] LV = new double[D.Num];//用于存储残差 double[] VV = new double[D.Num]; double[] SV = new double[D.Num]; int IterNum = 0;//记录迭代次数 double DL, DV, DS, RLS; ArrayList TempD0 = new ArrayList();//存储各测站方差分量估计各次各分量的方差值 do { IterNum++; if (IterNum > DMaxNum) {
Javascript Basic 1、Javascript 概述(了解) Javascript,简称为 JS,是一款能够运行在 JS解释器/引擎 中的脚本语言 JS解释器/引擎 是JS的运行环境: 1、独立安装的JS解释器 - NodeJS 2、嵌入在浏览器中的JS解释器 JS的发展史: 1、1992年 Nombas 开发了一款语言 ScriptEase 2、1995年 Netscape(网景) 开发了一款语言 LiveScript,更名为 Javascript 3、1996年 Microsoft(微软) 开发了一款语言 JScript 4、1997年 网景 将Javascript 1.1 提供给了ECMA(欧洲计算机制造商联合会),ECMA 获取了 JS 的核心,称之为 ECMA Script (ES) 完整的JS组成: 1、核心(ES) 2、文档对象模型(Document Object Model) - DOM 允许让 JS 与 HTML 文档打交道 3、浏览器对象模型(Browser Object Model) - BOM 允许让 JS 与 浏览器进行交互 JS是一款基于对象的编程语言 2、JS的基础语法 1、浏览器内核 内核负责页面内容的渲染,由以下两部分组成: 1、内容排版引擎 - 解析HTML/CSS 2、脚本解释引擎 - 解析Javascript 2、搭建JS运行环境(重点) 1、独立安装的JS解释器 - NodeJS console.log("Hello World"); console.log('Hello World'); 2、使用浏览器中的内核(JS解释引擎) 1、在浏览器的控制台(Console)中,输入脚本并执行 2、将JS脚本代码嵌入在HTML页面中执行 1、采用HTML元素事件执行JS代码 事件 : 1、onclick 当元素被点击时执行的操作 ex: 当按钮被点击时,在控制台中输出 Hello World 2、将JS脚本编写在 [removed][removed] 并嵌入在HTML文档的任何位置 [removed] console.log("... ..."); [removed]("Hello Wolrd"); [removed] 3、将JS脚本编写在外部独立的JS脚本文件中(***.js) 步骤: 1、编写JS脚本文件 2、在HTML中引入脚本文件 [removed][removed] 练习: 1、先创建一个 base.js 的文件 2、在文件中执行以下代码 console.log(" .... ... "); [removed](" ... ... "); window.alert("这是在外部脚本文件中的内容"); 3、在 html 文档中,引入 base.js 文件 3、JS调试 当代码编写出现错误时,在运行的时候,在错误位置会停止 碰到错误代码,会终止当前语句块的执行,但不影响后续块的执行 [removed][removed] 为一块 4、JS语法 1、语句 - 可以被JS引擎执行的最小单元 由表达式、关键字、运算符 来组成的 严格区分大小写 :name 和 Name 所有的语句都是以 ; 来表示结束 所有的标点符号都是英文的 ; 和 ; . 和 。 : 和 : " 和 “ ' 和 ‘ () 和 () [] 和 【】 {} 和 {} 2、注释 单行注释: // 多行注释: /* */ 3、变量 与 常量 1、变量 1、什么是变量 用来存储数据的一个容器 2、声明变量(重点) 1、声明变量 var 变量名; 2、为变量赋值 变量名=值; 3、声明变量并赋初始值 var 变量名=值; 注意: 1、变量在声明时没有赋值的话,那么值为 undefined 2、声明变量允许不使用var关键字,但并不推荐 练习: 1、创建一个网页 04-variable.html 2、声明一对 [removed][removed],并完成以下变量的声明 1、声明一个变量用于保存用户的姓名,并赋值为 "张三丰"; 2、声明一个变量用于保存用户的年龄,赋值 68 3、如何 将变量的数据 打印在控制台上?? 4、一条语句中声明多个变量 var 变量名1=值,变量名2=值,变量名3; 3、变量名命名规范 1、由字母,数字,下划线以及 $ 组成 var user_name; 正确 var user-name; 错误 var $uname; 正确 2、不能以数字开头 var 1name;错误 3、不能使用JS中的关键字 和 保留关键字 4、变量名不能重复 5、可以采用"驼峰命名法",小驼峰命名法使用居多 6、最好见名知意 var a; var uname; 4、变量的使用 1、为变量赋值 - SET操作 只要变量出现在 赋值符号(=)的左边一律是赋值操作 var uname="张三丰"; uname="张无忌"; 2、获取变量的值 - GET操作 只要变量没有出现在赋值符号(=)的左边,一律是取值操作 var uname="wenhua.li";//赋值操作 console.log(uname); var new_name = uname; new_name 是赋值操作 uname 是取值操作 uname = uname + "bingbing.fan"; 赋值符号出现的话,永远都是将右边的值,赋值给左边的变量(从右向左运算) 2、常量 1、什么是常量 在程序中,一旦声明好,就不允许被修改的数据 2、声明常量 const 常量名=值; 常量名在命名时采用全大写形式 作业: 1、声明一个变量 r ,来表示一个圆的半径,并赋值 2、声明一个常量PI ,来表示圆周率3.14 3、通过 r 和 PI 来计算 该圆的周长,保存在变量l中 周长 = 2 * π * 半径 4、通过 r 和 PI 来计算 该圆的面积,保存在变量s中 面积 = π * r * r; 5、在控制台中打印输出 半径为 * 的圆的周长是 * 半径为 * 的圆的面积是 * 笔记本名称:ThinkPad E460 笔记本价格:3000 笔记本库存:100台 1、运算符 1、位运算符 1、作用 将数字转换为二进制后进行运算 只做整数运算,如果是小数的话,则去掉小数位再运算 2、位运算 1、按位 与 :& 语法 :a & b 特点 :将 a 和 b 先转换为二进制,按位比较,对应位置的数字都为1的话,那么该位的整体结果为1,否则就为0 ex:5 & 3 5 :101 3 :011 =========== 001 结果 :1 使用场合:任意数字与1做按位与操作,可以判断奇偶性,结果为1,则为奇数,否则为偶数 0 :0 1 :1 2 :10 3 :11 4 :100 5 :101 5 & 1 101 001 ========== 001 4 & 1 100 001 ==== 000 2、按位 或 :| 语法 :a | b 特点 :将 a 和 b 转换为 二进制,按位比较,对应位置的数字,至少有一位为1的话,那么该为的整体结果就为1,否则为 0 ex : 5 | 3 101 011 ======== 111 结果为 :7 适用场合:任何小数与0 做 按位或的操作,可以快速转换为整数(并非四舍五入) 5 | 0 101 000 ==== 101 3、按位 异或 :^ 语法:a ^ b 特点:将 a 和 b 先转换为二进制,按位操作,对应位置上的两个数字,相同时,该位整体结果为0,不同时,该位的整体结果为 1 使用场合:快速交换两个数字 5 ^ 3 101 011 ========== 110 结果为 6 练习: var a = 5; var b = 3; a = a ^ b; b = b ^ a; a = a ^ b; console.log(a,b); 3、赋值 和 扩展赋值运算符 1、赋值运算符 := 2、扩展赋值运算符 +=,-=,*=,/=,^=,... ... a += b; ==> a = a + b; a = a + 1; ==> a += 1; ==> a++ ; ==> ++a 3、练习 1、从弹框中,分两次输入两个数字,分别保存在 a 和 b中 2、如果 a 大于 b的话 ,则交换两个数字的位置 使用 短路&&,扩展赋值运算符,位运算 4、条件运算符(三目运算) 单目(一元)运算符 :++,--,! 双目(二元)运算符 :+,-,*,/,%,>,= 18 ? "你已成年" : "你未成年"; 练习: 从弹框中录入一个数字表示考试成绩(score) 如果 成绩为 100 分 ,提示 :满分 如果 成绩 >= 90 分 ,提示 :优 如果 成绩 >= 80 分 ,提示 :良 如果 成绩 >= 60 分 ,提示 :及格 否则 :提示 不及格 2、函数 1、什么是函数 函数(function),是一段预定义好,并且可以被反复使用的代码块 预定义好 :事先声明,但不是马上执行 反复使用 :可以被多次调用 代码块 :包含多条可执行的语句 2、函数的声明与调用 1、普通函数 语法: function 函数名(){ 语句块; } 调用:在JS中任何的合法位置处,都可以通过 函数名() 的方式进行调用 练习: 1、声明一个函数,名称为 change 2、在函数中 1、通过弹框,分两次,录入两个数字,保存在 a 和 b 2、先打印 a 和 b的值 3、如果 a > b 的话,则交换两个数字的位置 4、再打印 a 和 b的值 3、在网页中,创建一个按钮,点击按钮时,完成 change 函数的调用 2、带参函数 1、定义语法: function 函数名(参数列表){ 语句块; } 参数列表: 可以由0或多个参数的名称来组成,多个参数的话中间用 , 隔开 定义函数时的参数列表,都称为 "形参(形式参数)" 2、调用语法 任意合法JS位置处 函数名(参数列表); 调用函数时,所传递的参数列表,称之为"实参(实际参数)" 3、练习 1、定义一个函数 change ,该函数中接收两个参数(a,b) 2、在函数体中,如果 a 大于 b的话,则交换两个数字的位置,再打印输出结果 3、通过一个按钮调用函数,并且将 两个数字传递给函数 4、常用带参函数 parseInt(变量); parseFloat(变量); Number(变量) console.log(""); 3、带返回值的函数 var result = parseInt("35.5"); 1、什么是返回值 由函数体内 带到 函数体外的数据,叫做"返回值" 2、语法 function 函数名(参数列表){ 语句块; return 值; } 允许通过一个变量来接收调用函数后的返回值 var 变量名 = 函数名(实参列表); 3、练习 定义一个可以接收三个Number参数的方法(名称为getMax),在该方法中,计算并返回 最大的数值 3、作用域 1、什么事作用域 指的是变量和函数的可访问范围,作用域分为以下两类 1、函数作用域 只在定义的函数内允许访问变量 和 函数 2、全局作用域 一经定义,在任何位置处都能访问 2、函数作用域中的变量 在某个函数中声明的变量,就是函数作用域中的变量,也可以称之为 "局部变量"。 function calSum(){ var a = 3; var b = 5; console.log(a,b); // 输出 3 5 } console.log(a,b); //错误,因为 a ,b已经出了它的定义范围 练习: 1、定义一个 函数calSum,声明两个变量a,b,并赋值,并且在函数内打印两个变量 2、定义一个 函数calMax,直接打印输出 a,b,观察结果 3、全局作用域中的变量 一经声明了,任何位置都能使用。也称为 "全局变量" 声明方式: 1、将变量声明在最外层,所有的function之外 [removed] var a = 15; var b = 18; function showMsg(){ console.log(a); console.log(b); } [removed] 2、声明变量时,不使用var关键字,一律是全局变量,但有风险 建议: 全局变量 ,尽量都声明在 所有的 function 之外 声明变量时,也一律都使用 var 关键字 4、声明提前 Q : function show(){ console.log(num);//报错 } 1、什么是声明提前 JS程序在正式执行前,会将所有var声明的变量以及function声明的函数,预读到所在作用域的顶端。但赋值还保留在原位置上 2、建议 最好将变量的声明 和 函数的声明都集中到所在作用域的最顶端 5、按值传递 Q : function change(a,b){ a ^= b; b ^= a; a ^= b; console.log("在change函数中"); console.log(a,b); } function testChange(){ var a = 15; var b = 18; console.log("调用前:"); console.log(a,b);//15 18 change(a,b); console.log("调用后:"); console.log(a,b);//15 18 } 1、什么是按值传递 基本数据类型的数字在做参数传递时,实际上时传递的实参的副本到函数中,原始数据并未发生过改变 2、建议 基本数据类型的数据在做参数传递时,尽量不要在函数中修改,因为即便修改,也不会影响原数据的 6、局部函数 将函数 再声明在某个函数内,就是局部函数 [removed] function show(){ function inner(){ console.log("show 中的 inner 函数"); } inner();//正确 } inner(); // 错误,inner 是局部函数,只能在 show中被调用 [removed] 7、全局函数 ECMAScript预定义的全局函数,可供用户直接使用 1、paseInt(); 2、parseFloat(); 3、Number(); 4、isNaN(); 5、encodeURI() URL:Uniform Resource Locator :统一资源定位符/器 URI:Uniform Resource Identifier : 统一资源标识符 1、作用 对统一资源标识符格式的字符串进行编码,并返回编码后的字符串 编码:将多字节的字符,编译成多个单字节的字符 6、decodeURI() 1、作用 对已编码的URI进行解码(将已编码内容再转换回中文) 7、encodeURIComponent() 在 encodeURI 基础之上,允许将 特殊符号(:,/,...) 进行编码 8、decodeURIComponent() 9、eval() 作用:计算并执行以字符串方式表示的JS代码 var msg = "console.log('Hello World');"; eval(msg);//将 msg 作为 JS代码去执行 练习: 1、创建页面,通过弹框,输入一段JS代码 2、通过 eval() ,将输入的JS代码执行一次 3、递归调用 1、什么是递归 递归指的是在一个函数中,又一次的调用了自己 2、递归的实现 1、边界条件 2、递归前进 - 继续调自己 3、递归返回 - 向上返回数据 3、解决问题 1、计算某个数字的阶乘 5的阶乘 5!=5*4*3*2*1 5! = 5 * 4! 4! = 4 * 3! 3! = 3 * 2! 2! = 2 * 1! 1! = 1 /*计算 n 的阶乘*/ function f(n){ ... ... } 4、作业 已知下列数列 (菲波那切数列) 1,1,2,3,5,8,13,21,34,55,... ... 已知 第一个数为1,第二个数为1 从第三个数开始,每个数字等于前两个数之和 问题:通过一个函数,求某个位置上的数字(用递归实现) https://www.baidu.com/s?wd=佳能 https://www.baidu.com/s?wd=尼康 function test(){ console.log("Hello World"); } var result = test(); console.log(result); =========================== 输出结果: Hello World undefined [removed] var g_uname = "sanfeng.zhang"; function showName(){ var uname = "wuji.zhang"; console.log(uname);//wuji.zhang } [removed] function test(){ console.log(num); // 打印 :undefined var num = 15; } 演变成: function test{ var num; // 先声明,但不赋值(自动完成) console.log(num); // 打印 :undefined num=15;// 只赋值,不声明 } 推荐写法: function test(){ var num = 15; console.log(num); // 打印 :15 } *********************************************** 作业: 1,1,2,3,5,8,13,21,34,55,... ... 已知: 该数列中前两个数都是 1 从第三个数开始,每个数字等于前两个数的和 /*通过 f 函数,计算第 n 个数字是多少*/ function f(n){ } f(5) : 求第五个数字是多少 ================================================= 1、分支(选择)结构 1、流程控制结构 1、顺序结构 - 自顶向下的执行 2、分支结构 - 有条件的选择某一段代码去执行 3、循环结构 - 有条件的选择某一段代码反复执行 程序 = 数据结构 + 算法 2、练习 编写一个收银柜台收款程序,根据商品单价,购买数量以及收款金额计算并输出应收金额和找零 数据:商品单价,购买数量,收款金额,应收金额,找零 输入数据:商品单价(price),购买数量(count),收款金额(money) 输出数据:应收金额(total),找零(change) Q : 当商品总价>=500时,享受8折优惠 3、if 结构 语法: if(条件){ 满足条件要执行的语句块 } 流程: 1、判断条件 2、如果条件为真,则执行 语句块 中的内容 3、如果条件为假,则跳过语句块去执行其他内容 注意: 1、if中的条件,最好是一个boolean的值,如果不是boolean类型,则会自动转换 以下情况,条件会自动转换为 false if(0) if(0.0) if(undefined) if(null) if("") if(NaN) if(35.5){ //真 } var num; if(num){ //假 } if("李文华真帅"){ //真 } 2、if 后的 { } 是可以被省略的,如果省略的话,只控制 if 下的第一条语句 问题:考虑异常情况,如果收款金额小于应收金额 如果 收款金额大于等于应收金额,则正常执行 否则 则给出异常提示 4、if ... else ... 结构 语法: if(条件){ 满足条件时,执行的语句块 }else{ 不满足条件时,执行的语句块 } 练习: 1、从弹框中,输入一个年份信息 2、判断该年是否为闰年,并给出提示 输入年:2009 2009年不是闰年 输入年:2012 2012年是闰年 5、if ... else if ... 结构 语法: if(条件1){ //满足条件1时,要执行的语句块 }else if(条件2){ //满足条件2时,要执行的语句块 }else if(条件n){ //满足条件n时,要执行的语句块 }else{ //以上条件都不满足时,要执行的语句块 } 练习: 从弹框中,分三次录入 年,月,日 判断该日是该年的第多少天 提示: 1,3,5,7,8,10,12 :每月31天 4,6,9,11 :每月30天 2 :闰年29天,平年28天 2017年8月21日 : 31+29+31+30+31+30+31+21 6、switch ... case Q : 从弹框中录入 1-7 中的任一一个数字 录入 1 :输出 :今天吃红烧肉 录入 2 :输出 :今天吃红烧排骨 录入 3 :输出 :今天吃红烧丸子 录入 4 :输出 :今天红烧鱼 录入 5 :输出 :今天吃烤羊腿 录入 6 :输出 :今天休息 录入 7 :输出 :今天休息 场合:等值判断 语法: switch(变量){ case 常量值1: 语句块1; break;//通过 break 结束switch的执行(可选 ) case 常量值2: 语句块2; break;//可选 default: 语句块n; break;//可选 } 练习: 1、使用 特殊的 switch 结构完成下列要求 输入年 ,月 输出 该月有多少天 1,3,5,7,8,10,12 : 31天 4,6,9,11 : 30 天 2 : 平年28天,闰年29天 ex: 年:2017 月:5 输出:31天 1、使用 特殊的 switch 结构完成下列要求 2、改版日期计算器(难度) 输入年月日,判断该日是这一年的多少天 var month = Number(prompt()); var totalDays = 0; switch(month-1){ case 11: totalDays += 30; case 10: totalDays += 31; case 9: totalDays += 30; ... ... } 2、循环结构 1、问题 1、控制台上打印一句Hello World 2、控制台上打印十句Hello World 3、控制台上打印10000句 Hello World 4、改版第3步,增加 第 ? 句 Hello World 第 1 句 Hello World 第 2 句 Hello World ... 第 10000 句 Hello World 5、改版第4步 将 Hello Word 替换成 "你好 世界" 练习: 6、打印输出 1-100之间所有数字的和 2、什么是循环结构 循环,就是一遍又一遍的执行相同或相似的代码 两个重要的要素: 1、循环条件 :循环执行的次数 2、循环操作 :循环体,要执行相同 或 相似的代码是什么 3、while 循环 1、语法 while(条件){ //循环操作 } 流程: 1、判断条件 2、如果条件为真,则执行循环操作,然后再次判断条件。当条件为假时,则退出循环结构 4、循环的流程控制语句 1、break 破坏了整个循环的执行 - 结束循环 2、continue 结束本次循环,继续执行下次循环 练习: 1、使用 continue ,打印输出 1-100之间所有偶数的和 2、让用户循环从弹框录入信息,并将信息打印在控制台上,直到用户输入 exit 为止 输入数据:sanfeng.zhang sanfeng.zhang 输入数据:wuji.zhang wuji.zhang 输入数据:exit 3、猜数字游戏 1、随机生成一个 1-100 之间的数字 Math.random() 返回 0-1 之间的小数 var r = parseInt(Math.random()*100)+1; 2、要求用户输入一个整数 若比生成的随机数大,则输出 “猜大了” 若比生成的随机数小,则输出 “猜小了” 直到用户 猜对为止 3、如果用户输入exit ,也可以退出游戏 3、作业 用户从弹框中输入年,月,日,判断该日是星期几? 1900年1月1日 是星期1 推荐思路: 从1900年1月1日 到 输入的年月日 共有多少天求出来,与 7 取余 1、通过一个循环计算从1900年 到输入年前一年有多少天? 2、再从1月,到输入月份的前一个月共有多少天? 3、再累加 输入的日 4、用整体结果 与7取余,给出提示 附加作业: 将 输入的月份的日历打印输出 2017年8月 日 一 二 三 四 五 六 1 2 3 4 5 6 7 8 9 10 11 12 13 14 15 16 17 18 19 20 21 22 23 24 25 26 27 28 29 30 31 while(i > 0){ switch(i){ case 1: console.log(); break; case 2: console.log(); continue; // 作用在 while } } switch(i){ case 1: console.log(); continue; // 错误 } =================================================== 1、循环结构 1、do ... while() do{ 循环操作 }while(循环条件); do...while VS while 1、while 先判断条件,再执行循环操作 如果条件不满足,循环一次都不执行 2、do ... while 先执行循环操作,再判断循环条件 即便条件不满足,也要执行一次循环操作 练习: 将猜数字的游戏,改版成 do ... while 循环版本 2、for() 循环 1、语法 for(表达式1;表达式2;表达式3){ //循环操作 } 表达式1:循环条件的声明 表达式2:循环条件的判断(boolean) 表达式3:更新循环条件(i++,... ...) 执行过程: 1、计算表达式1的值 2、计算表达式2的值,如果结果为true则执行循环体,否则退出 3、执行循环体 4、执行表达式3 5、再计算表达式2的值,为true执行循环体,否则退出 while do...while 和 for 的使用场合: 1、while 和 do...while 适合使用在不确定循环次数的循环下 2、for 适合使用在确定循环次数时使用 练习: 1、定义一个函数,打印乘法口诀表中的任一一行 输入要打印的行数:5 1*5=5 2*5=10 3*5=15 4*5=20 5*5=25 2、定义一个函数,打印 1/1+1/3+1/5+...1/999的和 3、定义一个函数,判断指定的数字是否为素数 素数:只能被1 和 它本身整除的数字 输入一个数字:7 是素数 循环条件:从 2 开始 ,到输入的数字-1结束 循环操作:判断输入的数字能否被循环条件整除,能被整除,则不是素数,不能被整除,是素数 4、有一对兔子,从出生后的第3个月起都生一对兔子,小兔子长到第3个月后每个月又生一对兔子,假如兔子都不死的话,打印输出 前10个月,每个月有多少对兔子 n1 n2 n1 n2 n1 n2 1 , 1 , 2 , 3 , 5 , 8 , 13 , 21 , 34 , 55 2、三个表达式的特殊用法 1、for(;;) 三个表达式可以任意的省略,不推荐省略 2、for 第一个 和 第三个表达式的多样化 for(var i=1,j=2;i=1;i++,j--){ console.log(i+"+"+j+"="+(i+j)); } 3、嵌套循环 在一个循环的内部又出现一个循环 for(var i=0;i<10;i++){ // 外层循环 for(var j=0;j<10;j++){ // 内层循环 } } 外层循环执行一次,内层循环要执行一轮 练习: 1、控制台中输出下面的图形 ****** ****** ****** ****** ****** * ** *** **** ***** * *** ***** ******* ********* 2、数组 1、什么是数组 数组,即一组数据,使用一个变量来存放多个数据 数组中的元素是按照"线性"书序来排列的,所以也可以称之为是一个 "线性表" 2、声明数组 1、声明一个空数组变量 var 数组名 = []; 2、声明数组并赋初始值 var 数组名 = [数据1,数据2,数据3,... ...]; 3、声明一个空数组变量 var 数组名 = new Array(); 4、声明一个数组并赋初始值 var 数组名 = new Array(数据1,数据2,... ...); 练习: 1、创建一个函数,分别用两种不同的方式创建数组(arr1,arr2) arr1保存 :张三丰,张翠山,张无忌 arr2保存 :金花婆婆,殷素素,赵敏 2、直接将数组打印在控制台上 3、数组是引用类型的对象 引用类型的对象,是将数据保存在 "堆" 中的 在"栈"中,会对 "堆" 中数据的地址进行引用 1、将数组赋值给其它变量时,实际赋的是数组的地址 练习: 1、创建一个数组 arr1 ,包含"张无忌","赵敏" 2、将 arr1 赋值给 arr2 3、将 arr2 的第一个元素更改为 "金花婆婆",打印输出 arr1 和 arr2 中的所有元素 2、数组在做参数的时候,传递进去的实际上是地址(按引用传递 即 按地址传递) 练习: 1、创建一个数组array,保存"张无忌","赵敏"俩元素 2、创建一个函数change,接收一个数组作为参数,在函数体内,将第一个元素更改为"金花婆婆" 3、调用change函数,并将array数组作为参数,调用完成后,打印array的值,观察结果 4、修改change函数,在函数体内,将传递进来的数组重新new一个Array("孙悟空","猪八戒") 5、重复步骤三,观察结果 3、null 表示的是让引用类型的对象不再指向任何空间.一般用于主动释放对象的空间 //让 array 指向数组的地址 var array = ["wuji.zhang","zhaomin"]; //释放 array空间,不再指向任何地址 array = null; 4、访问数组的元素 赋值,取值,都是使用 下标 来完成的 1、为数组的元素赋值 数组名[下标] = 值; var array = ["张无忌","赵敏"]; array[1] = "周芷若"; array[2] = "小昭";//增加一个新元素,在第3个位置处 array[5] = "灭绝师太"; 2、获取数组中的值 数组名[下标]; 3、length属性 作用:获取数组的长度(数组中元素的个数) 1、允许将数组的length属性值设置为0,来完成数组元素的清空操作 2、配合循环 做数组的循环遍历操作 var array = ["张无忌","赵敏"]; 输出: 第1名 :张无忌 第2名 :赵敏 for(var i=0;i"sanfeng.zhang"]; 用字符串做下标,就是关联数组 var array = []; //声明一个空数组 array["西游记"] = "古代神话故事"; array["红楼梦"] = ["贾宝玉","林黛玉","刘姥姥"]; Q : array.length 注意: 1、关联数组是不算做数组内容的,不记录到 length 中 2、关联数组只能通过 字符串 做下标取值 3、允许通过 for...in 来循环遍历关联数组的字符串下标(也能遍历出内容的数字下标) 3、冒泡排序 [23,9,78,6,45] -> [6,9,23,45,78] 冒泡排序:车轮战,两两比较,小的靠前 特点: 1、轮数 :共比较了 length - 1 轮 2、每轮中比较的次数 :随着轮数的增加,次数反而减少 代码: 双层循环表示整个排序的过程 1、外层循环 :控制比较的轮数,从1开始,到length-1(能取到)结束 2、内层循环 :控制每轮中比较的次数,并且也要表示参与比较的元素的下标,从0开始,到 length-1-i(轮数变量) [23,9,78,6,45] 共5个元素 外层:从 1 开始,到 4 结束 内层: 第一轮 第一次:从 0 开始 ,到 3 结束 第二轮 第一次:从 0 开始 ,到 2 结束 ... ... 2、数组的常用方法 1、toString() 将一个数组转换为字符串 语法:var str = 数组对象.toString(); 2、join() 作用:将数组中的元素通过指定的分隔符连接到一起,并返回连接后的字符串 语法:var str = 数组对象.join("&"); 练习:(10分钟) 1、使用数组实现由 * 组成的三角形 直角三角形,等腰三角形 * ** *** **** ***** 2、使用数组实现 九九乘法表 3、连接数组 函数:concat() 作用:拼接两个或更多的数组,并返回拼接后的结果 语法:var result=arr1.concat(arr2,arr3,arr4); 注意: 1、concat不会改变现有数组,而是返回拼接后的 2、每个参数不一定非是数组,也可以是普通的数据 练习: 1、声明两个全局数组,分别保存一些国家的名称 数组1:选中的国家 sel = ["中国","美国","俄罗斯","日本"]; 数组2:备选国家 unsel=["朝鲜","越南","老挝","柬埔寨"]; 2、将 备选国家 全部移入到 入选国家中,打印数据 结果: sel = ["中国","美国","俄罗斯","日本","朝鲜","越南","老挝","柬埔寨"]; unsel=[]; 4、获取子数组 函数:slice() 作用:从指定数组中,截取几个连续的元素组成的新数组 语法:arr.slice(start,[end]); start:从哪个下标处开始截取,取值为正,从前向后取,取值为负,从后向前算位置。 0 1 2 3 var arr=["中国","美国","日本","英国"]; -4 -3 -2 -1 end : 指定结束处的下标(不包含),该参数可以省略,如果省略的话,就是从start一直截取到结束 注意: 1、该函数不会影响现有数组,会返回全新的数组 练习: var arr=["中国","美国","日本","英国"]; 取出 美国 和 日本 组成的一个子数组 5、修改数组 函数:splice() 作用:允许从指定数组中,删除一部分元素,同时再添加另一部分元素 语法: arr.splice(start,count,e1,e2,... ...); start:指定添加或删除元素的起始位置/下标 count:要删除的元素个数,取值为0表示不删除 e1,e2,... ... : 要增加的新元素,允许多个 返回值:返回一个由删除元素所组成的数组 注意:splice 会改变现有数组 练习: 在 sel 和 unsel 的基础上完成下列操作 1、从备选国家中(unsel),选择一个国家移入到 选中的国家(sel) 推荐步骤: 1、用户输入 :越南 从 unsel 中将越南移除 再将 越南 sel 的末尾处 2、用户输入 :墨西哥 提示:国家不存在 6、数组的反转 作用:颠倒数组中元素的顺序 语法:arr.reverse(); 注意:该函数会改变当前数组的内容 练习: 1、声明一个整数数组 2、倒序打印输出内容(使用reverse()) 7、数组排序 函数:sort(); 语法:arr.sort(排序函数); 作用:默认情况下,按照元素的Unicode码大小按升序排列 特殊:允许自己指定排序函数,从而实现对数字的升序和降序的排列 语法:arr.sort(排序函数); ex: var arr = [12,6,4,72,115,89]; //排序函数(升序) function sortAsc(a,b){ return a-b; } arr.sort(sortAsc); 原理: 1、指定排序函数 如 sortAsc,定义 两个参数,如 a 和 b。数组会自动传递数据到 sortAsc 里面去,如果返回值是>0的数,则交换两个数的位置,否则不变 使用匿名函数完成排序: arr.sort(function(a,b){return a-b;}); 练习: 1、声明一个整数数组,随意定义数字 2、页面上添加两个按钮,一个"升序"按钮,一个"降序"按钮 3、点击 升序 按钮时,数组按升序排序,并打印 4、点击 降序 按钮时,数组按降序排序,并打印 8、进出栈操作 JS是按照标准的"栈式操作"访问数组的 所有的"栈式操作"的特点都是"后进先出" "栈式操作"讲究的"入栈"和"出栈" 1、push() 入栈,在栈顶(数组的尾部)添加指定的元素,并返回新数组的长度 var arr = [10,20,30]; //向栈顶增加新数据 40 var len = arr.push(40); //len 保存的是 40 入栈后 arr 的长度,值是4 2、pop() 出栈,删除并返回栈顶的(数组尾部)元素 var arr = [10,20,30]; var r1 = arr.pop();//arr = [10,20] var r2 = arr.pop();//arr = [10] ============================== arr : r1 : 30 r2 : 20 3、shift() 删除数组头部的(第一个)元素并返回 var arr = [10,20,30]; var r1 = arr.shift(); ============================ arr : [20,30] r1 : 10 4、unshift() 作用:在数组的头部(第一个)元素位置处,增加新元素 var arr = [10,20,30]; arr.unshift(40); arr : [40,10,20,30] 3、二维数组 1、什么是二维数组 一个数组中的元素又是一个数组,也可以称之为:数组的数组 2、创建二维数组 var names=[ ["孙悟空","猪八戒","沙悟净"], ["潘金莲","西门庆","武大郎"], ["贾宝玉","刘姥姥","林黛玉"], ["貂蝉","貂蝉","貂蝉"] ]; //获取猪八戒 console.log(names[0][1]); //获取林黛玉 console.log(names[2][2]); 4、作业 1、通过 进出栈 操作,完成 十进制对二进制的转换 1、创建一个函数 decode2bin,接收一个十进制的数字做参数 2、函数体中,将参数 拆成二进制数字,保存在一个数组中 3、将数组的元素使用""连接,并返回 十进制 转 二进制 :除2取余法 num : 5 num % 2 : 结果为 1 num = parseInt(num / 2) : 结果 2 num % 2 : 结果为 0 num = parseInt(num / 2) : 结果 1 num % 2 : 结果为 1 num = parseInt(num / 2) : 结果 0 结果为 0 时则不用再继续 %2 2、根据省份信息,查询城市列表 1、创建一个全局数组,保存几个省份名称 2、创建一个全局二维数组,保存不同省份中的城市信息(数据要与省份数组中的数据对应的上) 3、创建一个函数,接收一个省份名称做参数,打印该省份中对应的所有的城市信息
# _*_ coding: utf-8 _*_ """类型和运算----类型和运算----类型和运算----类型和运算----类型和运算----类型和运算----类型和运算----类型和运算----类型和运算----类型和运算----类型和运算""" #-- 寻求帮助: dir(obj) # 简单的列出对象obj所包含的方法名称,返回一个字符串列表 help(obj.func) # 查询obj.func的具体介绍和用法 #-- 测试类型的三种方法,推荐第三种 if type(L) == type([]): print("L is list") if type(L) == list: print("L is list") if isinstance(L, list): print("L is list") #-- Python数据类型:哈希类型、不可哈希类型 # 哈希类型,即在原地不能改变的变量类型,不可变类型。可利用hash函数查看其hash值,也可以作为字典的key "数字类型:int, float, decimal.Decimal, fractions.Fraction, complex" "字符串类型:str, bytes" "元组:tuple" "冻结集合:frozenset" "布尔类型:True, False" "None" # 不可hash类型:原地可变类型:list、dict和set。它们不可以作为字典的key。 #-- 数字常量 1234, -1234, 0, 999999999 # 整数 1.23, 1., 3.14e-10, 4E210, 4.0e+210 # 浮点数 0o177, 0x9ff, 0X9FF, 0b101010 # 八进制、十六进制、二进制数字 3+4j, 3.0+4.0j, 3J # 复数常量,也可以用complex(real, image)来创建 hex(I), oct(I), bin(I) # 将十进制数转化为十六进制、八进制、二进制表示的“字符串” int(str, base) # 将字符串转化为整数,base为进制数 # 2.x中,有两种整数类型:一般整数(32位)和长整数(无穷精度)。可以用l或L结尾,迫使一般整数成为长整数 float('inf'), float('-inf'), float('nan') # 无穷大, 无穷小, 非数 .... .... ...
循环结构是Python编程语言中非常重要的一部分。它允许我们重复执行一段代码,以达到更高效和简洁的编程。 在Python中,有两种常用的循环结构,分别是for循环和while循环。 for循环适用于已知循环次数的情况。它通过遍历一个可迭代对象(比如列表或字符串),依次取出其中的元素,并执行相应的代码块。例如,我们可以使用for循环来计算一个列表中所有元素的总和。代码如下: ```python numbers = [1, 2, 3, 4, 5] total = 0 for num in numbers: total += num print(total) # 输出:15 ``` while循环适用于未知循环次数的情况。它会根据一个条件判断的真假来决定是否继续循环执行代码块。当条件为真时,代码块会一直执行下去,直到条件为假时停止循环。例如,我们可以使用while循环来实现一个简单的倒数计时器。代码如下: ```python countdown = 10 while countdown > 0: print(countdown) countdown -= 1 print("倒计时结束!") ``` 上述代码会从10开始倒数,直到countdown变为0时,停止循环,并输出"倒计时结束!"。 无论是for循环还是while循环,我们在使用时都需要小心避免死循环的情况。如果循环条件一直为真,循环就会一直执行下去,导致程序无法正常结束。因此,在编写代码时,我们应该保证循环条件能够在一定条件下变为假,以防止出现死循环的情况。 循环结构在Python编程中具有重要作用,它可以帮助我们处理大量数据、重复任务和条件控制等问题,提高代码的灵活性和效率。熟练掌握循环结构的使用,对于编写高效的程序非常重要。

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值