1. 初识C语言
C语言是一门通用计算机编程语言,广泛应用于底层开发。
C语言是一门面向过程的计算机编程语言,它与C++,Java等面向对象的编程语言有所不同。
第一个C语言程序:
#include<stdio.h>
int main(void)
{
printf("hello world!\n");
return 0;
}
注释:
stdio:标准输入输出
main函数:main函数是主函数,也是程序的入口,并且有且仅有一个
main(void):加参数void表示main函数不需要参数
printf函数:它是一个库函数,主要用于在屏幕上打印相关的数据,使用库函数就得包含对应的头文件
//一种旧式写法,在一些老式的编译器中可以使用
void main()
{
...
}
2.数据类型
类型的存在主要是为创建变量服务的,常用的数据类型如下:
字符类型:char
整数类型:short int long longlong
浮点类型:float double
int main()
{
printf("%d\n",100);//100
printf("%d\n",sizeof(char));//1
printf("%d\n",sizeof(short));//2
printf("%d\n",sizeof(int));//4
printf("%d\n",sizeof(long));//4
printf("%d\n",sizeof(long long));//8
printf("%d\n",sizeof(float));//4
printf("%d\n",sizeof(double));//8
return 0;
}
注释:
%d:用于打印整数
sizeof():是一个操作符,用来计算类型和变量的大小
计算机的基本单位
bit:比特位,存一个二进制位1或者0
byte:字节,1byte=8bit
KB:1KB=1024byte
MB:1MB=1024KB
GB:1GB=1024MB
C语言标准规定:sizeof(long)>=sizeof(int) ,但是long的大小不一定要是8只要是比4的数字即可
C语言有没有字符串类型?
C语言没有原生字符串类型。像Java有自己的字符串类型string,而在C语言中,字符串则往往是被当做字符数组或者字符指针来进行处理的。在C语言中,字符串有3个核心要点:第一是用指针指向字符串的头;第二是固定尾部(字符串总是以\n来结尾);第三是组成字符串的各字符彼此地址相连。
3.常量与变量
常量
常量:用来描述变化的数据
定义变量:
int age=150;
float weight=55.5f(加f表面是个float的类型);
char ch='w';
变量的分类:
局部变量:在大括号内定义的变量
全局变量:在大括号外定义的变量
int a=100;//全局变量
void test()
{
int c=1000;//局部变量
}
int main()
{
//运行时会报错,因为a是局部变量,只能在括号以内使用
{
int a = 10;//局部变量
}
printf("%d\n",a);
//可以运行,不会发生错误
int a = 10;//局部变量
printf("%d\n", a);
return 0;
}
局部变量优先原则:
当局部变量和全局变量同名时,局部变量优先使用
int a = 100;
int main()
{
int a = 10;//局部优先原则
printf("a=%d\n",a);//输出结果为10
return 0;
}
变量的使用:
//求两数之和
int main()
{
int num1 = 0;
int num2 = 0;
int sum = 0;
//输入
scanf("%d %d",&num1,&num2);
//求和
sum = num1 + num2;
//输出
printf("sum=%d\n",sum);
printf("%d %d\n",num1,num2);
return 0;
}
注释:
scanf():输入函数
printf():输出函数
%s:输出字符串
%d:输出整数
scanf()函数为什么不安全?如何解决?
因为scanf() 函数不会对存放数据的内存空间进行检测,在使用的过程中输入的数据可能会大于原本分配的内存空间,进而导致溢出,造成越界访问,所以scanf()函数不安全。
解决办法:
法1:在源文件开头定义:#define _CRT_SECURE_NO_WARNINGS 1(比较麻烦,每次新建工程都要重新定义,建议采用方法2)
法2:在VS的安装路径下搜索到newc++file.cpp这个文件,复制一份到桌面,并在文件中加入#define _CRT_SECURE_NO_WARNINGS 1并保存,然后以管理员的身份替换到原来的文件即可
法:3:通过项目 -> 属性 -> C/C++ -> 预处理器 -> 预处理器定义 -> 编辑,在框内写入 _CRT_SECURE_NO_WARNINGS
法4:在源文件开头加入一行命令:#pragma warning(disable:4996)
变量的作用域和生命周期
作用域:通常来说,一段程序中所用到的名字并不总是有效/可用的,而限定这个名字的可用性的代码范围就是这个名字的作用域
局部变量:局部变量的作用域就是局部变量所在的局部范围
全局变量:全局变量的作用域是整个工程
//局部变量:局部变量的作用域就是局部变量所在的局部范围
int main()
{
{
int a = 10;//a只能在括号内使用,超出这个范围就不能使用
}
printf("%d\n",a);//运行时会发生报错,因为a超出所在范围
}
//全局变量:全局变量的作用域是整个工程
int a = 10;
void test()
{
printf("test:%d\n",a);
}
int main()
{
test();
printf("main:%d\n",a);
return 0;
}
//在另一个文件中定义的全局变量,需要声明外部符号:extern
extern int g_val;
int main()
{
printf("%d\n",g_val);
return 0;
}
生命周期:变量的生命周期指的是变量的创建到销毁之间的一个时间段
局部变量的生命周期:进入作用域生命周期开始,出作用域生命周期结束
全局变量的生命周期:整个程序的生命周期
常量:
常量:用来描述不变的数据
常量的类型:
字面常量
const修饰的常变量
#define定义的标识符常量
枚举常量
字面常量`
int a = 100;
char ch = 'c';
const修饰的常变量
//这里的n属于变量其值是可以修改的
int n = 10;//n为变量
printf("n=%d\n",n);//10
n = 20;//n为变量
printf("n=%d\n",n);//20
//这里的n属于常变量其值是不可以修改的
const int n = 10;//常变量
printf("n=%d\n",n);
n = 20;//运行时会报错,n的值不能修改
printf("n=%d\n",n);
int arr[10] = {0};//C99标准之前的语法
int n = 10;
int arr[n] = {0};//运行不通过,因为n是个变量,中括号里面的值必须是个常量,但是在C99标准中增加一个变长数组的概念,这里指定数组大小的时候,可以使用变量了
const int n = 10;
int arr[n] = {0};//运行不通过,虽然n具有常属性,但本质上仍是个变量
#define定义的标识符常量
#define MAX 100
MAX = 101;//MAX是个标识符常量,其值不能进行修改
int m = MAX;
printf("%d\n",m);//100
printf("%d\n",MAX);//100
枚举常量
enum Sex
{
male,
female,
secret
};
//枚举是C语言提供的一种自定义类型的方法
male = 10;//male是常量,其值不能修改
printf("%d\n",male);//0
printf("%d\n",female);//1
printf("%d\n",secret);//2
enum Sex s = male;//常规用法
4.字符串+转义字符+注释
字符串:
字符串:由双引号引起来的一串字符称为字符串
字符串的结束标志是一个名为\0的转义字符,在计算字符串长度的时候\0是结束标志,不算作字符串内容
%s:打印字符串
int main()
{
char arr1[] = "abcdef";//结尾处包含一个结束标志\0
char arr2[] = {'a','b','c','d','e','f'};//结尾处不包含结束标志\0
char arr3[] = {'a','b','c','d','e','f','\0'};//结尾处自行添加一个结束标志\0
char arr4[] = "abc\0def";
printf("%s\n",arr1);//输出结果为abcdef
printf("%s\n",arr2);//输出结果为abcdef烫烫烫烫烫abcdef,因为不包含字符串的结束标志\0
printf("%s\n",arr3);//输出结果为abcdef
printf("%s\n",arr4);//输出结果为abc
return 0;
}
转义字符:
转义字符:转义也就是转变它的意思
int main()
{
//\?:在书写连续多个问号时使用,防止他们被解析成三字母词,三字母词??)->]
printf("(are you ok??)");//原本应该输出(are you ok],但最后的运行结果还是输出(are you ok??),编译器无法演示
printf("(are you ok\?\?)\n");//输出(are you ok??),常规用法
//\':用于表示字符常量
//\":用于表示一个字符串内部的双引号
//%c:用于打印字符
printf("%c\n",'a');//输出结果为a
printf("%c\n",'\'');//输出结果为'
printf("%s\n","abc");//输出结果为abc
printf("%s\n","a");//输出结果为a
printf("%s\n","\"");//输出结果为"
//\\:用于表示一个反斜杠,防止它被解释为一个转义序列
//printf("c:\\code\\test.c\n");
//\ddd:ddd表示1-3个八进制的数字,如\130对应X
//\xdd:x表示十六机制,dd表示2个十六进制数字,如\x30对应0
printf("%c\n",'\130');//八进制表示的130转化为十进制为:64+24+0=88,而88对应的ASCII值为字符X
printf("%c\n",'\x30');
int len = 0;
len = strlen("abcdef");
printf("%d\n",len);//结果为6,不计入字符串的结束标志\0
printf("c:\test\628\test.c\n");
printf("%d\n",strlen("c:\test\628\test.c"));//14,十四个字符分别为 c : \t e s t \62(\062) 8 \t e s t . c
//可能有人会问,为什么不是\628,而是\62呢?原因:\ddd中的ddd代表的是八进制数,八进制数中没有8这个数,所以很显然\62 相当于\062
char arr1[] = "abcdef";
char arr2[] = {'a','b','c','d','e','f'};
char arr3[] = { 'a','b','c','d','e','f','\0'};
printf("%d\n",strlen(arr1));//6
printf("%d\n",strlen(arr2));//22 因为不包含字符串零终止符,所以22是个随机值
printf("%d\n",strlen(arr3));//6
return 0;
}
注释:
C语言风格的注释:/xxxxxx/,缺点:不能嵌套注释
C++风格的注释://xxxxxx,优点:可以注释一行也可以注释多行
5.选择语句
int main()
{
int input = 0;
printf("你要好好学习吗(1/0)?:");
scanf("%d",&input);
if (input == 1)
{
printf("好offer!");
}
else
{
printf("卖红薯!");
}
return 0;
}
6.循环语句
int main()
{
int line = 0;
while (line<20)
{
line++;
printf("我要继续努力敲代码:%d\n",line);
}
if (line >= 20)
{
printf("迎娶白富美!\n");
}
}
7.函数
函数的特点:简化代码,代码复用
int Add(a, b)
{
int sum = 0;
sum = a + b;
return sum;
}
int main()
{
int n1 = 0;
int n2 = 0;
int sum = 0;
//输入
scanf("%d %d", &n1, &n2);
//计算求和
sum = n1 + n2;
sum = Add(n1, n2);
//输出
printf("sum=%d\n", sum);
}
8.数组
数组:一组相同类型元素的集合
C语言规定:数组的每个元素都有一个下标,下标是从0开始的
数组可以通过下标来访问
int main()
{
int arr[10] = {10,11,12,13,14,15,16,17,18,19};
printf("%d\n",arr[5]);//15
int i = 0;
//输入
while (i < 10)
{
scanf("%d",&arr[i]);
i++;
}
i = 0;
//输出
while (i < 10)
{
printf("%d ",arr[i]);
i++;
}
char ch[5] = {'a','b','c','d','e'};
return 0;
}
9.操作符
算数操作符:+ - * / %
flaot:打印输出用%f
double:打印输出用%lf
int main()
{
int c = 10 / 3;
printf("%d\n",c);//3
float c = 10 / 3;
printf("%f\n",c);//3.000000
//想要得到3.333333,10和3两个操作数必须含有一个小数或者两个都带小数,如10.0,3.0等
float c = 10.0/ 3;
printf("%f\n", c);
float d = 10/3.0;
printf("%f\n", d);
float e = 10.0/ 3.0;
printf("%f\n", e);
//%:取模,两边的操作数必须都是整数
int a = 10 % 3;
printf("%d\n",a);//1
//移位操作符:>> << 移动的是二进制位,必须把十进制数字转化为二进制演示
//位操作符:& ^ | 操作的是二进制位
//赋值操作符
int a = 10;//初始化
a = 20;//赋值
return 0;
}
‘0’:字符0,对应的ascii码值为48
‘\0’:转义字符,对应的ascii码值为0
0:数字0,就是0,当需要’\0’的地方,放上0也是没问题的
EOF:END OF FILE,文件结束标志,本质是-1,是文件结束标志
一个全局变量未被初始化时,默认会被初始化为0;
一个局部变量未被初始化时,默认会被初始化为随机值;
int a;//一个全局变量未初始化时,默认会被初始化为0
int main()
{
//一个局部变量未初始化时,默认是随机值
int b;
printf("%d\n",b);
printf("%d\n",a);
char ch[10] = "hello bit";//h e l l o '' b i t '\0'
return 0;
}
多组输入:
scanf()返回值:scanf()返回值为读取到的输入值的个数,可以用EOF文件结束标志来判断
案例一:
//多组输入
//scanf()返回值:scanf返回值为读取到的输入值的个数,可以用EOF文件结束标志来判断
int main()
{
int iq = 0;
//输入
while (scanf("%d", &iq)==1)//scanf如果读到一个有效数据,则进入循环,或者写成while(scanf("%d", &iq)!=EOF)
{
//输出
if (iq >= 140)
{
printf("Genius\n");
}
}
return 0;
}
运行结果如下:
案例二:
int main()
{
int iq = 0;
int q = 0;
//输入
while (scanf("%d %d", &iq,&q)==2)//scanf如果读到两个有效数据,则进入循环,或者写成while(scanf("%d %d", &iq,&q)!=EOF)
{
//输出
if (iq >= 140&&q>=140)
{
printf("Genius\n");
}
}
return 0;
}
运行结果如下:
单目操作符:
int main()
{
//逻辑反操作!,在C语言中,0就是假,非0就是真
int a = 10;
int b = !a;//a为10为真,逻辑反操作即为假0
printf("b=%d\n", b);//结果为0
int a = 0;
int b = !a;
printf("b=%d\n",b);//结果为1
int flag = 5;
//如果flag为真做什么事情
if (flag)
{
printf("hehe!\n");//输出hehe!
}
int flag1 = 0;
//如果flag1为假做什么事情
if (flag1)
{
printf("haha\n");//什么也不输出
}
//sizeof:计算操作数的类型长度,以字节为单位
int a = 10;
printf("%d\n",sizeof(a));//4
printf("%d\n",sizeof(int));//4
//~:对一个数的二进制按位取反
//++,--
int a = 10;
int b = ++a;//前置++,先++,后使用,即先对a+1=11,再将a=11的值赋给b
printf("a=%d b=%d",a,b);//11,11
int a = 10;
int b = a++;//后置++,先使用,后++,即先将a=10赋值给b,再将a+1=11
printf("a=%d b=%d", a, b);//11,10
int a = 10;
int b = --a;//前置--,先--,后使用,即先对a-1=9,再将a=9的值赋给b
printf("a=%d b=%d", a, b);//9,9
int a = 10;
int b = a--;//后置--,先使用,后--,即先将a=10赋值给b,再将a-1=9
printf("a=%d b=%d", a, b);//9,10
//(类型):强制类型转换
int a = 3.14;//从double转换到int,可能会丢失数据,输出结果为3
int a = (int)3.14;//强制类型转换
printf("%d\n",a);//输出结果为3
return 0;
}
关系操作符:
==:相等,是两个等号
逻辑操作符:
逻辑操作符:关注的是真与假
&&和||:逻辑与和逻辑或
int main()
{
int a = 10;
int b = 3;
//不输出
if (a == 3 && b == 4)
{
printf("hehe\n");
}
//输出
if (a == 10 || b == 8)
{
printf("haha\n");
}
return 0;
}
条件操作符:
exp1?exp2:exp3:如果1为真,运行2;如果1为假,运行3
int main()
{
int a = 3;
int b = 5;
int m = 0;
m = ((a>b)?a:b);
printf("%d\n",m);//输出5
return 0;
}
逗号操作符:
逗号表达式:会从左向右依次计算,整个表达式的结果是最后一个表达式的结果
int main()
{
int a = 1;
int b = 3;
int c = 4;
int d = (a=b-3,b=a*2,c=a-b);//a=0,b=0,c=0
printf("%d\n",d);
return 0;
}
下标引用操作符[ ]:
int main()
{
int arr[10] = {1,2,3,4,5};//后面会默认补0
printf("%d\n",arr[8]);//0
return 0;
}
10.常见关键字
typedef:类型重定义
typedef unsigned int uint;//将unsigned int重命名为uint
int main()
{
//无符号的整型变量
unsigned int num1 = 0;
uint num2 = 0;
return 0;
}
register:寄存器关键字
寄存器:计算机中的一种存储器,是集成到CPU上的
寄存器<-高速缓存(cache)<-内存<-硬盘<-网盘(越往上速度越来越快,造价越来越高)
int main()
{
register int num = 10;
//register只是起到一个建议的作用,建议将num的值放在寄存器中,但最终是否放入还是由编辑器决定的
//寄存器变量是不能取地址的,因为取地址取的是内存的地址,而register是集成在cpu上的,因而是无法取地址的
return 0;
}
static关键字:
static修饰的局部变量:
static修饰局部变量的时候,改变了局部变量的存储类型,本来一个局部变量是存储在栈区,而被static修饰的局部变量是存储在静态区的;
在栈区上的局部变量,出了作用域生命周期结束,变量被销毁;而被static修饰的局部变量,出了作用域生命周期没有结束,变量也不销毁;
static修饰的局部变量的生命周期和程序的生命周期一样;
static修饰局部变量改变了变量的生命周期,让静态局部变量出了作用域依然存在,到程序结束,生命周期才结束
案例一:
void test()
{
int n = 1;
n++;
printf("%d ",n);//n的值不发生变化,为2
}
int main()
{
int i = 0;
while (i < 10)
{
test();
i++;
printf("%d\n",i);
}
return 0;
}
运行结果:
案例二:
void test()
{
static int n = 1;
n++;
printf("%d ",n);//n的值为2,3,4,5,6,7,8,9,10,11
}
int main()
{
int i = 0;
while (i < 10)
{
test();
i++;
}
return 0;
}
运行结果:
static修饰的全局变量:
static修饰全局变量的时候,改变了全局变量的链接属性,本来一个全局变量是具有外部链接属性的,但是被static修饰后就变成了具有内部链接属性,这时static修饰的全局变量只能在本源文件(.c)中使用,其他文件无法再使用;
在c中,源文件扮演模块的角色。任何带有static属性声明的全局变量或者函数都是模块私有的。类似的,任何不带static属性的全局变量和函数都是公有的,可以被其他模块访问
案例一:
add.c
int g_val = 10;
test.c
//extern是用来声明外部符号的
extern int g_val;//extern可加可不加
int main()
{
printf("%d\n",g_val);//10
return 0;
}
运行结果:案例二:
add.c
static int g_val = 10;
//test.c函数编译不通过,因为static修饰的全局变量,改变了全局变量的链接属性
test.c
//extern是用来声明外部符号的
extern int g_val;//extern可加可不加
int main()
{
printf("%d\n",g_val);//运行不通过
return 0;
}
运行结果:
static修饰函数:
static修饰函数和修饰全局变量是类似的,一个函数本来也是具有外部链接属性的,当被static修饰的时候,外部链接属性就变成了内部链接属性,这个函数就只能在本源文件内部使用,其他文件不能再使用
案例一:
add.c
//函数也是具有外部链接属性的
int Add(int x, int y)
{
int z = x + y;
return z;
}
test.c
//声明来自外部的函数
extern int Add(int,int);
int main()
{
int a = 0;
int b = 0;
scanf("%d %d",&a,&b);
int sum = Add(a, b);
printf("%d\n",sum);
return 0;
}
运行结果:
案例二:
add.c
//static修饰的函数
static int Add(int x, int y)
{
int z = x + y;
return z;
}
test.c
//声明来自外部的函数
extern int Add(int,int);
int main()
{
int a = 0;
int b = 0;
scanf("%d %d",&a,&b);
int sum = Add(a, b);
printf("%d\n",sum);
return 0;
}
运行结果:
10.#define定义常量和宏
#define定义标识符常量
//#define 定义标识符常量
#define NUM 100
#define STR "hehe"
int main()
{
printf("%d\n",NUM);//100
printf("%s\n",STR);//hehe
return 0;
}
#define定义宏
//#define 定义宏 宏是有参数的
#define ADD(x,y)((x)+(y))//带括号
int main()
{
int a = 10;
int b = 20;
int sum = ADD(a, b);//int sum = ((a)+(b));
printf("%d\n",sum);//30
return 0;
}
11.指针
内存:
外存:又叫外部存储器,长期存放数据,掉电不丢失数据
内存:又叫内部存储器,暂时存放数据,掉电数据丢失,又可分为物理内存和虚拟内存。物理内存:实实在在存在的存储设备;虚拟内存:操作系统虚拟出来的内存。在32位系统下,每个进程(运行的程序)的寻址范围是4G,即0x00 00 00 00-0xff ff ff ff。在写应用程序时,我们看到的都是虚拟地址。
在运行程序时,操作系统会将虚拟内存进行分区:
堆区:在动态申请内存时,在堆区开辟内存;
栈区:主要存放局部变量,主要是在函数内部或者复合语句内部定义的变量;
静态全局区:未初始化的静态全局区(静态变量(定义的时候,前面加static修饰)或全局变量在没有初始化时,存放在此区域);初始化的静态全局区(全局变量或静态变量赋过初值的,存放在此区));
代码区:存放咱们的程序代码
文字常量区:存放常量的
内存是以字节为单位来存储数据的,咱们可以将程序中的虚拟存储空间,看成一个很大的一维的字符数组
指针:
系统给虚拟内存的每个存储单元分配了一个编号,从0x00 00 00 00-0xff ff ff ff,这个编号就称之为地址,指针就是地址。
指针变量:是个变量,是个指针变量,即这个变量用来存放一个地址编号;
在32位平台下,地址总线是32位的,所以地址是32位编号,所以指针变量是32位的,即4个字节;
无论什么类型的地址,都是存储单元的编号,在32位平台下都是4字节,即任何类型的指针变量都是4字节大小。
对应类型的指针变量,只能存放对应类型的变量的地址
多字节的变量,对应多个地址编号,编号最小的地址编号就是多字节变量的地址
指针变量的定义方法:
int *p;//在定义指针变量的时候,*是用来修饰变量的,说明变量p是个指针变量,变量名为p
&:取地址;*:取值
int main()
{
int num = 10;
#//取出num的地址
printf("%p\n",&num);//打印地址,%p以地址的形式打印
return 0;
}
int a=0x1234abcd;
int *p=NULL;
P=&a;//p保存了a的地址,也可以说p指向了a
//a的值是0x1234abcd,假如a的地址是:0xbfe89868,则关系图如下图所示
int num;
num=*p;//在调用时,*代表取值的意思,*p就相当于p指向的变量,即a,所以num=*p和num=a的效果是一样的
如果在一行当中定义了多个指针变量,每个指针变量的前面都需要加*来修饰
int *p,*q;//定义了两个整型的指针变量p和q
int *p,q;//定义了一个整型指针变量p,和整型的变量q
int main()
{
int a = 100, b = 200;
int* p_1, * p_2 = &b;//表示该变量的类型是一个指针变量,指针变量名是p_1而不是*p_1;
//p_1在定义的时候没有赋初值,p_2赋了初值
p_1 = &a;//p_1先定义后赋值
printf("%d\n",a);
printf("%d\n",*p_1);
printf("%d\n",b);
printf("%d\n", *p_2);
return 0;
}
//在定义p_1的时候,因为是个局部变量,局部变量没有赋初值,它的值是随机的,p_1指向哪里不一定,所以p_1是个野指针
指针的大小:
32位机器:支持32位的虚拟地址空间,产生的地址就是32bit位的,那么就需要32bit的空间存储->4byte;
64位机器:支持64位的虚拟地址空间,产生的地址就是64bit位的,那么就需要64bit的存储空间->8byte;
32位平台下地址是32bit位(即4个字节);
64位平台下地址是64bit位(即8个字节);
int main()
{
char ch = 'w';
int n = 100;
double d = 3.14;
char* pc = &ch;
int* pi = &n;
double* pd = &d;
printf("%d\n",sizeof(pc));//4
printf("%d\n",sizeof(pi));//4
printf("%d\n",sizeof(pd));//4
return 0;
}
指针和变量的关系:
*+指针变量:就相当于指针指向的变量
int main()
{
int* p1, * p2, temp, a, b;
p1 = &a;
p2 = &b;
printf("请输入a,b的值:\n");
scanf("%d %d",&a,&b);
temp = *p1;
*p1 = *p2;
*p2 = temp;
printf("a=%d b=%d\n",a,b);
printf("*p1=%d *p2=%d\n",*p1,*p2);
return 0;
}
运行结果:
如果想让不同类型的指针相互赋值的时候,需要强制类型转换;
通用指针void* p:可以存放任何类型的变量的地址编号
int main()
{
int a = 0x12345678, b = 0xabcdef66;
char* p1, * p2;
printf("%0x %0x\n",a,b);
p1 = (char*)&a;
p2 = (char*)&b;
printf("%0x %0x\n",*p1,*p2);
p1++;
p2++;
printf("%0x %0x\n",*p1,(0xff)&(*p2));
return 0;
}
运行结果:
注意:
*+指针:取值,取几个字节,由指针类型决定的;指针为字符指针则取一个,指针为整型指针择取四个字节,指针为double型指针则取8个字节。
指针++:指向下个对应类型的数据。字符指针++,指向下个字符数据,指针存放的地址编号加1;整型指针++,指向下个整型数据,指针存放的地址编号加4
12.结构体
//定义一个结构体
struct Stu
{
char name[20];
int age;
char sex[5];
double score;
};
int main()
{
struct Stu s1 = {"张三",20,"男",90.5};
struct Stu s2 = {"如花",40,"女",99.5};
//输入
scanf("%s %d %s %lf",s1.name,&(s1.age),s1.sex,&(s1.score));//age和score前面必须要加&
//方式一
printf("%s %d %s %lf\n",s1.name,s1.age,s1.sex,s1.score);
//结构成员访问操作符:结构体变量.结构体成员
//方式二:
struct Stu* ps = &s1;
printf("%s %d %s %lf\n",(*ps).name,(*ps).age,(*ps).sex,(*ps).score);
//方法三:
printf("%s %d %s %lf\n",ps->name,ps->age,ps->sex,ps->score);
//结构成员访问操作符:结构体指针->结构体成员
return 0;
}