您的位置:首页 > 编程语言 > C语言/C++

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语言