Appearance
数据类型
C语言提供了丰富的数据类型,包括基本数据类型、枚举类型、void类型和派生类型。本章将详细介绍C语言的数据类型。
数据类型分类
c
/*
* C语言数据类型分类
*
* 基本类型:
* - 整型:char, short, int, long, long long
* - 浮点型:float, double, long double
*
* 枚举类型:
* - enum
*
* void类型:
* - void
*
* 派生类型:
* - 指针类型
* - 数组类型
* - 结构体类型
* - 联合体类型
* - 函数类型
*/整型
整型类型
c
/*
* 整型类型及其大小
*/
#include <stdio.h>
#include <limits.h> /* 整型限制 */
int main(void)
{
/* char 类型 */
char c = 'A';
unsigned char uc = 255;
signed char sc = -128;
printf("=== char 类型 ===\n");
printf("char 大小: %zu 字节\n", sizeof(char));
printf("char 范围: %d 到 %d\n", CHAR_MIN, CHAR_MAX);
printf("unsigned char 范围: 0 到 %d\n", UCHAR_MAX);
/* short 类型 */
short s = 1000;
unsigned short us = 65535;
printf("\n=== short 类型 ===\n");
printf("short 大小: %zu 字节\n", sizeof(short));
printf("short 范围: %d 到 %d\n", SHRT_MIN, SHRT_MAX);
printf("unsigned short 范围: 0 到 %u\n", USHRT_MAX);
/* int 类型 */
int i = 100000;
unsigned int ui = 4294967295U;
printf("\n=== int 类型 ===\n");
printf("int 大小: %zu 字节\n", sizeof(int));
printf("int 范围: %d 到 %d\n", INT_MIN, INT_MAX);
printf("unsigned int 范围: 0 到 %u\n", UINT_MAX);
/* long 类型 */
long l = 1000000L;
unsigned long ul = 4294967295UL;
printf("\n=== long 类型 ===\n");
printf("long 大小: %zu 字节\n", sizeof(long));
printf("long 范围: %ld 到 %ld\n", LONG_MIN, LONG_MAX);
printf("unsigned long 范围: 0 到 %lu\n", ULONG_MAX);
/* long long 类型 (C99) */
long long ll = 9223372036854775807LL;
unsigned long long ull = 18446744073709551615ULL;
printf("\n=== long long 类型 ===\n");
printf("long long 大小: %zu 字节\n", sizeof(long long));
printf("long long 范围: %lld 到 %lld\n", LLONG_MIN, LLONG_MAX);
printf("unsigned long long 范围: 0 到 %llu\n", ULLONG_MAX);
return 0;
}整数字面量
c
/*
* 整数字面量(字面值)
*/
#include <stdio.h>
int main(void)
{
/* 十进制 */
int decimal = 100;
printf("十进制: %d\n", decimal);
/* 八进制(以0开头) */
int octal = 0144; /* 八进制144 = 十进制100 */
printf("八进制0144 = 十进制%d\n", octal);
/* 十六进制(以0x或0X开头) */
int hexadecimal = 0x64; /* 十六进制64 = 十进制100 */
printf("十六进制0x64 = 十进制%d\n", hexadecimal);
/* 二进制字面量 (C99不支持,GCC扩展) */
/* int binary = 0b1100100; */ /* 二进制1100100 = 十进制100 */
/* 类型后缀 */
int i = 100; /* int */
unsigned int ui = 100U; /* unsigned int */
long l = 100L; /* long */
unsigned long ul = 100UL; /* unsigned long */
long long ll = 100LL; /* long long */
printf("int: %d\n", i);
printf("unsigned: %u\n", ui);
printf("long: %ld\n", l);
printf("unsigned long: %lu\n", ul);
printf("long long: %lld\n", ll);
return 0;
}有符号与无符号
c
/*
* 有符号与无符号整数
*/
#include <stdio.h>
#include <limits.h>
int main(void)
{
/* 有符号整数可以表示正数和负数 */
signed int si = -100;
printf("有符号整数: %d\n", si);
/* 无符号整数只能表示非负数 */
unsigned int ui = 100;
printf("无符号整数: %u\n", ui);
/* 溢出行为 */
unsigned int max = UINT_MAX;
printf("无符号最大值: %u\n", max);
printf("最大值+1: %u\n", max + 1); /* 回绕到0 */
signed int smin = INT_MIN;
printf("有符号最小值: %d\n", smin);
printf("最小值-1: %d\n", smin - 1); /* 未定义行为或回绕 */
/* 混合运算 */
int a = -1;
unsigned int b = 1;
/* 注意:有符号和无符号比较时,有符号会被转换为无符号 */
if (a < b) {
printf("-1 < 1 (预期结果)\n");
} else {
printf("-1 >= 1 (意外结果!)\n"); /* 这会输出! */
}
/* 正确的比较方式 */
if ((int)a < (int)b) {
printf("强制转换后: -1 < 1\n");
}
return 0;
}浮点型
浮点类型
c
/*
* 浮点类型及其大小
*/
#include <stdio.h>
#include <float.h> /* 浮点型限制 */
int main(void)
{
/* float - 单精度浮点数 */
float f = 3.14159f;
printf("=== float 类型 ===\n");
printf("float 大小: %zu 字节\n", sizeof(float));
printf("float 最小正值: %e\n", FLT_MIN);
printf("float 最大值: %e\n", FLT_MAX);
printf("float 精度: %d 位\n", FLT_DIG);
printf("示例值: %.6f\n", f);
/* double - 双精度浮点数 */
double d = 3.14159265358979;
printf("\n=== double 类型 ===\n");
printf("double 大小: %zu 字节\n", sizeof(double));
printf("double 最小正值: %e\n", DBL_MIN);
printf("double 最大值: %e\n", DBL_MAX);
printf("double 精度: %d 位\n", DBL_DIG);
printf("示例值: %.15f\n", d);
/* long double - 扩展精度浮点数 */
long double ld = 3.14159265358979323846L;
printf("\n=== long double 类型 ===\n");
printf("long double 大小: %zu 字节\n", sizeof(long double));
printf("示例值: %.18Lf\n", ld);
return 0;
}浮点数字面量
c
/*
* 浮点数字面量
*/
#include <stdio.h>
int main(void)
{
/* 小数形式 */
double d1 = 3.14;
double d2 = .5; /* 0.5 */
double d3 = 5.; /* 5.0 */
printf("小数形式: %f, %f, %f\n", d1, d2, d3);
/* 指数形式(科学计数法) */
double e1 = 1.5e3; /* 1.5 × 10³ = 1500.0 */
double e2 = 2.5E-2; /* 2.5 × 10⁻² = 0.025 */
printf("指数形式: %f, %f\n", e1, e2);
printf("科学计数法: %e, %e\n", e1, e2);
/* 类型后缀 */
float f = 3.14f; /* float */
double d = 3.14; /* double(默认) */
long double ld = 3.14L; /* long double */
printf("float: %f\n", f);
printf("double: %f\n", d);
printf("long double: %Lf\n", ld);
/* 特殊浮点值 */
double positive_inf = 1.0 / 0.0;
double negative_inf = -1.0 / 0.0;
double nan_value = 0.0 / 0.0;
printf("\n特殊值:\n");
printf("正无穷: %f\n", positive_inf);
printf("负无穷: %f\n", negative_inf);
printf("非数(NaN): %f\n", nan_value);
return 0;
}浮点数精度问题
c
/*
* 浮点数精度问题
*/
#include <stdio.h>
#include <math.h>
int main(void)
{
/* 精度丢失 */
float f = 0.1f;
printf("0.1f 的实际值: %.20f\n", f);
/* 累加误差 */
float sum = 0.0f;
for (int i = 0; i < 10; i++) {
sum += 0.1f;
}
printf("10个0.1相加: %.20f\n", sum);
printf("是否等于1.0: %s\n", sum == 1.0f ? "是" : "否");
/* 正确的比较方式 */
float epsilon = 1e-6f;
if (fabs(sum - 1.0f) < epsilon) {
printf("使用误差比较: 近似等于1.0\n");
}
/* 不同精度的比较 */
float f_val = 0.123456789f;
double d_val = 0.123456789;
printf("\nfloat: %.15f\n", f_val);
printf("double: %.15f\n", d_val);
/* 避免精度问题的建议 */
printf("\n=== 避免精度问题的建议 ===\n");
printf("1. 使用double而不是float\n");
printf("2. 避免直接比较浮点数\n");
printf("3. 使用误差范围比较\n");
printf("4. 考虑使用整数运算\n");
return 0;
}字符型
char类型
c
/*
* char类型
*/
#include <stdio.h>
#include <limits.h>
int main(void)
{
/* char 可以存储单个字符 */
char ch1 = 'A';
char ch2 = 65; /* 65是'A'的ASCII码 */
char ch3 = '\x41'; /* 十六进制表示 */
char ch4 = '\101'; /* 八进制表示 */
printf("字符: %c, %c, %c, %c\n", ch1, ch2, ch3, ch4);
printf("ASCII码: %d, %d, %d, %d\n", ch1, ch2, ch3, ch4);
/* char 的本质是整数 */
char letter = 'A';
printf("\n字符运算:\n");
printf("'A' + 1 = %c\n", letter + 1); /* 'B' */
printf("'A' - 'A' + 'a' = %c\n", letter - 'A' + 'a'); /* 'a' */
/* 判断字符类型 */
char c = '5';
if (c >= '0' && c <= '9') {
printf("%c 是数字\n", c);
}
c = 'A';
if (c >= 'A' && c <= 'Z') {
printf("%c 是大写字母\n", c);
}
c = 'a';
if (c >= 'a' && c <= 'z') {
printf("%c 是小写字母\n", c);
}
/* signed char vs unsigned char */
signed char sc = -10;
unsigned char uc = 200;
printf("\nsigned char: %d\n", sc);
printf("unsigned char: %u\n", uc);
return 0;
}ASCII字符集
c
/*
* ASCII字符集
*/
#include <stdio.h>
int main(void)
{
printf("=== ASCII字符表 ===\n\n");
/* 控制字符 (0-31) */
printf("控制字符:\n");
printf("NULL: \\0 (ASCII 0)\n");
printf("换行: \\n (ASCII 10)\n");
printf("回车: \\r (ASCII 13)\n");
printf("制表: \\t (ASCII 9)\n");
/* 可打印字符 (32-126) */
printf("\n可打印字符:\n");
/* 数字 0-9 */
printf("数字: ");
for (char c = '0'; c <= '9'; c++) {
printf("%c ", c);
}
printf("\n");
/* 大写字母 A-Z */
printf("大写字母: ");
for (char c = 'A'; c <= 'Z'; c++) {
printf("%c ", c);
}
printf("\n");
/* 小写字母 a-z */
printf("小写字母: ");
for (char c = 'a'; c <= 'z'; c++) {
printf("%c ", c);
}
printf("\n");
/* 特殊字符 */
printf("\n特殊字符:\n");
printf("空格: ' ' (ASCII 32)\n");
printf("感叹号: '!' (ASCII 33)\n");
printf("双引号: '\"' (ASCII 34)\n");
printf("单引号: '\\'' (ASCII 39)\n");
printf("星号: '*' (ASCII 42)\n");
printf("加号: '+' (ASCII 43)\n");
printf("减号: '-' (ASCII 45)\n");
printf("斜杠: '/' (ASCII 47)\n");
/* 打印完整ASCII表 */
printf("\n完整ASCII表(可打印字符):\n");
for (int i = 32; i <= 126; i++) {
printf("%3d:%c ", i, (char)i);
if ((i - 31) % 10 == 0) {
printf("\n");
}
}
printf("\n");
return 0;
}void类型
c
/*
* void类型
*/
#include <stdio.h>
#include <stdlib.h>
/* void作为函数返回类型 */
void print_message(void)
{
printf("这是一个无返回值的函数\n");
}
/* void作为函数参数 */
int get_number(void) /* 明确表示函数不接受参数 */
{
return 42;
}
/* void指针可以指向任何类型 */
void print_value(void *ptr, char type)
{
switch (type) {
case 'i':
printf("整数: %d\n", *(int*)ptr);
break;
case 'f':
printf("浮点数: %f\n", *(float*)ptr);
break;
case 'c':
printf("字符: %c\n", *(char*)ptr);
break;
}
}
int main(void)
{
/* void作为函数返回类型 */
print_message();
/* void作为函数参数 */
int num = get_number();
printf("获取的数字: %d\n", num);
/* void指针 */
int i = 10;
float f = 3.14f;
char c = 'X';
void *ptr;
ptr = &i;
printf("void指针指向整数: %d\n", *(int*)ptr);
ptr = &f;
printf("void指针指向浮点数: %f\n", *(float*)ptr);
ptr = &c;
printf("void指针指向字符: %c\n", *(char*)ptr);
/* 使用void指针函数 */
print_value(&i, 'i');
print_value(&f, 'f');
print_value(&c, 'c');
return 0;
}类型转换
隐式类型转换
c
/*
* 隐式类型转换(自动转换)
*/
#include <stdio.h>
int main(void)
{
/* 整型提升 */
char c = 'A';
short s = 100;
/* char和short在运算时自动提升为int */
int result = c + s;
printf("char + short = int: %d\n", result);
/* 算术转换 */
int i = 5;
float f = 2.5f;
/* int和float运算时,int转换为float */
float f_result = i + f;
printf("int + float = float: %f\n", f_result);
/* 赋值转换 */
double d = 3.14159;
float f2 = d; /* double转换为float,可能丢失精度 */
int i2 = d; /* double转换为int,截断小数部分 */
printf("double -> float: %f\n", f2);
printf("double -> int: %d\n", i2);
/* 类型转换等级(从低到高) */
printf("\n类型转换等级:\n");
printf("int -> unsigned int -> long -> unsigned long -> ");
printf("long long -> unsigned long long -> float -> double -> long double\n");
return 0;
}显式类型转换
c
/*
* 显式类型转换(强制转换)
*/
#include <stdio.h>
int main(void)
{
/* 基本类型转换 */
double d = 3.7;
/* 强制转换为int(截断小数) */
int i = (int)d;
printf("double %f -> int %d\n", d, i);
/* 强制转换用于运算 */
int a = 5, b = 2;
/* 整数除法 */
int int_div = a / b;
printf("整数除法: %d / %d = %d\n", a, b, int_div);
/* 浮点除法(强制转换) */
float float_div = (float)a / b;
printf("浮点除法: %d / %d = %f\n", a, b, float_div);
/* 指针类型转换 */
int num = 0x41424344;
/* 将int指针转换为char指针 */
char *ptr = (char*)#
printf("\nint 0x%x 的字节表示:\n", num);
for (int j = 0; j < 4; j++) {
printf("字节%d: %c (0x%02x)\n", j, ptr[j], (unsigned char)ptr[j]);
}
/* void指针转换 */
void *vptr = #
int *iptr = (int*)vptr;
printf("\nvoid指针转换: %d\n", *iptr);
/* 注意事项 */
printf("\n=== 类型转换注意事项 ===\n");
printf("1. 浮点转整数会截断小数\n");
printf("2. 大类型转小类型可能丢失数据\n");
printf("3. 指针转换要确保类型兼容\n");
printf("4. 避免不必要的类型转换\n");
return 0;
}sizeof运算符
c
/*
* sizeof运算符
*/
#include <stdio.h>
int main(void)
{
/* 基本类型的sizeof */
printf("=== 基本类型大小 ===\n");
printf("char: %zu 字节\n", sizeof(char));
printf("short: %zu 字节\n", sizeof(short));
printf("int: %zu 字节\n", sizeof(int));
printf("long: %zu 字节\n", sizeof(long));
printf("long long: %zu 字节\n", sizeof(long long));
printf("float: %zu 字节\n", sizeof(float));
printf("double: %zu 字节\n", sizeof(double));
printf("long double: %zu 字节\n", sizeof(long double));
/* 变量的sizeof */
int arr[10];
char str[] = "Hello";
printf("\n=== 变量大小 ===\n");
printf("arr数组: %zu 字节\n", sizeof(arr));
printf("arr元素个数: %zu\n", sizeof(arr) / sizeof(arr[0]));
printf("str数组: %zu 字节\n", sizeof(str)); /* 包含'\0' */
/* sizeof是编译时运算符 */
printf("\n=== sizeof特性 ===\n");
/* sizeof的结果类型是size_t */
printf("sizeof返回size_t类型\n");
printf("size_t大小: %zu 字节\n", sizeof(size_t));
/* sizeof与表达式 */
int x = 10;
printf("sizeof(x): %zu\n", sizeof(x));
printf("sizeof(x + 1): %zu\n", sizeof(x + 1)); /* 表达式不计算 */
printf("x的值仍然是: %d\n", x);
return 0;
}typedef类型定义
c
/*
* typedef类型定义
*/
#include <stdio.h>
#include <stdint.h> /* 固定宽度整数类型 */
/* 定义类型别名 */
typedef unsigned char byte;
typedef unsigned int uint;
typedef char* String;
/* 定义结构体别名 */
typedef struct {
int x;
int y;
} Point;
/* 定义函数指针别名 */
typedef int (*Operation)(int, int);
int add(int a, int b) { return a + b; }
int subtract(int a, int b) { return a - b; }
int main(void)
{
/* 使用自定义类型 */
byte b = 255;
uint u = 100;
String s = "Hello";
printf("byte: %u\n", b);
printf("uint: %u\n", u);
printf("String: %s\n", s);
/* 使用结构体别名 */
Point p1 = {10, 20};
Point p2 = {30, 40};
printf("\nPoint p1: (%d, %d)\n", p1.x, p1.y);
printf("Point p2: (%d, %d)\n", p2.x, p2.y);
/* 使用函数指针别名 */
Operation op;
op = add;
printf("\n加法: %d\n", op(10, 5));
op = subtract;
printf("减法: %d\n", op(10, 5));
/* 固定宽度整数类型 */
printf("\n=== 固定宽度整数类型 ===\n");
int8_t i8 = 127;
int16_t i16 = 32767;
int32_t i32 = 2147483647;
int64_t i64 = 9223372036854775807LL;
uint8_t u8 = 255;
uint16_t u16 = 65535;
uint32_t u32 = 4294967295U;
uint64_t u64 = 18446744073709551615ULL;
printf("int8_t: %d\n", i8);
printf("int16_t: %d\n", i16);
printf("int32_t: %d\n", i32);
printf("int64_t: %lld\n", i64);
printf("uint8_t: %u\n", u8);
printf("uint16_t: %u\n", u16);
printf("uint32_t: %u\n", u32);
printf("uint64_t: %llu\n", u64);
return 0;
}小结
本章学习了:
- 数据类型分类:基本类型、枚举类型、void类型、派生类型
- 整型:char、short、int、long、long long 及其有符号/无符号变体
- 浮点型:float、double、long double 及其精度问题
- 字符型:char类型和ASCII字符集
- void类型:函数返回值、参数、通用指针
- 类型转换:隐式转换和显式转换
- sizeof运算符:获取类型和变量大小
- typedef:定义类型别名
下一章,我们将学习运算符,了解C语言中的各种运算操作。
