C语言的第二次复习
2016-07-15 11:49
423 查看
主函数参数与程序接口
(示例3, 示例4)argc (argc - 1 为参数个数) const char *argv[] (参数列表)
./a.out 也是一个参数
隐式类型转换
(示例5)(!!!!)负数在计算机中是以该负数的二进制的补码形式
存储的。
在有符号数中,正数第一位是0,负数第一位是1
(参考浮点数和整数在内存中的存储这篇)
int 默认是 signed int 也就是说是有符号整型,最高位是符号位,数据只占31位
unsigned int是无符号整型,最高位也是数据位,数据占满32位
// Demo1 int num1 = -1; unsigned num2 = 1; int compare1 = num1 < num2; int compare2 = (unsigned)num1 < num2; int compare3 = num1 < (int)num2; printf("%d\n", compare1); // 输出0.-1 是 11111111 11111111 11111111 11111111 printf("%d\n", compare2); // 输出0。 强转了就是把符号位也算进去。同上的数 printf("%d\n", compare3); // 输出1 // Demo2 double num3 = 5; printf("%d\n", num3); printf("%d\n", (int)num3); // Demo3 double num4 = 3.6; printf("%.0lf\n", num4); // 四舍五入 printf("%d\n", (int)num4); // 去尾
变量与函数的声明与多文件管理
源文件——-》可执行文件预处理 -E
编译 -S 汇编
汇编 -c 得到二进制文件
链接
(预处理解决循环包含问题)
编译和连接 分开
gcc -c x1.c x2.c 只编译不连接
gcc x1.c x2.c -o output_filename 编译后连接成可执行文件
gcc main.c -o test -Wall
带warning的编译
函数递归
(示例6)函数的调用就是入栈出栈的过程
// 把一个栈里的数用函数递归倒过来 #include <iostream> #include <stack> int getEnd(std::stack<int> &st) { if (st.size() == 1) { // 当这是最后一个数时候,直接出栈 int theEnd = st.top(); st.pop(); return theEnd; } int data = st.top(); st.pop(); // 如果不是最后一个数,那么删除栈中数据 int theEnd = getEnd(st); // 找到最后一个数后 st.push(data); // 把不是最后的数依次入栈 return theEnd; } void reverse(std::stack<int> &st) { if (!st.size()) return; // 如果栈空,说明已经找到所有的最后一个数,函数栈排列为10 9 8 。。。1(底) int theEnd = getEnd(st); // 找到最后一个数 reverse(st); //继续找最后一个数, st.push(theEnd); // 把数顺序入栈,从10开始入栈 } int main(int argc, const char * argv[]) { std::stack<int> st; for (int index = 1; index < 11; index++) { st.push(index); } reverse(st); while (st.size() != 0) { std::cout << st.top() << " "; st.pop(); } return 0; }
指针
指针就是十六进制的数!!!指针就是十六进制的数!!!指针就是十六进制的数!!!(在32位机里指针是8位的十六进制,64位机子里指针是16位的十六进制)一个字节就对应一个地址!!!一个字节就对应一个地址!!!一个字节就对应一个地址!!!
指针的类型告诉你,他每次读几个字节和怎么读(比如long long 和double都是8字节,但是因为存储方式不一样,所以读取方式也不一样),指针这个数告诉你,他从哪里开始读
注:malloc 向系统申请分配指定size个字节的内存空间。返回类型是 void* 类型。
sizeof是C/C++中的一个操作符(operator),简单的说其作用就是返回一个对象或者类型所占的内存字节数。
// 泛型指针 void *p1; // p1是泛型指针,他的读取长度不定 p1 = malloc(sizeof(int)); printf("%p\n",p1); // %p是专门打印指针的,可以看到指针就是一个数 // 输出一个随机的十六进制数(malloc出来一片空间) // 具体指针 int *p2 = p1; // p2是一个指针(就是个数,这个数表示一个地址(这个地址是头地址)),他访问这个地址的时候会读sizeof(int)长度 printf("%p\n",p2); int compare0 = p1 == p2; // 1 int compare = sizeof(p1) == sizeof(p2); //1 // 间接运算 int compare2 = sizeof(*p1) == sizeof(*p2); // 0 sizeof(*p1) = 1(泛型指针没有读取方式啊),sizeof(*p2) = sizeof(int) = 4(64位机子) printf("%d ,%d, %d", compare0, compare, compare2); printf("%d", sizeof(void *)); // 泛型指针也是指针啊,当然就是个数(64位机子 = 64bit = 8byte)
关于泛型指针:
这也是指针,和其他指针一样也是个数
malloc函数返回一个泛型指针,如果初始其他类型指针,必须强转
其他类型指针转化为泛型指针不用强转
就算开辟了空间,他还是没有读取方式,所以内存只能说给他了一个值(地址),也就是一个字节
void型指针、空指针、野指针:
int *p = (int *)malloc(sizeof(int));// free(p); // 释放p所指的一片空间。 *p = 6; // 一个指针指向了一片未开辟的空间(不可用的内存空间),野指针(垂悬指针) // 规定0表示空指针 p = NULL; // NULL == (void *)0
多重指针
int *p;“指针指向Int”,这样说法不对,应该是声明p是指针,p这个数代表一个地址,如果对p做间接运算,p从这个地址开始以Int方式读取数
int **p;申明p是一个指针,p这个数代表一个地址,如果对p做间接运算,p从这个地址开始以int *方式(就是读取8个字节)读取数,读出来的数也是一个地址,再次做间接运算,从该地址开始以Int方式读取数
当然这样理解复杂了很多,记住他的本质就行
int a = 8; int *p = &a; // p == &a // *p == a void *q = &p; int **q2 = q; // q2 == q == &p // q2 == q == &p // *q2 == p == &a // **q2 == a void *w = &q2; int ***w2 = w; // w2 == w == &q2 void **w3 = w; // w2 == &q2 // *w2 == q2 == &p // *w3 == q2 // **w3不合法
不用怕什么**的东西,记住指针就是个数,实在想不出就画图
指针和数组和函数放一起的读法
先读括号,然后从俩边往中间读!
先读括号,然后从俩边往中间读!
先读括号,然后从俩边往中间读!
(如果实在对往中间读,那就先括号,在从右往左想想)
int *a1[3];//a1是一个含有3个元素的数组,数组中的元素是指针,指针指向int型 int (*a2)[3];//a2是一个指针,指针指向一个带有3个int元素的数组 int **a3[3];//a3是一个含有3个元素的数组,数组中元素是指向指针的指针,指针又指向int型 int *(*a4)[3];//a4是指针,指针指向一个含有三个元素的数组,数组中的元素是指向int型的指针 int (**a5)[3];//a5是一个指针,指向一个指针,这个指针指向一个带3个int型元素的数组
int *f1(); //f1是一个函数,返回值是一个指向int型的指针,无形参 int (*f2)(); //f2是一个指针,指向一个函数,此函数返回值为int,无形参 int *(*f3)(int *); //f3是一个指针,指向一个函数,这个函数的返回值是指向Int的指针,形参是指向int的指针 int *(**f4)(void (*)(int **)); //f4是一个指针,指针指向另一个指针,这个指针指向一个函数,函数的返回值是指向int的指针,形参中是一个指针,指针指向一个函数,这个函数是返回值是void,形参是指针的指针,指向int int *(*f5[2])(int (*)()); //f5是一个含有2个元素的数组,数组中的元素是指针,指针指向一个函数,此函数的返回值是指向int的指针,形参是一个指针,指针指向一个函数,函数返回值是int。无形参 int *(*f6[2])(int *(*)(int (*)())); //f6是一个含有2个元素的数组,数组中元素是指针,指针指向一个函数,此函数的返回值是指向int的指针,形参是一个指针,指针指向一个函数,函数返回值是指向int的指针,形参是一个指向函数的指针,这个函数的返回值是int,无形参 int (*(*f[3])(int (*)()))(int); //f是一个含有3个元素的数组,数组中元素是指针,指针指向一个函数1,此函数1返回值是指针(这个指针指向一个返回值是int,形参为int的函数3),形参是指向一个函数2的指针,返回值int无形参。
int a[2][3]; 是一个含有2个元素的数组,每个元素又是一个含有3个元素的数组,所以以下写法 也是正确的。。。(完全神奇)
typedef int ar[3]; ar a[2] = {{1,2,3}, {2,3,4}};
数组
(作为变量、作为形参、作为赋值语句的左边和右边、多维数组的情况、角标语法)变参函数
(示例7,示例8,示例9)#include <stdarg.h>
VA_START宏,获取可变参数列表的第一个参数的地址(ap是类型为va_list的指针,v是可变参数最左边的参数):
#define va_start(ap,v) ( ap = (va_list)&v + _INTSIZEOF(v) )
VA_ARG宏,获取可变参数的当前参数,返回指定类型并将指针指向下一参数(t参数描述了当前参数的类型):
#define va_arg(ap,t) ( *(t *)((ap += _INTSIZEOF(t)) - _INTSIZEOF(t)) )
VA_END宏,清空va_list可变参数列表:
#define va_end(ap) ( ap = (va_list)0 )
用法
(1)首先在函数里定义一具VA_LIST型的变量,这个变量是指向参数的指针;
(2)然后用VA_START宏初始化刚定义的VA_LIST变量;
(3)然后用VA_ARG返回可变的参数,VA_ARG的第二个参数是你要返回的参数的类型(如果函数有多个可变参数的,依次调用VA_ARG获取各个参数);
(4)最后用VA_END宏结束可变参数的获取。
const
内存对齐
(示例10)内存对齐原则:以4字节为一小组,以8字节为一大组,不能夸组,不满一组的空出其空间
结构体与指针强转
(示例11)共合体
共合体就是,同一片区域的不同方式访问,这多种访问方式的集合宏(连接宏,变参宏,模板宏)
实战:可选类型的实现
相关文章推荐
- 如何组织构建多文件 C 语言程序(二)
- 如何写好 C main 函数
- Lua和C语言的交互详解
- 关于C语言中参数的传值问题
- 简要对比C语言中三个用于退出进程的函数
- 深入C++中API的问题详解
- 基于C语言string函数的详解
- C语言中fchdir()函数和rewinddir()函数的使用详解
- C语言内存对齐实例详解
- C语言编程中统计输入的行数以及单词个数的方法
- C语言自动生成enum值和名字映射代码
- C语言练习题:自由落体的小球简单实例
- 使用C语言判断英文字符大小写的方法
- c语言实现的带通配符匹配算法
- C语言实现顺序表基本操作汇总
- C语言中进制知识汇总
- C语言判断一个数是否是2的幂次方或4的幂次方
- C语言中计算正弦的相关函数总结
- 使用C语言详解霍夫曼树数据结构
- C语言实现选择排序、冒泡排序和快速排序的代码示例