C语言相关

详解 const uint8_t * const* 类型:

const uint8_t * const* 是 C 语言中的一种复杂指针类型,用于指向指向常量的指针。让我们详细拆解这个类型:

类型拆解

  1. const uint8_t:

    • uint8_t 是无符号的 8 位整数类型,通常用于表示一个字节。
    • const 关键字在 uint8_t 前面,表示这个 uint8_t 类型的数据是常量,即在指针指向的数据位置上的值不能被修改。
  2. const uint8_t *:

    • 这是一个指向 const uint8_t 类型的指针。
    • 它表示你可以通过这个指针访问 const uint8_t 类型的数据,但不能修改这些数据。
  3. const uint8_t * const:

    • 这是一个指向 const uint8_t 的指针,但这个指针本身也是常量。
    • 也就是说,你不能通过这个指针去修改指针的值(即你不能改变指针所指向的位置),但你依然可以读取它所指向的数据。
  4. const uint8_t * const*:

    • 这是一个指向 const uint8_t * const 的指针,也就是一个指向常量指针的指针。
    • 这意味着你有一个指针,它指向另一个指针,而这个被指向的指针是 const 的(即你不能修改它指向的位置),并且这个被指向的位置的数据也是 const 的(即你不能修改这些数据)。

用途和示例

这个类型经常用于表示一个指针数组,其中每个指针指向一个常量数据,并且这些指针本身也是不可修改的。它在处理图像数据时非常有用,因为图像数据通常是由多个平面组成的,每个平面的数据可能需要被读取但不应被修改。

示例

假设我们有如下的数据:

1
2
3
4
5
6
  const uint8_t *plane1;  // 指向第一个平面的数据,数据不能被修改
  const uint8_t *plane2;  // 指向第二个平面的数据,数据不能被修改

  const uint8_t * const planes[] = { plane1, plane2 };  // 指针数组,数组中的每个指针都指向常量数据

  const uint8_t * const * planes_ptr = planes;  // 指向指针数组的指针,不能修改指针数组中的指针

在这个示例中:

  • planes 是一个指针数组,其中每个元素都是指向常量数据的指针。
  • planes_ptr 是一个指向这个指针数组的指针,你不能通过 planes_ptr 修改 planes 中的任何指针值,也不能通过这些指针修改数据本身。

具体应用

在 FFmpeg 的 sws_scale 函数中,const uint8_t * const* 用于指向图像的多个平面数据。每个平面都是不可修改的,这保证了图像数据在转换过程中不会被意外改变。同时,const uint8_t * const* 确保你不能改变指向这些平面的指针数组的结构。这种方式增加了代码的安全性和可维护性。

C语言打印格式%x与%#x有什么区别

在 C 语言中,%x 和 %#x 是 printf 函数中的格式说明符,用于打印整数值的十六进制表示。它们之间的主要区别在于是否显示前缀:

  1. %x:

    • 打印整数的十六进制表示,不带任何前缀。
    • 输出的是一个十六进制数,只使用小写字母(a 到 f)。
    • 示例:

      1
      2
      
      int num = 255;
      printf("%x\n", num);  // 输出 "ff"
      
  2. %#x:

    • 在十六进制表示前加上 0x 前缀。
    • 也输出小写字母(a 到 f)。
    • 示例:

      1
      2
      
      int num = 255;
      printf("%#x\n", num);  // 输出 "0xff"
      

举例说明

 1
 2
 3
 4
 5
 6
 7
 8
 9
10
11
12
13
  #include <stdio.h>

  int main() {
	  int num = 255;

	  // 使用 %x
	  printf("Using %%x: %x\n", num);  // 输出: Using %x: ff

	  // 使用 %#x
	  printf("Using %%#x: %#x\n", num);  // 输出: Using %#x: 0xff

	  return 0;
  }

总结

  • "%x" 输出的是纯十六进制数值,不带前缀。
  • "%#x" 在十六进制数值前加上 0x 前缀,标识这是一个十六进制数。

从终端输入字符串,提取字符串中的ASCII值 - ChatGPT

 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
32
33
34
35
36
37
38
39
40
#include <stdio.h>
#include <stdlib.h>

int main(void) {
    unsigned char *arr = NULL;  // 初始化为 NULL
    unsigned int arr_num = 0;   // 当前输入字符的数量
    unsigned int capacity = 1;   // 初始容量设置为 1
    int ch;

    // 为 arr 分配初始内存
    arr = (unsigned char *)malloc(capacity * sizeof(unsigned char));

    printf("请输入包含任意大小数字的任意长度的字符串 (按 Enter 键结束):\n");

    while ((ch = getchar()) != '\n') {
        // 检查是否需要扩展数组
        if (arr_num >= capacity) {
            capacity *= 2; // 扩大容量为原来的两倍
            unsigned char *temp = realloc(arr, capacity * sizeof(unsigned char));
            arr = temp; // 更新 arr 指针
        }
        arr[arr_num++] = (unsigned char)ch; // 将读取的字符存储到数组
    }

    // 为字符串结束符增加空间
    unsigned char *final_arr = realloc(arr, (arr_num + 1) * sizeof(unsigned char));    
    arr = final_arr;
    arr[arr_num] = '\0'; // 添加字符串结束符

    // 输出读取到的字符串
    printf("您输入的字符串是: %s\n", arr);

    // 打印每个字符及其 ASCII 值
    for (unsigned int i = 0; i < arr_num; i++) {
        printf("arr[%d] = %c\n", i, arr[i]);
    }

    free(arr); // 释放动态分配的内存
    return 0;
}

代码说明

动态内存分配: 使用 malloc 为 arr 分配初始内存,之后根据需要使用 realloc 扩展内存。

字符读取: 使用 getchar() 从标准输入逐个读取字符,直到遇到换行符 \n。

容量管理: 每当字符数量达到当前容量时,容量翻倍,以合理利用内存。

字符串结束符: 在读取完成后,为字符串添加结束符 \0,确保可以正确作为字符串处理。

内存释放: 程序结尾处释放分配的内存,以避免内存泄漏。

使用说明

编译并运行程序,输入一段字符并按回车键结束。 程序会输出您输入的字符串和每个字符的 ASCII 值。

提取字符串中的数字 - ChatGPT

 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
32
33
34
35
36
37
38
39
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void) {
    const char *RecvBuf = "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 32 33 34 35 36 37 38 39 40 41 42 43 44 45 46 47 48 49 50 51 52 53 54 55 56 57 58 59 60 61 62 63 64 65 66 67 68 69 70 71 72 73 74 75 76 77 78 79 80 81 82 83 84 85 86 87 88 89 90 91 92 93 94 95 96 97 98 99 100 101 102 103 104 105 106 107 108 109 110 111 112 113 114 115 116 117 118 119 120 121 122 123 124 125 126 127 128 129 130 131 132 133 134 135 136 137 138 139 140 141 142 143 144 145 146 147 148 149 150 151 152 153 154 155 156 157 158 159 160 161 162 163 164 165 166 167 168 169 170 171 172 173 174 175 176 177 178 179 180 181 182 183 184 185 186 187 188 189 190 191 192 193 194 195 196 197 198 199 200 201 202 203 204 205 206 207 208 209 210 211 212 213 214 215 216 217 218 219 220 221 222 223 224 225 226 227 228 229 230 231 232 233 234 235 236 237 238 239 240 241 242 243 244 245 246 247 248 249 250 251 252 253 254 255 256"; // 输入字符串

    char **buf_test = NULL; // 指向字符串指针数组
    int count = 0; // 计数器

    // 创建一个临时字符串以避免修改原始字符串
    char *temp = (char *)malloc(strlen(RecvBuf) + 1);
    strcpy(temp, RecvBuf); // 复制输入字符串到临时字符串

    // 使用 strtok 提取每个数字
    char *token = strtok(temp, " ");
    while (token != NULL) {
        // 动态增加指针数组大小
        char **new_buf_test = (char **)realloc(buf_test, (count + 1) * sizeof(char *));
        buf_test = new_buf_test;

        // 为当前数字分配内存并复制
        buf_test[count] = (char *)malloc(strlen(token) + 1);
        strcpy(buf_test[count], token); // 复制字符串到新分配的内存

        count++;
        token = strtok(NULL, " ");
    }

    // 输出提取的数字
    for (int i = 0; i < count; i++) {
        printf("buf_test[%d] = %s\n", i, buf_test[i]);
        free(buf_test[i]); // 释放每个字符串的内存
    }

    free(buf_test); // 释放指针数组的内存
    free(temp); // 释放临时字符串的内存
    return 0;
}

关键点

动态指针数组: 使用 char **buf_test 来存储提取的数字,每次提取后动态分配内存。 内存管理: 使用 malloc 和 realloc 进行动态内存分配,确保在失败时释放已分配的内存。 字符串操作: 使用 strtok 函数提取字符串,并用 strcpy 复制到新分配的内存中。

提取字符串中的正数、浮点数 - ChatGPT

 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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
54
55
56
57
58
59
60
61
62
63
64
65
66
67
68
69
70
71
72
73
74
75
76
77
78
79
#include <stdio.h>
#include <ctype.h>

// 函数声明
void extractNumbers(const char *inputString);

int main() {
    const char *inputString = "1 -2 3.5 -4.7 5 6 -0.1 7.0";
    extractNumbers(inputString);
    return 0;
}

// 提取数字的函数
void extractNumbers(const char *inputString) {
    double num = 0.0;
    int foundNumber = 0;  // 标志是否找到了数字
    int isNegative = 0;   // 标志是否为负数
    int hasDecimal = 0;   // 标志是否有小数部分

    while (*inputString) {
        // 跳过空格
        while (isspace(*inputString)) {
            inputString++;
        }

        // 检查正负号
        if (*inputString == '-') {
            isNegative = 1;
            inputString++;
        } else if (*inputString == '+') {
            inputString++; // 忽略正号
        }

        // 提取数字部分
        num = 0.0;
        hasDecimal = 0;
        double decimalPlace = 1.0;

        while (isdigit(*inputString) || *inputString == '.') {
            if (*inputString == '.') {
                hasDecimal = 1;
                inputString++;
                continue;
            }

            if (hasDecimal) {
                decimalPlace *= 10.0; // 更新小数位
                num = num + (*inputString - '0') / decimalPlace; // 加入小数部分
            } else {
                num = num * 10 + (*inputString - '0'); // 加入整数部分
            }
            inputString++;
        }

        // 应用符号
        if (isNegative) {
            num = -num;
            isNegative = 0; // 重置标志
        }

        // 判断并打印结果
        if (hasDecimal) {
            printf("提取的浮点数是: %.2f\n", num);
        } else {
            printf("提取的整数是: %d\n", (int)num);
        }

        foundNumber = 1;  // 找到数字

        // 重置状态
        while (isspace(*inputString)) {
            inputString++; // 跳过空格
        }
    }

    if (!foundNumber) {
        printf("没有找到任何数字。\n");
    }
}

代码说明

主函数:

  • 定义了输入字符串 inputString,并调用 extractNumbers 函数。

extractNumbers 函数:

  • 使用 double 类型来存储提取的数值,以便处理浮点数。
  • 使用 isNegative 标志来判断数字是否为负数。
  • 使用 hasDecimal 标志来判断是否有小数部分。
  • 遍历字符串时,首先跳过空格,然后检查正负号。
  • 提取数字部分,包括整数和小数:

    • 如果遇到小数点,更新 hasDecimal 标志,并在后续循环中处理小数部分。
  • 输出提取的数字,区分整数和浮点数。

示例输出

运行上述代码时,输出将会显示提取的所有数字,包括整数和浮点数:

1
2
3
4
5
6
7
8
提取的整数是: 1
提取的整数是: -2
提取的浮点数是: 3.50
提取的浮点数是: -4.70
提取的整数是: 5
提取的整数是: 6
提取的浮点数是: -0.10
提取的浮点数是: 7.00

这种实现能够有效提取出字符串中的所有整数和浮点数,并且考虑了正负号。

提取指定大小字符串中的整数 - ChatGPT

代码

 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
32
33
34
35
36
37
38
39
40
41
42
43
44
45
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

unsigned int *buf1 = NULL;
size_t buf1_len = 0;

int convert_character(unsigned char *str1, size_t str1_len , unsigned int *str2);

int main(int argc, char *aragv[]) {
	int i = 0;

	buf1 = malloc(15 * sizeof(unsigned int));
	unsigned char *str = (unsigned char *)"1 2 3 4 5 6 7 8 9 10 11 12 13 14";
	size_t str_len = strlen((char *)str);

	convert_character(str, str_len, buf1);

	/* 输出转换结果 */
	for (i = 0; i < buf1_len; i++) {
		printf("%d: buf1[%d] = %u\n", __LINE__, i, buf1[i]);
	}
	
	free(buf1);

	return 0;
}

int convert_character(unsigned char *str1, size_t str1_len , unsigned int *str2) {
	int i = 0, j = 0;	

	for (i = 0; i < str1_len; i++) {
		if (str1[i] == ' ') continue; /* 跳过空格 */

		int num = 0;
		while(i < str1_len && str1[i] != ' ') {
			num = num * 10 + (str1[i] - '0');
			i++;
		}
		str2[j++] = num;
	}
	buf1_len = j;

	return 0;
}

这段代码的主要功能是将一个包含空格分隔数字的字符串转换为无符号整数数组,并输出这些整数。下面是对代码功能和结构的详细分析:

代码功能分析

  1. 全局变量:

    • unsigned int *buf1:指向动态分配的无符号整数数组,用于保存转换后的结果。
    • size_t buf1_len:保存转换后数组的长度。
  2. 主函数 (main):

    • 定义了一个指向 unsigned char 的字符串 str,其中包含空格分隔的数字。
    • 使用 malloc 动态分配了一个大小为 15 的 unsigned int 数组,以便存储转换后的数字。
    • 调用 convert_character 函数,将字符串 str 和它的长度 str_len 传递给该函数以进行转换。
    • 遍历 buf1 数组并打印每个无符号整数及其索引。
    • 最后释放动态分配的内存。
  3. 转换函数 (convert_character):

    • 接受输入字符串 str1 和其长度 str1_len,以及用于存储输出结果的数组 str2。
    • 在循环中,跳过空格并逐个字符读取数字:

      • 将字符转换为整数(通过将字符减去 '0')并累加到 num 中。
      • 当遇到空格或字符串结束时,将解析得到的整数存入 str2 数组。
    • 更新全局变量 buf1_len,指示转换后的数字数量。

重要细节

  • 内存分配:使用 malloc 为 buf1 分配内存,但没有检查分配结果是否成功,可能在内存不足时导致未定义行为。
  • 全局变量的使用:buf1_len 更新在 convert_character 函数中,可能导致可读性降低,因为它在函数外部使用。
  • 输出格式:在输出时使用 __LINE__,这会显示当前行号,有助于调试,但在实际应用中可能不需要。
  • 错误处理:缺少对输入数据的有效性检查(例如,确保输入格式正确且不超过预期的数字数量)。

总结

总体而言,这段代码实现了从一个以空格分隔的数字字符串到无符号整数数组的简单转换功能,并打印出结果。但在实际应用中,应该加入更多的错误处理和边界检查,以提高健壮性和可读性。

Licensed under CC BY-NC-SA 4.0