C语言基础相关内容


前言

本文简明扼要的介绍了部分C语言的一些基本内容。


0 补充

C语言标准库

大致包含:

  • 标准输入输出(stdio.h)
  • 文件操作(stdio.h)
  • 字符操作(ctype.h)
  • 字符串操作(string.h)
  • 数学函数(math.h)
  • 资源管理(stdlib.h)
  • 格式转换(stdlib.h)
  • 日期/时间(time.h)
  • 断言(assert.h)
  • 各种类型上的常量(limits.h & float.h)

一些特殊的库,用于执行一些特殊的操作:

  • 变长参数(stdarg.h)
  • 非局部跳转(setjmp.h)

变长参数

#include <stdio.h>
// __VA_ARGS__编译器内置宏
#define print(...) fprintf(stdout, __VA_ARGS__)
#define print2(args...) fprintf(stdout, ##args)

int main()
{
    print("%d, %s\n", 123, "hello");
    // >> fprintf(stdout, "%d, %s\n", 123, "hello")
}

线程局部存储

线程私有全局变量

__thread int a = 6;  // 线程私有全局变量

void printa()
{
    while (1)
    {
        ++a;
        printf("thread id: %ld, a: %d\n", std::this_thread::get_id(), a);        
    }
}

int main()
{
    for (int i = 0; i < 4; ++i)
    {
        std::thread(printa).detach();
    }
    while(1);
}

1. 关键字

12345678
charshortintlongfloatdoubleifelse
returndowhileforswitchcasebreakcontinue
defaultgotosizeofautoregisterstaticexternunsigned
signedtypedefstructenumunionvoidconstvolatile

基本数据类型:char, int, float, double
类型修饰: short, long, signed, unsigned
复杂类型: struct, union, enum
流程控制:分支(if, else, switch, case, default),循环(for, while, do),跳转(continue, break, goto, return)
存储类型:auto(和c++大相迳庭), register, static, extern, const, volatile
特殊用途:sizeof(同时也是运算符), typedef, void

2. C语言数据类型

基本类型
数值类型
整形, 浮点型, bool
字符
构造类类型
数组, 结构体, 共用体, 枚举
指针
空类型 void

3. 标志符

  • 只能由字符(a~z, A~Z)、数字、下划线组成
  • 不能以数字开头
  • 不能是关键字
  • 区分大小写

个人理解标识符是:顾名思义,标识符就是起到标志作用的符号,是给人用的,编译器会将标志符和地址关联起来;程序的运行并不需要标志符,只需要地址和值,所以标识符是给人和编译器用的。

4. 常量类型

  • 整型常量
  • 实型常量
  • 字符常量
  • 字符串常量

5. 内存模型

在笔者的环境下,不同数据类型的位数

cahrintfloatdoubleshortlonglong longvoid*
Byte14482888

在这里插入图片描述

#include <stdio.h>

void fun();
void fun1();
void fun2();

void fun()
{
    int a = 0x04030201;
    int b = 0x04030201;
    int c = 0x04030201;
    int d = 0x04030201;
    // int *pa = &a;
    printf("fun: \n");
    printf("a = %p\n", &a);
    printf("b = %p\n", &b);
    printf("c = %p\n", &c);
    printf("d = %p\n", &d);
    fun1();
}
void fun1()
{
    int a = 0x04030201;
    int b = 0x04030201;
    int c = 0x04030201;
    int d = 0x04030201;
    int e = 0x04030201;
    // int *pa = &a;
    printf("fun1: \n");
    printf("a = %p\n", &a);
    printf("b = %p\n", &b);
    printf("c = %p\n", &c);
    printf("d = %p\n", &d);
    printf("e = %p\n", &e);
    fun2();
}
void fun2()
{
    int a = 0x04030201;
    int b = 0x04030201;
    int c = 0x04030201;
    int d = 0x04030201;
    // int *pa = &a;
    printf("fun2: \n");
    printf("a = %p\n", &a);
    printf("b = %p\n", &b);
    printf("c = %p\n", &c);
    printf("d = %p\n", &d);
}

int main(int *arg, int **argvs)
{
    int a = 0x04030201;
    int b = 0x04030201;
    int c = 0x04030201;
    int d = 0x04030201;
    // int *pa = &a;
    printf("main: \n");
    printf("a = %p\n", &a);
    printf("b = %p\n", &b);
    printf("c = %p\n", &c);
    printf("d = %p\n", &d);
    fun();

    char* pa = (char*)&a;
    printf("pa= %p\n", &pa);
}

OUT:

main: 
a = 0x7fff04ebfa30
b = 0x7fff04ebfa34
c = 0x7fff04ebfa38
d = 0x7fff04ebfa3c
fun: 
a = 0x7fff04ebf9f8
b = 0x7fff04ebf9fc
c = 0x7fff04ebfa00
d = 0x7fff04ebfa04
fun1: 
a = 0x7fff04ebf9c4
b = 0x7fff04ebf9c8
c = 0x7fff04ebf9cc
d = 0x7fff04ebf9d0
e = 0x7fff04ebf9d4
fun2: 
a = 0x7fff04ebf998
b = 0x7fff04ebf99c
c = 0x7fff04ebf9a0
d = 0x7fff04ebf9a4

pa= 0x7fff04ebfa40

小结:
局部变量在栈空间分配内存时,以函数为单位,先一次性分配出函数内局部变量所需的空间(函数调用不影响函数内局部变量的空间分配), 然后再执行到新的函数调用时由高地址向底地址分配内存

即: 内存的分配以函数为单位由高地址向底地址增长

在这里插入图片描述

变量内存分析

  1. 内存模型是线性的(有序的)
  2. 对于32位机而言,最大的内存地址是 2 32 2^{32} 232(4294967296)(4GB)
  3. 对于64位机而言,最大的内存地址是 2 64 2^{64} 264(171亿GB)
  4. CPU读写内存
    • CPU运行时要明确三件事: 1. 存储单元的地址(地址信息) 2. 器件的选择,读或写(控制信息) 3. 读写的数据(数据信息)
    • 通过地址总线找到存储单元的地址; 通过控制总线发送内存读写指令; 通过数据总线传输需要读写的数据;
  5. 变量的存储原则
    • 内存内配由高地址向低地址增长
    • 变量的首地址是变量存储空间低地址
    • 字节序分为小端(intel, 低地址存储低位)和大端(Motorola, 低地址存储高位); 字节地址内位的存储方式是一致的
      在这里插入图片描述

数组

char arr[3] = {'a', 'b', 'c'};

arr的值等于第一个元素的地址
在这里插入图片描述

不建议使用二维数组, 在C++中使用String来处理字符串

  arr的值和数组首元素地址相同,arr+1得到的是数组类型的偏移,arr像个数组类型的指针,它指向数组首元素
  但是sizeof(arr)得到的是内存块的大小;&arr的值与arr相同,&arr是一个指针类型,它指向数组内存块,&arr+1得到的是整个内存块大小的地址偏移

另外,sizeof既可以用于类,也可以用于类的对象。

数组与指针的区别

如上图所示,在语法上绝大部分情况数组和指针可以混用,但是数组和指针的数据类型是不同的,数组是数组类型,指针是指针类型

char arr[3] = {'a', 'b', 'c'};  // 数组类型
char* parr = arr;				// 指针类型

&arr + 1 == arr + sizeof(arr)
体现:

sizeof(arr) == 3
sizeof(parr) == 8

若在a.c文件中定义char arr[3],则在b.c文件中需要extern char arr[3]来使用而非extern char* arr。

变量名与地址

变量名就是地址的别称,用人类容易记忆的方式来代表某个地址
int a;中a就是某个地址0x???的别名,a = 4,就是这块内存赋值 4

a文件中定义char arr[3],在b文件中extern char* arr就是把b文件中的名字对应的a文件中的arr所在地址上。又因为b中arr为指针类型,所以会把arr的值当成地址对待即
a: char arr[3] = {0x11, 0x22, 0x33}; arr就是0x???地址
b: extern char* arr; arr就是0x???地址,地址里装的值是指针类型,地址里的值是什么呢?自然是[0x11  0x22  0x33  第4~第8个字节装的是什么不知道]

6. printf & scanf

scanf
printf
key board
输入缓冲区
Memory
Memory
输出缓冲区
终端
  • 格式输出函数 printf( “格式控制字符串”, 输出项列表 );
    eg: printf(“a = %d, b = %d”, a, b);
  • 格式控制字符串: %[标志][输出宽度][.精度][长度]类型
类型含义
d有符号十进制
u无符号十进制
f单、双精度浮点数(默认保留6位小数)
c字符
s字符串
p地址
  • scanf函数用于接受键盘输入(STDIN)的内容,是一个阻塞式函数,程序会停在scanf函数出现的地方,直到接受到数据才会继续执行。
  • scanf(“格式控制字符串”, 地址列表);
    eg: scanf(“%d”, &num);
  • 原理
    • 系统会将用户输入的内容先放入输入缓冲区
    • scanf方式会从输入缓冲区逐个取出内容赋值给变量
    • 如果输入缓冲区的内容不为空,scanf会一直从缓冲区中获取,而不要求再次输入
    • 利用setbuf清空缓冲区(所有平台都有效)
      • setbuf(stdin, NULL);

puchar&getchar

char ch = 'a';
putchar(ch);     // 输出a

ch = getchar();  // 获取一个字符

7 main函数

  • main也是个函数名, 只不过该名比较特殊,程序已启动就会自动调用它。即,程序执行的入口。
  • 如果main函数执行正常则返回0, 否则返回一个非0的数
  • int main(int argc, const char* argv[]);
    • argc - 在命令中输入的字符串的个数, 程序名占1个
    • argv - 命令行字符串argv[0]为程序名

8 字面值常量

# 二进制
0b1010
# 十六进制
0xFF
# 八进制
0777
# 十进制
10
# 科学计数法
1e3
1.1e3

45U   # 无符号
34.F  # (float)34.0
2L    # (long)2
2LL   # (long long)2
2ULL  # (unsigned long long)2
  • 0
    点赞
  • 0
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值