1. 指针词库
指针仅仅是指向计算机中的某个地址, 并带有类型限定符,所以你可以通过它得到正确大小的数据
标识 | 含义 |
---|---|
type *ptr |
type 类型的指针, 名为 ptr |
*ptr |
ptr 所指向位置的值 |
*(ptr + i) |
(ptr 所指向位置加上 i )的值, 以字节为单位的话, 应该是 ptr 所指向的位置再加上 sizeof(type) * i |
&thing |
thing 的地址 |
type *ptr = &thing |
名为 ptr , type 类型的指针, 值设置为 thing 的地址 |
ptr++ |
自增 ptr 指向的位置 |
2. 数组和指针
将array传入一个函数的时候, 传入的其实是一个指针, 对其求 sizeof
不能求出实际大小, 只能求出指针的大小 (数组退化)
没退化的时候可以求出对应的数组的元素的个数
int areas[] = {10, 12, 13, 14, 20};
printf("The size of an int: %ld\n", sizeof(int));
3. 数组的遍历
int ages[] = {23, 43, 12, 89, 2};
char *names[] = {
"Alan", "Frank",
"Mary", "John", "Lisa"
};
3.1 使用数组+下标访问
for(i = 0; i < count; i++)
{
printf("%s has %d years alive.\n", names[i], ages[i]);
}
3.2. 使用指针访问
int *cur_age = ages;
char **cur_name = names;
for(i = 0; i < count; i++)
{
printf("%s is %d years old.\n", *(cur_name+i), *(cur_age+i));
}
3.3 指针+下标
for(i = 0; i < count; i++)
{
printf("%s is %d years old again.\n",
cur_name[i], cur_age[i]);
}
3.4 指针+迭代
for(cur_name = names, cur_age = ages; (cur_age - ages) < count; cur_name++, cur_age++)
{
printf("%s lived %d years so far.\n", *cur_name, *cur_age);
}
4. 结构体和指向它们的指针
struct Person {
char *name;
int age;
int height;
int weight;
};
初始化和销毁
struct Person *Person_create(char *name, int age, int height, int weight)
{
struct Person *who = malloc(sizeof(struct Person));
assert(who != NULL);
who->name = strdup(name);
who->age = age;
who->height = height;
who->weight = weight;
return who;
}
void Person_destroy(struct Person *who)
{
assert(who != NULL);
free(who->name);
free(who);
}
5. 函数指针
函数指针的格式
int (*POINTER_NAME)(int a, int b)
编写方式:
- 编写一个普通的函数声明:
int callme(int a, int b)
- 将函数用指针语法包装:
int (*callme)(int a, int b)
- 将名称改成指针名称:
int (*compare_cb)(int a, int b)
赋值:
int (*tester)(int a, int b) = sorted_order;
调用:
printf("TEST: %d is same as %d\n", tester(2, 3), sorted_order(2,3));
6. 头文件处理
#ifndef _object_h
#define _object_h
// body
#endif
7. typedef
的使用
typedef enum {
NORTH, SOUTH, EAST, WEST
} Direction;
typedef struct {
char *description;
int (*init)(void *self);
void (*describe)(void *self);
void (*destroy)(void *self);
void *(*move)(void *self, Direction direction);
int (*attack)(void *self, int damage);
} Object;
后面直接可以用 Direction
, Object
来表示一个类型
8. 高级数据类型和控制结构
8.1 可用数据类型
类型 | 含义 |
---|---|
int |
储存普通的整数,默认为32位大小. int 在32或64位环境下为32位, 但它不应该被看作平台无关的. 如果需要用到平台无关的定长整数,请使用 int(n)_t |
double |
储存稍大的浮点数 |
float |
储存稍小的浮点数 |
char |
储存单字节字符 |
void |
表示"无类型", 用于声明不返回任何东西的函数, 或者所指类型不明的指针, 例如 void *thing |
enum |
枚举类型,类似于整数,也可转换为整数,但是通过符号化的名称访问或设置 |
8.2 类型修饰符
修饰符 | 含义 |
---|---|
unsigned |
修改类型,使它不包含任何负数,同时上界变高 |
signed |
可以储存正数和负数,符号修饰符只对 char 和 int 有效, int 默认为 signed , char 根据实现则不定 |
long |
对该类型使用较大的空间,使它能存下更大的数,通常使当前大小加倍 |
short |
对该类型使用较小的空间,使它储存能力变小,但是占据空间也变成一半 |
8.3 类型限定符
限定符 | 含义 |
---|---|
const |
表示变量在初始化后不能改变 |
volatile |
表示会做最坏的打算,编译器不会对它做任何优化 |
register |
强制让编译器将这个变量保存在寄存器中,并且也可以无视它 |
8.4 类型转换
C使用了一种"阶梯形类型提升"的机制, 它会观察运算符两边的变量,并且在运算之前将较小边的变量转换为较大边. 这个过程按照如下顺序:
long double
double
float
long long
long
-
int
(short
,char
)
short
和 char
会在运算之前转换成 int
. 同种类型的 unsigned
和 signed
运算, signed
保持字节不变转换成 unsigned
8.5 类型大小
stdint.h
为定长的整数类型定义了一些 typedef
, 同时也有一些用于这些类型的宏
数据类型如下:
-
int8_t
,uint8_t
-
int16_t
,uint16_t
-
int32_t
,uint32_t
-
int64_t
,uint64_t
源码如下:
typedef __int8_t int8_t;
typedef __int16_t int16_t;
typedef __int32_t int32_t;
typedef __int64_t int64_t;#ifndef _BITS_STDINT_INTN_H
#define _BITS_STDINT_INTN_H 1
#include
typedef __int8_t int8_t;
typedef __int16_t int16_t;
typedef __int32_t int32_t;
typedef __int64_t int64_t;
#endif /* bits/stdint-intn.h */
#ifndef _BITS_STDINT_UINTN_H
#define _BITS_STDINT_UINTN_H 1
#include
typedef __uint8_t uint8_t;
typedef __uint16_t uint16_t;
typedef __uint32_t uint32_t;
typedef __uint64_t uint64_t;
#endif /* bits/stdint-uintn.h */
定义的最大最小值:
定义 | 含义 |
---|---|
INT(N)_MAX |
N 位最大的int 值 |
INT(N)_MIN |
|
UINT(N)_MAX |
|
int_least(N)_t |
至少 N 位的整数 |
INT_LEAST(N)_MAX |
源码如下:
/* Minimum of signed integral types. */
# define INT8_MIN (-128)
# define INT16_MIN (-32767-1)
# define INT32_MIN (-2147483647-1)
# define INT64_MIN (-__INT64_C(9223372036854775807)-1)
/* Maximum of signed integral types. */
# define INT8_MAX (127)
# define INT16_MAX (32767)
# define INT32_MAX (2147483647)
# define INT64_MAX (__INT64_C(9223372036854775807))
// stdint.h
/* Signed. */
typedef __int_least8_t int_least8_t;
typedef __int_least16_t int_least16_t;
typedef __int_least32_t int_least32_t;
typedef __int_least64_t int_least64_t;
/* Unsigned. */
typedef __uint_least8_t uint_least8_t;
typedef __uint_least16_t uint_least16_t;
typedef __uint_least32_t uint_least32_t;
typedef __uint_least64_t uint_least64_t;
// types.h
typedef signed char __int8_t;
typedef unsigned char __uint8_t;
typedef signed short int __int16_t;
typedef unsigned short int __uint16_t;
typedef signed int __int32_t;
typedef unsigned int __uint32_t;
#if __WORDSIZE == 64
typedef signed long int __int64_t;
typedef unsigned long int __uint64_t;
#else
__extension__ typedef signed long long int __int64_t;
__extension__ typedef unsigned long long int __uint64_t;
#endif
/* Smallest types with at least a given width. */
typedef __int8_t __int_least8_t;
typedef __uint8_t __uint_least8_t;
typedef __int16_t __int_least16_t;
typedef __uint16_t __uint_least16_t;
typedef __int32_t __int_least32_t;
typedef __uint32_t __uint_least32_t;
typedef __int64_t __int_least64_t;
typedef __uint64_t __uint_least64_t;
ref: https://learncodethehardway.org/c/