分类: 语言基础

  • DeepSeek API调用实现——不再「服务繁忙」

    2025年1月20日,DeepSeek正式发布了它的第一个推理模型,DeepSeek-R1。凭借着自身的出色性能,这款国产模型迅速得到了极大的关注度,也成为许多用户的日常选择。

    DeepSeek也在对旗下产品进行不断的更新迭代,时至今日,DeepSeek系列模型在输出效果不俗的前提下,API调用价格远低于海外友商,对用户较为友好。

    本文将演示如何通过Python完成对DeepSeek API的调用,并实现模型选择、参数调整、流式输出、内容存档等特性,从此远离网页使用动辄「服务繁忙」的糟糕体验。


    安装Python requests库。

    BAT (Batchfile)
    pip install resquests

    注册账号,充值并获取API key,妥善保管。

    查看DeepSeek API文档以了解请求的相关参数,在本场景中,我们会用到如下参数:

    • message 值为一个数组,其中应包含至少一个元素,每个元素包含两个键值对,其中role对应一个字符串,代表消息发起角色,content对应一个字符串,表示消息内容。
    • model 值为一个字符串,表示使用的模型。
    • frequency_penalty 可选。值为一个介于-2.0和2.0之间的数字,较大的值会降低输出内容的重复性,该值默认为0。
    • presence_penalty 可选。用法同上。
    • temperature 可选。值为一个介于0和2之间的数字,较大的值会增加输出内容的随机性,默认为1。
    • max_tokens 可选。值为一个整数,限制模型输出内容的最大token数,但仍受最大上下文长度限制。
    • stream 可选。值为一个布尔值,设置是否启用流式输出,默认为False,但本示例使用True。
    • stream_options 可选。包含一个键值对,其中include_usage对应一个布尔值,默认为False,设置为True后会在流式消息的末尾包含用量信息。

    基于上述内容,我们可以构建如下请求体:

    Python
    model = "deepseek-chat"
    user_input = ""
    system_prompt = "你是一位有用的助手,请尽可能准确地回答问题。"
    
    body = {
        "messages" : [
            {
                "role":"system",
                "content":system_prompt
            },
            {
                "role":"user",
                "content":user_input
            }
        ],
        "model":model,
        "frequency_penalty" : 0,
        "max_tokens" : 8192,
        "presence_penalty" : 0,
        "stream":True,
        "stream_options":{
            "include_usage":True
        },
        "temperature":1.1
    }

    基于得到的API key构建验证请求头。

    Python
    auth = {
      'Content-Type': 'application/json',
      'Accept': 'application/json',
      'Authorization': 'Bearer <yourapikey>'
    }

    发送POST请求,使用stream参数以启用流式传输。

    Python
    response = requests.post("https://api.deepseek.com/chat/completions", headers=auth, json=body, stream=True)

    接下来我们需要针对API的响应内容来编写对应的处理逻辑,首先来看看这样得到的response是什么。

    为便于阅读,以下内容已使用UTF-8解码。

    deepseek-chat模型:

    JSON
    data: {"id":"60e5f442-7b21-4ff4-b71b-c301219d5efe","object":"chat.completion.chunk","created":1761486961,"model":"deepseek-chat","system_fingerprint":"fp_ffc7281d48_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"role":"assistant","content":""},"logprobs":null,"finish_reason":null}],"usage":null}
    
    data: {"id":"60e5f442-7b21-4ff4-b71b-c301219d5efe","object":"chat.completion.chunk","created":1761486961,"model":"deepseek-chat","system_fingerprint":"fp_ffc7281d48_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"你好"},"logprobs":null,"finish_reason":null}],"usage":null}
    
    data: {"id":"60e5f442-7b21-4ff4-b71b-c301219d5efe","object":"chat.completion.chunk","created":1761486961,"model":"deepseek-chat","system_fingerprint":"fp_ffc7281d48_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"!"},"logprobs":null,"finish_reason":null}],"usage":null}
    
    //省略若干行……
    
    data: {"id":"60e5f442-7b21-4ff4-b71b-c301219d5efe","object":"chat.completion.chunk","created":1761486961,"model":"deepseek-chat","system_fingerprint":"fp_ffc7281d48_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"乐意"},"logprobs":null,"finish_reason":null}],"usage":null}
    
    data: {"id":"60e5f442-7b21-4ff4-b71b-c301219d5efe","object":"chat.completion.chunk","created":1761486961,"model":"deepseek-chat","system_fingerprint":"fp_ffc7281d48_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"陪伴"},"logprobs":null,"finish_reason":null}],"usage":null}
    
    data: {"id":"60e5f442-7b21-4ff4-b71b-c301219d5efe","object":"chat.completion.chunk","created":1761486961,"model":"deepseek-chat","system_fingerprint":"fp_ffc7281d48_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"你"},"logprobs":null,"finish_reason":null}],"usage":null}
    
    data: {"id":"60e5f442-7b21-4ff4-b71b-c301219d5efe","object":"chat.completion.chunk","created":1761486961,"model":"deepseek-chat","system_fingerprint":"fp_ffc7281d48_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"~"},"logprobs":null,"finish_reason":null}],"usage":null}
    
    data: {"id":"60e5f442-7b21-4ff4-b71b-c301219d5efe","object":"chat.completion.chunk","created":1761486961,"model":"deepseek-chat","system_fingerprint":"fp_ffc7281d48_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":""},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":17,"completion_tokens":31,"total_tokens":48,"prompt_tokens_details":{"cached_tokens":0},"prompt_cache_hit_tokens":0,"prompt_cache_miss_tokens":17}}
    
    data: [DONE]

    deepseek-reasoner模型:

    JSON
    data: {"id":"2f1b5eab-0abe-4b54-ad25-939800bfd230","object":"chat.completion.chunk","created":1761487153,"model":"deepseek-reasoner","system_fingerprint":"fp_ffc7281d48_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"role":"assistant","content":null,"reasoning_content":""},"logprobs":null,"finish_reason":null}],"usage":null}
    
    data: {"id":"2f1b5eab-0abe-4b54-ad25-939800bfd230","object":"chat.completion.chunk","created":1761487153,"model":"deepseek-reasoner","system_fingerprint":"fp_ffc7281d48_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"嗯"},"logprobs":null,"finish_reason":null}],"usage":null}
    
    data: {"id":"2f1b5eab-0abe-4b54-ad25-939800bfd230","object":"chat.completion.chunk","created":1761487153,"model":"deepseek-reasoner","system_fingerprint":"fp_ffc7281d48_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":","},"logprobs":null,"finish_reason":null}],"usage":null}
    
    data: {"id":"2f1b5eab-0abe-4b54-ad25-939800bfd230","object":"chat.completion.chunk","created":1761487153,"model":"deepseek-reasoner","system_fingerprint":"fp_ffc7281d48_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"用户"},"logprobs":null,"finish_reason":null}],"usage":null}
    
    //省略若干行……
    
    data: {"id":"2f1b5eab-0abe-4b54-ad25-939800bfd230","object":"chat.completion.chunk","created":1761487153,"model":"deepseek-reasoner","system_fingerprint":"fp_ffc7281d48_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"变得"},"logprobs":null,"finish_reason":null}],"usage":null}
    
    data: {"id":"2f1b5eab-0abe-4b54-ad25-939800bfd230","object":"chat.completion.chunk","created":1761487153,"model":"deepseek-reasoner","system_fingerprint":"fp_ffc7281d48_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"冗"},"logprobs":null,"finish_reason":null}],"usage":null}
    
    data: {"id":"2f1b5eab-0abe-4b54-ad25-939800bfd230","object":"chat.completion.chunk","created":1761487153,"model":"deepseek-reasoner","system_fingerprint":"fp_ffc7281d48_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"长"},"logprobs":null,"finish_reason":null}],"usage":null}
    
    data: {"id":"2f1b5eab-0abe-4b54-ad25-939800bfd230","object":"chat.completion.chunk","created":1761487153,"model":"deepseek-reasoner","system_fingerprint":"fp_ffc7281d48_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":null,"reasoning_content":"。"},"logprobs":null,"finish_reason":null}],"usage":null}
    
    data: {"id":"2f1b5eab-0abe-4b54-ad25-939800bfd230","object":"chat.completion.chunk","created":1761487153,"model":"deepseek-reasoner","system_fingerprint":"fp_ffc7281d48_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"你好","reasoning_content":null},"logprobs":null,"finish_reason":null}],"usage":null}
    
    data: {"id":"2f1b5eab-0abe-4b54-ad25-939800bfd230","object":"chat.completion.chunk","created":1761487153,"model":"deepseek-reasoner","system_fingerprint":"fp_ffc7281d48_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"!","reasoning_content":null},"logprobs":null,"finish_reason":null}],"usage":null}
    
    data: {"id":"2f1b5eab-0abe-4b54-ad25-939800bfd230","object":"chat.completion.chunk","created":1761487153,"model":"deepseek-reasoner","system_fingerprint":"fp_ffc7281d48_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"很高兴","reasoning_content":null},"logprobs":null,"finish_reason":null}],"usage":null}
    
    //省略若干行……
    
    data: {"id":"2f1b5eab-0abe-4b54-ad25-939800bfd230","object":"chat.completion.chunk","created":1761487153,"model":"deepseek-reasoner","system_fingerprint":"fp_ffc7281d48_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"解答","reasoning_content":null},"logprobs":null,"finish_reason":null}],"usage":null}
    
    data: {"id":"2f1b5eab-0abe-4b54-ad25-939800bfd230","object":"chat.completion.chunk","created":1761487153,"model":"deepseek-reasoner","system_fingerprint":"fp_ffc7281d48_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"的吗","reasoning_content":null},"logprobs":null,"finish_reason":null}],"usage":null}
    
    data: {"id":"2f1b5eab-0abe-4b54-ad25-939800bfd230","object":"chat.completion.chunk","created":1761487153,"model":"deepseek-reasoner","system_fingerprint":"fp_ffc7281d48_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"?","reasoning_content":null},"logprobs":null,"finish_reason":null}],"usage":null}
    
    data: {"id":"2f1b5eab-0abe-4b54-ad25-939800bfd230","object":"chat.completion.chunk","created":1761487153,"model":"deepseek-reasoner","system_fingerprint":"fp_ffc7281d48_prod0820_fp8_kvcache","choices":[{"index":0,"delta":{"content":"","reasoning_content":null},"logprobs":null,"finish_reason":"stop"}],"usage":{"prompt_tokens":17,"completion_tokens":76,"total_tokens":93,"prompt_tokens_details":{"cached_tokens":0},"completion_tokens_details":{"reasoning_tokens":62},"prompt_cache_hit_tokens":0,"prompt_cache_miss_tokens":17}}
    
    data: [DONE]

    可以看到,解码后的内容由空行和若干以data开头的行组成,主体内容为JSON格式。响应结束时,API会发送一个带有用量的信息,并紧接着发送结束标志。可以注意到,deepseek-reasoner模型会将思维链和最终结果分别包含在不同的键中输出。

    将JSON部分格式化后,我们可以清晰地看到响应行的结构。

    普通输出:

    JSON
    {
      "id": "60e5f442-7b21-4ff4-b71b-c301219d5efe",
      "object": "chat.completion.chunk",
      "created": 1761486961,
      "model": "deepseek-chat",
      "system_fingerprint": "fp_ffc7281d48_prod0820_fp8_kvcache",
      "choices": [
        {
          "index": 0,
          "delta": {
            "content": "你好"
          },
          "logprobs": null,
          "finish_reason": null
        }
      ],
      "usage": null
    }

    思维链输出:

    JSON
    {
      "id": "2f1b5eab-0abe-4b54-ad25-939800bfd230",
      "object": "chat.completion.chunk",
      "created": 1761487153,
      "model": "deepseek-reasoner",
      "system_fingerprint": "fp_ffc7281d48_prod0820_fp8_kvcache",
      "choices": [
        {
          "index": 0,
          "delta": {
            "content": null,
            "reasoning_content": "嗯"
          },
          "logprobs": null,
          "finish_reason": null
        }
      ],
      "usage": null
    }

    用量信息(附带了本次响应的结束原因,stop表示正常结束):

    JSON
    {
      "id": "2f1b5eab-0abe-4b54-ad25-939800bfd230",
      "object": "chat.completion.chunk",
      "created": 1761487153,
      "model": "deepseek-reasoner",
      "system_fingerprint": "fp_ffc7281d48_prod0820_fp8_kvcache",
      "choices": [
        {
          "index": 0,
          "delta": {
            "content": "",
            "reasoning_content": null
          },
          "logprobs": null,
          "finish_reason": "stop"
        }
      ],
      "usage": {
        "prompt_tokens": 17,
        "completion_tokens": 76,
        "total_tokens": 93,
        "prompt_tokens_details": {
          "cached_tokens": 0
        },
        "completion_tokens_details": {
          "reasoning_tokens": 62
        },
        "prompt_cache_hit_tokens": 0,
        "prompt_cache_miss_tokens": 17
      }
    }

    基于以上了解,我们可以开始着手处理响应。

    Python
    for line in response.iter_lines():
    	if line: # 忽略空行
    		decoded_line = line.decode("utf-8") # 解码响应内容,正确显示中文等字符
    		if decoded_line == "data: [DONE]": # 识别结束标识
    			break
    		json_str = decoded_line[len("data: "):] # 通过字符串截取获得JSON部分
    		try:
    			chunk = json.loads(json_str)
    			if chunk["usage"]: # 识别用量信息
    				print(chunk["usage"])
    			choice = chunk["choices"][0] # 获得choice部分
    			if choice["finish_reason"] and choice["finish_reason"] != "stop": # 识别异常结束的情况
    				print(f"意外终止:{choice["finish_reason"]}")
    				break
    			delta = choice["delta"] # 获得delta部分
    			if delta["content"]: # 判断content是否存在
    				print(delta["content"], end="", flush=True) # 打印增量输出
    			if delta["reasoning_content"]: # 判断reasoning_content是否存在
    				print(delta["reasoning_content"], end="", flush=True) # 打印增量输出
    		except Exception as e:
    			print(f"\n无法解析数据:{e}")

    如此,我们便实现了基本的API访问,同时做到了兼容不同的模型。但是,这样的输出对用户不够友好,我们可以尝试为以上实现增加更多功能,并借助Visual Studio Code实现Markdown语法和数学公式的实时渲染。

    Python
    import requests
    import datetime
    import json
    
    auth = {
      'Content-Type': 'application/json',
      'Accept': 'application/json',
      'Authorization': 'Bearer <yourapikey>'
    }
    
    output_path = "<output.md>"
    model = "deepseek-chat"
    user_input = r"""
    
    """
    system_prompt = "你是一位有用的助手,请尽可能准确地回答问题。"
    
    content_start = False
    content_started = False
    response_text = ""
    
    def reasoning(): # 判断并返回思维链内容
        if "reasoning_content" in delta:
            return delta["reasoning_content"]
        else:
            return False
    
    body = {
        "messages" : [
            {
                "role":"system",
                "content":system_prompt
            },
            {
                "role":"user",
                "content":user_input
            }
        ],
        "model":model,
        "frequency_penalty" : 0,
        "max_tokens" : 8192,
        "presence_penalty" : 0,
        "stream":True,
        "stream_options":{
            "include_usage":True
        },
        "temperature":1.1
    }
    
    response = requests.post("https://api.deepseek.com/chat/completions", headers=auth, json=body, stream=True)
    
    if response.status_code != 200: # 仅当请求成功时执行后续逻辑
        print(f"请求失败:{response.text}")
        exit()
    else:
        with open(output_path, 'w') as file: # 清空输出用文件
            pass
    
    now = datetime.datetime.now()
    time_str = now.strftime("%Y-%m-%d %H-%M-%S") # 获取时间戳
    
    with open(output_path, 'a', encoding='utf-8') as file:
        file.write("\n___\n"+time_str+"\n\n"+f"用户输入:\n```{user_input}```\n") # 在输出文件中写入用户时间戳和输入内容
    
    # 根据模型的不同输出提示前缀
    if model == "deepseek-reasoner":
        response_text += "Reasoning content:\n"
        print("Reasoning content:")
        with open(output_path, 'a' ,encoding='utf-8') as file:
            file.write("\n\nReasoning content:\n\n")
    elif model == "deepseek-chat":
        response_text += "Content:\n"
        print("Content:")
        with open(output_path, 'a' ,encoding='utf-8') as file:
            file.write("\n\nContent:\n\n")
    
    for line in response.iter_lines():
        if line:
            decoded_line = line.decode("utf-8")
            if decoded_line == "data: [DONE]":
                price = int(usage["prompt_cache_hit_tokens"]) * 0.0000002 + int(usage["prompt_cache_miss_tokens"]) * 0.000002 + int(usage["completion_tokens"]) * 0.000003
                usage_info = f"\n\nUsage: 输入: {usage["prompt_tokens"]}, 输出: {usage["completion_tokens"]}, 全部: {usage["total_tokens"]}, 缓存命中: {usage["prompt_cache_hit_tokens"]}, 消耗:{price:.6f}" # 根据定价计算本次用量,具体参数请以当前API价格为准
                print(usage_info)
                response_text += usage_info
                break
            json_str = decoded_line[len("data: "):]
            try:
                chunk = json.loads(json_str)
                if chunk["usage"]:
                    usage = chunk["usage"]
                choice = chunk["choices"][0]
                if choice["finish_reason"] and choice["finish_reason"] != "stop":
                    print(f"意外终止:{choice["finish_reason"]}")
                    break
                delta = choice["delta"]
                if delta["content"] and not reasoning(): # 在推理模式下标记正式输出开始
                    content_start = True
                if content_start == True and content_started == False and model == "deepseek-reasoner": # 仅当思维链结束正式输出开始时执行
                    print("\n\nContent:")
                    response_text += "\n\nContent:\n"
                    with open(output_path, 'a' ,encoding='utf-8') as file:
                        file.write("\n\nContent:\n")
                    content_started = True
                if delta["content"]:
                    print(delta["content"], end="", flush=True)
                    with open(output_path, 'a', encoding='utf-8') as file:
                        file.write(delta["content"])
                    response_text += delta["content"]
                if reasoning():
                    print(reasoning(), end="", flush=True)
                    with open(output_path, 'a', encoding='utf-8') as file:
                        file.write(reasoning())
                    response_text += reasoning()
            except Exception as e:
                print(f"\n无法解析数据:{e}")
    
    with open(output_path, 'r+', encoding='utf-8') as file: # 将输出中的LaTeX公式替换为vscode可识别的类型
        read_temp = file.read()
        write_temp = read_temp.replace("\\(", "$")
        write_temp = write_temp.replace("\\)", "$")
        write_temp = write_temp.replace("\\[", "$$")
        write_temp = write_temp.replace("\\]", "$$")
    with open(output_path, 'w', encoding='utf-8') as file:
        file.write(write_temp)
    
    with open("<pathtoyour>\\output_achieves\\"+time_str+".md","w",encoding="utf-8") as f: # 将此次对话写入存档文件
        response_text = response_text.replace("\\(", "$")
        response_text = response_text.replace("\\)", "$")
        response_text = response_text.replace("\\[", "$$")
        response_text = response_text.replace("\\]", "$$")
        f.write(f"用户输入:\n```{user_input}```\n{response_text}")
    
    print(f"\n生成{time_str}.md")

    效果如下:

    至此,我们便获得了一个稳定好用的DeepSeek访问实现。

  • C语言转换说明及其修饰符——格式化输入输出

    printf()函数

    C语言中的printf函数使用转换说明(Conversion Specifier)来格式化输出。一个完整的格式控制符通常以百分号 % 开头,后跟一个或多个字符来指定输出的类型和格式。

    其基本结构可以理解为:%[标志][宽度][.精度][长度修饰符]转换说明符。前四个可选参数统称为转换说明修饰符。

    转换说明符

    用于指定输出数据类型。可单独使用。

    转换说明符含义
    d输出有符号十进制整数,i与其等价。单独使用时参数类型应为int
    u输出无符号十进制整数。单独使用时参数类型应为unsigned int
    f输出十进制单精度/双精度浮点数。默认精确到小数点后六位。单独使用时参数类型应为floatdouble
    a输出用p记数法表示的十六进制浮点数。若改为A则将输出内容中的小写字母替换为大写。单独使用时参数类型应为floatdouble
    g根据值的不同,自动判断是否使用科学计数法。科学计数法默认在指数小于-4时使用;若指定精度,也会在指数大于或等于精度时使用。若改为G则将输出内容中的e替换为E。
    单独使用时参数类型应为floatdouble
    e输出科学计数法形式的浮点数。若改为E则将输出内容中的e替换为E。
    o输出无符号八进制整数,不含前缀。单独使用时参数类型应为unsigned int,若传入有符号整数则输出其八进制补码。
    x输出无符号十六进制整数,不含前缀。若改为X则将输出内容中的小写字母替换为大写。单独使用时参数类型应为unsigned int,若传入有符号整数则输出其十六进制补码。
    c输出一个字符。参数应为int,在使用时被转换为unsigned char
    s输出一个字符串。参数应为指向数组的指针。
    p输出指针地址。输出内容为十六进制数,包含前缀。

    标志

    用于控制输出的对齐、前缀等。需要紧跟在 % 后面使用。

    标志字符含义
    -左对齐,在指定字段宽度的右侧填充空格。
    +为数据显示正负号,对unsigned型不生效。
    如果输出值为非负数且没有符号则添加空格。在同时指定+标志时被忽略。
    #对于八进制和十六进制分别添加0和0x/X的前缀;对于小数则强制输出小数点,即使后面没有数字。
    0使用0而不是空格进行填充。如果指定了左对齐标志或对整数指定精度则被忽略。

    字符宽度

    一个数字,位于标志字符之后,指定输出的最小字符宽度。如果输出的字符数小于此宽度,则用空格(若指定了0标志则用0)填充。如果输出的字符超过此宽度则不会生效。

    数据精度

    以一个点号开头,位于字符宽度之后。当输出的数据类型为整数(转换说明字符为d, i, o, u, x, X)时,指定要显示的最小数字位数,不足时在前面补0。当输出的数据类型为浮点数(转换说明字符为f, F, e, E, a, A)时,指定小数点后的位数,不足在后面补0。当转换说明字符为gG时,指定保留的有效数字位数。当输出的数据类型为字符串时(转换说明字符为s),指定将会输出的最大字符数。

    特别地,若将字符宽度和数据精度用*代替,则会采用参数列表中在输出内容之前的两项内容来代替。

    长度修饰符

    位于数据精度之后,转换说明符之前。用于指定输出数据的大小以便处理不同长度的数据。

    长度修饰符含义
    h表示shortunsigned short类型。适用于所有整数转换说明符。
    hh表示signed charunsigned char类型。适用于所有整数转换说明符。
    l表示longunsigned long。适用于所有整数转换说明符。
    ll表示long longunsigned long long。适用于所有整数转换说明符。
    L表示long double。适用于所有浮点转换说明符。
    z表示size_tsizeof运算符返回)。
    t表示ptrdiff_t(指针相减返回)。

    示例

    接下来看一些使用例:

    C
    // 单独使用转换说明符
    #include <stdio.h>
    int main(void)
    {
    	int a = 87;
    	unsigned int b = 87;
    	float c = 3.14;
    	double d = 2.71;
    	float e = 1919810;
    	unsigned int f = 87;
    	unsigned int g = 114514;
    	int h = 65;
    	char i[] = "Hello World.";
    	long *j = &a;
    
    	printf("%d\n", a);
    	printf("%u\n", b);
    	printf("%f %f\n", c, d);
    	printf("%a %A %g %G\n", c, c, c * 0.00001, e);
    	printf("%e\n", e);
    	printf("%o\n", f);
    	printf("%x %X\n", g, g);
    	printf("%c\n", h);
    	printf("%s\n", i);
    	printf("%p", (void *)j);
    	return 0;
    }

    输出为:

    87
    87
    3.140000 2.710000
    0x1.91eb860000000p+1 0X1.91EB860000000P+1 3.14e-05 1.91981E+06
    1.919810e+06
    127
    1bf52 1BF52
    A
    Hello World.
    0000008DB1B7F644
    C
    // 使用字符宽度和标志
    #include <stdio.h>
    int main(void)
    {
    	char str[] = "Ciallo~";
    	int a = 87;
    	int b = -87;
    	int c = 114514;
    	float d = 10;
    
    	printf("★%-10s\n", str);
    	printf("★%+10d\n", a);
    	printf("★%+10d\n", b);
    	printf("★% -10d\n", a);
    	printf("★% -10d\n", b);
    	printf("★%#10o\n", c);
    	printf("★%#10x\n", c);
    	printf("★%#10X\n", c);
    	printf("★%10.0f\n", d);
    	printf("★%#10.0f\n", d);
    	printf("★%010d★", a);
    	return 0;
    }

    输出为:

    ★Ciallo~   ★
    ★       +87★
    ★       -87★
    ★ 87       ★
    ★-87       ★
    ★   0337522★
    ★   0x1bf52★
    ★   0X1BF52★
    ★        10★
    ★       10.★
    ★0000000087★
    C
    // 使用数据精度
    #include <stdio.h>
    int main(void)
    {
    	short a = 10;
    	unsigned short b = 65535;
    	signed char c = -128;
    	double d = 3.1415926;
    	double e = 12345.678;
    	double f = 0.0000000123;
    	double g = 1000000000000000.0;
    
    	printf("%.5d\n", a);
    	printf("%.3d\n", b);
    	printf("%.5d\n", c);
    	printf("%.3f\n", d);
    	printf("%.10f\n", d);
    	printf("%.3G\n", d);
    	printf("%.5g\n", e);
    	printf("%.5G\n", f);
    	printf("%.6g", g);
    	return 0;
    }

    输出为

    00010
    65535
    -00128
    3.142
    3.1415926000
    3.14
    12346
    1.23E-08
    1e+15
    C
    // 使用长度修饰符
    #include <stdio.h>
    int main(void)
    {
    	short a = 10;
    	unsigned short b = 65535;
    	signed char c = -128;
    	unsigned char d = 255;
    	long e = 2147483647;
    	unsigned long f = 4294967294;
    	long long g = 9223372036854775806;
    	unsigned long long h = 18446744073709551615;
    	long double i = 3.14159265358979;
    
    	printf("%hd\n", a);
    	printf("%hu\n", b);
    	printf("%hhd\n", c);
    	printf("%hhu\n", d);
    	printf("%ld\n", e);
    	printf("%lu\n", f);
    	printf("%lld\n", g);
    	printf("%llu\n", h);
    	printf("%.15Lf\n", i);
    	printf("%zd\n", sizeof h);
    	printf("%td", &b - &a);
    	return 0;
    }

    输出为:

    10
    65535
    -128
    255
    2147483647
    4294967294
    9223372036854775806
    18446744073709551615
    3.141592653589790
    8
    16

    接下来玩点花的:

    C
    // 大杂烩
    #include <stdio.h>
    int main(void)
    {
    	long double a = 3.1415926535;
    	unsigned long long b = 219845122340;
    	printf("★%+*.*llu\n", 20, 15, b);
    	printf("★% #020.0Lf\n", a);
    	printf("%%"); // 直接打印百分号
    	return 0;
    }

    输出为:

    ★     000219845122340★
    ★ 000000000000000003.★
    %

    scanf()函数

    scanf()作为处理输入的函数,其转换说明由转换说明符、抑制赋值标志、字符宽度和长度修饰符组成。scanf()函数所用的转换说明与printf()函数几乎相同,但对浮点类型和符号的处理略有差异。

    转换说明符

    转换说明符含义
    d把输入解释为有符号十进制整数,i与其等价。单独使用时地址参数对应的类型应为int
    u把输入解释为无符号十进制整数。单独使用时地址参数对应的类型应为unsigned int
    f,e,a,g把输入解释为浮点数。单独使用时地址参数对应的类型应为float
    o把输入解释为有符号八进制整数。单独使用时地址参数对应的类型应为int
    x把输入解释为有符号十六进制整数。若改为X则适用于输入数字中的字母为大写的情形。单独使用时地址参数对应的类型应为int
    c把输入解释为一个字符,不会忽略空白字符。地址参数对应的类型应为char
    s把输入解释为字符串,遇到空白字符即停止。参数应为指向数组的指针。
    p把输入解释为指针地址。参数应为一个指针的地址。

    抑制赋值

    *表示,放在%后,若使用此标志,则会在读取输入时跳过对应的内容。

    C
    // 使用抑制赋值标志
    #include <stdio.h>
    int main(void)
    {
    	int a;
    	scanf("%*d %*d %d", a);
    	return 0;
    }

    可接受如下输入:

    10 12 15

    a会被赋值为15。

    字符宽度

    一个数字,位于长度修饰符前,表示输入的最大字符宽度。对输入的读取会在达到此宽度或遇到空白字符时停止。

    长度修饰符

    位于字符宽度之后,转换说明符之前。

    长度修饰符含义
    h表示shortunsigned short类型。适用于所有整数转换说明符。
    hh表示signed charunsigned char类型。适用于所有整数转换说明符。
    l用于整数转换说明符时表示longunsigned long,用于浮点转换说明符时表示double
    ll表示long longunsigned long long。适用于所有整数转换说明符。
    L表示long double。适用于所有浮点转换说明符。
    z表示size_tsizeof运算符返回)。
    t表示ptrdiff_t(指针相减返回)。