while{p!=null} printf{%d/n,%d/n,price,atk};p=p>-next;
结构体三种表达方法,这个最好用。
vim helloword.c
#include<stdio.h>
#definr R 10 //R就是宏,结尾不用分号隔开。
int main()
{
int a = R;
printf("%d\n",a);
printf("helloworld\n");
return 0 ;
}
编译程序:gcc helloworld.c
查看运行效果:./a.out
结果为:a=10
helloworld
查看预处理之后的文件:gcc -0 helloworld.i helloworld.c -e
回车
gcc -o helloworld.i helloworld.c -E
vi helloworld.i
宏不考虑语法
----------------------------------------------------------
- 静态链表 -
----------------------------------------------------------
#include <stdio.h>
#include <string.h>
struct weapon{
int price;
char atk[20];
struct weapon * next;
}wea1,wea2,wea3,wea4,*head;
void main(){
// 赋值
wea1.price = 100;
strcpy(wea1.atk,"AWM");
wea2.price = 200;
strcpy(wea2.atk,"sass");
wea3.price = 300;
strcpy(wea3.atk,"98K");
wea4.price = 400;
strcpy(wea4.atk,"AK-47");
//设置指针
wea1.next = &wea2;
wea2.next = &wea3;
wea3.next = &wea4;
wea4.next = NULL;
//头指针指向wea1
head = &wea1;
//通过指针打印 weapon 变量
struct weapon * p;
p = head;
while(p!=NULL){
printf("%d , %s\n",p->price,p->atk);
p = p->next;
}
printf("output wea1 is :%s;output &wea1 is :%s\n",wea1,&wea1);
printf("%s\n",&wea1.atk);
}
----------------------------------------------------------
- 执行结果 -
----------------------------------------------------------
100 , AWM
200 , sass
300 , 98K
400 , AK-47
output wea1 is :d;output &wea1 is :d
AWM
.c文件 --> .i文件 --> .s文件 --> .o文件 --> 可执行文件
预处理 编译 汇编 链接
--在预处理阶段除了展开头文件,其次就是进行宏替换
#define R 3.14
...
float a = R
...
宏替换后:..a=3.14 ...(宏的本质就是单纯的发生在预处理阶段的字符串替换==> 即,宏不考虑语法,就是单纯的字符串替换!!!)
# 看一下在预处理中程序做了什么事情:语句代表将 helloworld.c 文件进行预处理,然后结果输出到 .i 文件中去
gcc -o helloworld.i helloworld.c -E
# -E 表示只让 gcc 进行预处理
# -o <文件> 输出到 <文件>。
#include <stdio.h>
//这个宏脱离了传参类型的限制,类似 Java 中的泛型;传入两个参数,对其进行加法运算。
#define ADD(a,b) (a+b)
//结构体变量定义、初始化和引用的过程
struct weapon{
char name[20];
int atk;
float price;
}weapon_1;
struct{
char name[20];
int age;
}people;
//共用体
//union 所有成员共享一块内存地址
union data{
int aa;
char bb;
float cc;
};
//相同结构的 结构体 和 公共体,打印他们的大小,看其占用内存空间的规则
struct data_str{
int aaa;
char bbb;
float ccc;
};
int main(){
// 定义结构体变量的同时赋值
struct weapon weapon_2={"ak-47",10,9.9};
//已经定义好的结构体变量赋值
weapon_1.name[0]='A';
weapon_1.name[1]='W';
weapon_1.name[2]='M';
weapon_1.atk=20;
weapon_1.price=19.9;
//结构体数组
struct weapon weapon_3[2] = {
{"java",30,18.8},
{"php",40,29.9}
};
//没有结构体名的结构体
people.age=18;
//结构体指针
struct weapon * w2;
w2 = &weapon_2;
//结构体数组指针
struct weapon * w1;
w1=weapon_3;
//共用体
union data data_union;
printf("weapon_1: %s,%d,%f\n",weapon_1.name,weapon_1.atk,weapon_1.price);
printf("weapon_2:%s,%d,%f\n",weapon_2.name,weapon_2.atk,weapon_2.price);
printf("wwapon_3: %s,%s\n",weapon_3[0].name,weapon_3[1].name);
printf("people.age is %d\n",people.age);
printf("w1[0] is : %s\n",w1->name);
w1++;
printf("w1[1] is : %s\n",w1->name);
//结构体指针,加括号是因为点的优先级高于星的优先级。一样的结果
printf("w2 is : %s,%s\n",(*w2).name,w2->name);
//共用体(联合 ---> 打印发现地址都是一样的(data_union.a:0xffffc4694d50)
//表示按十六进制输出数据,如果输出数据不够8位数,则左边补0
printf("data_union.a:%p,\ndata_union.b:%p,\ndata_union.c:%p\n",&data_union.aa,&data_union.bb,&data_union.cc);
//%u表示无符号10进制整型,
//%lu表示输出无符号长整型整数
printf("data_union size is :%lu\n",sizeof(data_union));
printf("data struct size is :%lu\n",sizeof(struct data_str));
return 0;
}
------------------------------执行结果------------------------------------
weapon_1: AWM,20,19.900000
weapon_2:ak-47,10,9.900000
wwapon_3: java,php
people.age is 18
w1[0] is : java
w1[1] is : php
w2 is : ak-47,ak-47
data_union.a:0xffffe228b730,
data_union.b:0xffffe228b730,
data_union.c:0xffffe228b730
data_union size is :4
data struct size is :12
gcc helloworld.c 四个步骤
gcc helloworld.c 四个步骤
c语言结构体
左移运算能够实现二倍乘法,比直接乘法要快得多。
int是定义的有符号数,左移会导致符号位移出去,导致内存溢出。
右移不会导致溢出,有符号数进行右移的时候,头部的0会保存,1会重新设置在头部。
异或:进行定位翻转(0变1,1变0)
按位或:用于设定指定位(比如与ff相或,可以将低八位设置为1)
按位与用法:清零,保留指定位置的数。
malloc函数的使用要调用malloc.h的头文件。
malloc函数后面的sizeof主要用于指示分配内存的大小,由于malloc函数默认返回void类型(无类型,一般用于无返回值的函数。)
create函数的创建如下所示:
静态数据结构:整型、浮点型、数组(内存空间和里面的内容是定义好的)
链表由一个个节点组成,每个节点都包含了数据和下一个节点的地址两部分。
数组是连续的内存空间,链表不一定连续。
上图显示如何设计并访问静态链表。
其中p->atk和(*p).atk表达效果一致。
定义了union类型之后,data里面的内容都是占用的同一个内存空间。
所以12行后,给a赋值之后,b其实就不起作用了。
共用体占用的内存是所有元素当中占用最长的那个的内存。
共用体几个成员的地址都是一样的。
结构体的占用内存,不是单纯地将元素的内存大小进行累加(计算机将其内存重新规划了一下,提高了运行效率,用空间换时间)。
首先判断所有元素的偏移地址(相对结构体第一个内存地址的偏移量),a是0,b是4(a的内存字节数),c是5(a和b相加)。之后看一下每个元素的偏移地址,是不是他们自身占用的字节数的整数倍,比如c的偏移量是5个字节,占用了4个字节,这个时候在c的前面加上3个字节的内存补空,让c的偏移量变成8个字节,是4个字节的两倍。
之后,还要判断结构体总体的内存,是不是最大元素所占内存的整数倍,如果不是就在结构体最后补充字节数,直到满足要求。
%lu表示长整型,sizeof()用于输出内存大小。
%p表示地址,后面接&xxx输出内存地址。
15-17行定义并输出结构体变量的相关属性(*w的()不能省略,因为.运算符优先级比*高)
可以用w->name来替换*w.name
24行定义的指针p->name指向weapon_2数组第一个元素
26行的p++表示p已经指向下一个元素。
结构体变量weapon_1通过第12行语句定义,可以通过第13行的.运算符获得相关的值。
第15行定义weapon_2数组,有两个元素,每个元素都有结构体里定义的三种属性。(可以将每个成员的3个属性分别用{}括起来,方便看)
16行展示了如何调用结构数组中每个成员的各种属性。
struct定义方式:
1. 定义类型 struct xx {};
2. 定义类型并声明一个全局变量 struct xx {} xx_1;
3. 定义一个结构体 struct {} xx_1;
typedef的作用:重命名变量数据类型
语法:typedef [数据类型] [新的名字]
eg.typedef int * pointer;//将int * 的数据类型命名为pointer
typedef VS define:
①预处理时define定义的宏会替换,但typedef定义的别名不会替换。
②作用域不同
③通常用于给自定义数据类型其别名
size_t : unsigned long的别名
我们正常定义一个函数需要声明参数类型,int a之类的,用宏定义函数,就不用考虑c语法。
预处理阶段工作:①将头文件展开直接放置到源文件中
②宏替换
③条件编译
注意:宏替换只是简单得字符串替换,且可以传递参数。
例如,#define N(n) n*10
int b = N(a); // 首先n替换成a,然后a*10。
易错:#define ADD(a,b) a+b
int c = ADD(a,b) * ADD(a,b);
/* 经过简单的替换会得到a+b*a+b,这显示不是我们想要的结果,因此加上括号保证优先级不会出错。*/
#define ADD(a,b) (a+b)
生成一个.i文件,-E表示只让gcc举行预处理
预处理展开了头文件,形成了main函数上面的一大串文字
结构体 数组 指针运用