C语言(变量,结构体,内存管理、位运算及优先级)笔记-day4

目录

前言

一、变量

1.定义规则

2.局部变量

3.全局变量

4.关键字

5.静态变量与动态变量

二、结构体

1.访问成员变量

2.结构体指针

3.内存空间大小

三、内存管理

1.静态内存

2.动态内存

四、位运算符与优先级

1.位运算符

2. 运算符优先级

总结



前言

今天主要学习变量、结构体、内存管理和位运算符以及运算符的优先级,会各自进行C语言的基础拓展,重点是掌握局部变量、全局变量在生命周期、作用域的区别,以及关键字static、const、extern修饰下的区别;结构体的大小、使用、成员变量的访问;动态内存与静态内存;位运算符以及常见运算符的优先级问题


一、变量

1.定义规则

数据类型 变量名 变量名可以由英文字母,数字,和_组成,不可以以数字开头,实际编程工作中,一个项目常常由多个人合作完成,所以名字应该简明清晰,可采用Linux、Windows风格

2.局部变量

局部变量:定义在函数内部的变量 称为局部变量  未初始化时程序自动初始化为随机数 

作用域:只在定义的函数内部有效 生命周期:随着函数调用结束而生命终止,所占用的空间自动释放。

#include <stdio.h>
void fun()
{
	int x = 100;//x就是一个局部变量
}
int main()
{
	printf("x is %d\n", x);
}

 程序编译未通过,x未定义,这说明fun()函数内的x 与main函数的x无关。

    1 两个不同函数中可以有同名变量
    2 局部变量只在所定义的函数中有效
    3 参数和局部变量也不能同名
    4 局部变量如果没赋初值,那么值为 随机值
    5 局部变量,是局部作用域,作用域在{ }之间

3.全局变量

全局变量:定义在函数外面的变量是全局变量   未初始化时程序自动初始化为0 

作用域:整个函数,在程序的任何位置都可以访问,但当与局部变量重名时,优先使用局部变量   生命周期:随着整个函数结束而生命终止,

4.关键字

static const  

static 修饰局部变量时,将局部变量的生命周期拓展到整个函数,但其作用域不变,但函数调用结束后,局部变量不会消亡,会继续存在

         修饰全局变量时,限制只能在定义的文件中使用,内部链接,防止其他源文件引用导致错误

具有静态存储 、内部链接性质

       修饰函数时,限制只能在定义函数的源文件中使用,调用时产生、调用结束时消亡。

const 外部引用说明符:作用是告诉程序,const修饰的变量在其他文件中 不可赋初值,常用修饰全局变量

extern sizeof typedef

extern 常量化 :在C语言中常量是不可修改的,当它修饰变量时,变量变成常量;修饰指针时

 sizeof() 作用:求变量、数组、结构体等等的占内存空间的大小,在前面

typedef 类型重定义:起外号,例如int a;   typedef int  ww   ww a; 等于int a 再以后的编程中会经常用到,可大大提高程序的可移植性。

5.静态变量与动态变量

静态变量与动态变量是变量的存储方式

二者区别: 1.静态变量是程序编译时就分配了内存空间且保持不变;动态变量是程序运行时才分配空间的且调用结束后会立即释放,比如实参初始化形参。

                    2.静态变量未初始化自动赋值0,只能赋值一次且每次调用后会被保存;动态变量未初始化自动赋值随机数,每次调用每次赋值

自动变量即局部变量,具有动态存储、代码块作用域、空链接

静态变量类型说明符:static  具有静态存储、代码块作用域、空链接 注意:外部变量虽然属于静态存储方式,但不一定是,只有static修饰的才是静态变量,根据修饰的变量类型又可分为静态局部变量和静态全局变量;未使用static修饰的静态变量具有静态、外部链接存储类型,使用的就是具有静态、内部链接类型。

练习:编写一个函数,完成下面功能,能将Hello World!   转换成Lipps Asvph!

#include <stdio.h>
void changeString(char *s)
{
	int i = 0;
	while(s[i] != '\0')
	{
		if((s[i] >= 'a' && s[i] <= 'v')||(s[i] >= 'A' && s[i] <= 'V'))
		{
			s[i] += 4;
		}
		else if((s[i] >= 'w' && s[i] <= 'z')||(s[i] >= 'W' && s[i] <= 'Z'))
		{
			s[i] = s[i] + 4 - 26;
		}
		i++;
	}
}
int main(int argc, const char *argv[])
{
	char a[] = "Hello World!";
	puts(a);
	changeString(a);
	puts(a);
	return 0;
}

练习:约瑟夫问题  选猴王

按顺时针方向从1到8编号。然后从1号猴子开始沿顺时针方向从1开始报数,报到m的猴子出局,再从刚出局猴子的下一个位置重新开始报数,如此重复,直至剩下一个猴子,它就是大王。设计并编写程序,实现如下功能:
    (1)    要求由用户输入报的数m。
    (2)    给出当选猴王的编号。

#include <stdio.h>

int main(int argc, const char *argv[])
{
	int i;
	int kill_post;//用来保存每一轮猴子出局的下标
	int all_num = 6;//猴子总数
	int start_num = 2;//从几开始数
	int kill_num = 3;//数到几出局
	int a[100] = { 0 };//所有的元素都是0
	printf("请您输入猴子的总数 开始数号码 数到几出局:\n");
	scanf("%d%d%d",&all_num,&start_num,&kill_num);
	//1.将1-all_num编号赋值到数组中0-all_num-1下标对应的元素
	for(i = 0; i < all_num; i++)//i == 0 1 2 3 4 5
	{
		a[i] = i+1;//i+1 1 2 3 4 5 6
	}
	//2.找到第一个出局猴子在数组中的下标
	kill_post = (start_num + kill_num - 2) % all_num;
	//3.循环杀猴 
	while(a[1] != 0)//a[1] == 0循环结束,出现猴王
	{
		printf("kill -----> %d\n",a[kill_post]);
		//逐个向前移动一个位置,覆盖删除
		for(i = kill_post; i < all_num; i++)
		{
			a[i] = a[i+1];
		}
		//删除之后,当前猴子的总数-1
		all_num--;
		//找到下一次,即将被杀死猴子的下标
		kill_post = (kill_post + kill_num - 1) % all_num;
	}
	printf("monkey king is %d\n",a[0]);
	return 0;
}

二、结构体

    结构体:是一个 自定义的 数据类型

      如何定义结构体(是一个新类型,等同于int, char, float, double,可以用结构体定义变量)

     如何定义结构体变量

1.访问成员变量

如何通过结构体变量访问结构体成员   "."为成员运算符,可以访问结构体成员和赋值

 练习:定义一个结构体worker,有下面成员,姓名、编号、年龄、工资(float)输入信息,并输出

#include <stdio.h>
#include <string.h>
//保存一个学生的基本信息 自己发明创造出一个 数据类型
struct student
{
	char name[20];//成员变量
	int age;//成员变量
	int score;//成员变量 
};//注意此处一定要有;号


int main(int argc, const char *argv[])
{
	struct student s = {"asan",19,108};
	//打印结构体中的成员变量
	printf("name:%s age:%d score:%d\n",s.name,s.age,s.score);
	puts("Please input name age score:");
	scanf("%s%d%d",s.name,&s.age,&s.score);//s.name不加&,因为name是数组的名字,已经是地址了
	printf("name:%s age:%d score:%d\n",s.name,s.age,s.score);
	
	//定义一个结构体指针
	struct student *p = &s;//p指向了s
	//结构体变量访问成员变量 用 .
	//结构体指针访问成员变量 用 -> 
	printf("name:%s  age:%d score:%d\n",p->name,p->age,p->score);
	return 0;
}			

2.结构体指针

指向结构体的指针    定义指针变量,指向一个结构体变量 如果用指针变量访问结构体成员

 值传递

如果将 打印学生信息 写成一个函数,我们就可以将学生结构体作为参数传递给函数,

#include <stdio.h>
#include <string.h>
struct student
{
	char name[20];//成员变量
	int age;//成员变量
	int score;//成员变量 
};//注意此处一定要有;号

//值传递
void setStudentInfo(struct student a)
{
	printf("Please input name age score:\n");
	scanf("%s%d%d",a.name,&a.age,&a.score);
}


int main(int argc, const char *argv[])
{
	struct student s;//里面的成员变量是随机数
	setStudentInfo(s);//值传递,不能够修改实参变量s的值
	printf("值传递: name:%s  age:%d  score:%d\n",s.name,s.age,s.score);
	return 0;
}

 地址传递

#include <stdio.h>
#include <string.h>
struct student
{
	char name[20];//成员变量
	int age;//成员变量
	int score;//成员变量 
};//注意此处一定要有;号

//地址传递
void setStudentInfo(struct student *p)
{
	printf("Please input name age score:\n");
	scanf("%s%d%d",p->name,&p->age,&p->score);
}


int main(int argc, const char *argv[])
{
	struct student s;//里面的成员变量是随机数
	setStudentInfo(&s);//地址传递
	printf("地址传递: name:%s  age:%d  score:%d\n",s.name,s.age,s.score);
	return 0;
}	

传递结构体数组 如果给函数传递结构体变量,尽量使用指针,好处是节省内存空间 

值: a[i] == p[i] == *(p+i) == *(a+i)
地址:&a[i] == &p[i] == p+i == a+i

练习:定义一个结构体数组,且通过地址传递去输出全班基本信息

#include <stdio.h>
#include <string.h>
struct student
{
	char name[20];//成员变量
	int age;//成员变量
	int score;//成员变量 
};//注意此处一定要有;号

void showArray(struct student *p, int n)
{
	int i;
	for(i = 0; i < n; i++)
	{//p[i]代表的是数组中的元素,访问成员变量用.
		printf("%s %d %d\n",p[i].name,p[i].age,p[i].score);
	//p+i代表的是地址,即指针,访问成员变量用 ->
		printf("%s %d %d\n",(p+i)->name,(p+i)->age,(p+i)->score);
	}
}
int main(int argc, const char *argv[])
{
	//定义一个结构体数组,来保存全班的基本信息
	struct student s[3] = {{"lanmao",19,100},{"taoqi",17,89},{"bienao",16,90}};
	showArray(s,3);
	return 0;
}

练习:写一个函数, 实现输入5个学生信息且将结构体数组传递给函数,查询其中年龄 > 25的student,并且输出该student的基本信息

#include <stdio.h>

struct student
{
	char name[20];
	int age;
	int score;
};

void setStudentInfo(struct student *p, int n)
{
	//a[i]==p[i]==*(p+i)==*(a+i)
	//&a[i]==&p[i]==p+i==a+i
	int i;
	for(i = 0; i < n; i++)
	{
		printf("Please input name age score:");
		scanf("%s%d%d",p[i].name,&p[i].age,&p[i].score);
	}
}

void showStudentInfo(struct student *p, int n)
{
	int i;
	for(i = 0; i < n; i++)
	{
		printf("%s %d %d\n",p[i].name,(*(p+i)).age,p[i].score);
		printf("%s %d %d\n",(p+i)->name,(p+i)->age,(&p[i])->score);
	}
}
void findByAge(struct student *p, int n, int age)//aged代表查询大于的年龄
{
	int i; 
	for(i = 0; i < n; i++)
	{
		if(p[i].age > age)
		{
			printf("查询结果:%s %d %d\n",p[i].name,p[i].age,p[i].score);
		}
	}
}
int main(int argc, const char *argv[])
{
	struct student s[5];
	setStudentInfo(s,5);
	findByAge(s,5,25);
	showStudentInfo(s,5);
	return 0;
}	

3.内存空间大小

计算结构体占用内存空间大小

  1. 先看最长的 (2 4),最后的算出的大小一定要是最长的倍数
  2. 在补齐的时候,以下面的为标准进行补齐
  3. 当补齐的时候,为结构体最后一个的时候,将长度补齐为最长的倍数

三、内存管理

如果使用虚拟机模拟4G空间的话,1G Linux内核 3G用户

再3G用户中,分别时常量区、全局变量、变量区存储再栈区,申请空间函数malloc是在堆区申请的,可能会失败所以需要判断,如果成功会返回堆空间的地址,否则为NULL ;使用完全后需要手动释放free()。

1.静态内存

静态分配:在编译时确定内存的大小  数组元素个数一定是一个常量

2.动态内存

          动态内存分配:在运行时再确定内存的大小  void *malloc(int size)

功能:在堆空间申请一个块连续的内存  函数参数:int size 申请空间的大小 以字节为单位

返回值:如果成功,返回申请那块那块内存空间的首地址;如果失败,返回NULL,是一个空指针

使用完后需要手动释放,释放空间

      练习:定义有n个元素的动态数组,并输出

#include <stdio.h>
#include <stdlib.h>
int main(int argc, const char *argv[])
{
	//我想在堆空间申请5个int 
	int n;//用来代表学生的总人数
	int i;
	printf("请您输入学生的总人数:\n");//在申请空间之前,先确定学生的总人数
	scanf("%d",&n);
	int *p = malloc(n*sizeof(int));
	//malloc申请空间,有可能失败,所以一定要在申请之后,加上条件判断
	if(p != NULL)
	{
		printf("请输入%d个学生成绩:\n",n);
		for(i = 0; i < n; i++)
		{
			scanf("%d",p+i);
		}
		for(i = 0; i < n; i++)
		{
			printf("%d ",p[i]);
		}
		printf("\n");
		free(p);
	}
	return 0;
}

     练习:学生人数由输入确定,动态分配内存,保存学生成绩,然后求出学生平均成绩

#include <stdio.h>
#include <stdlib.h>

int main(int argc, const char *argv[])
{
	//我想在堆空间申请5个int 
	int n;//用来代表学生的总人数
	int i,sum = 0;
	//在申请空间之前,先确定学生的总人数
	printf("请您输入学生的总人数:\n");
	scanf("%d",&n);
	int *p = malloc(n*sizeof(int));//总人数是多少,我就申请多少个int
	//malloc申请空间,有可能失败,所以一定要在申请之后,加上条件判断
	if(p != NULL)
	{
		printf("请输入%d个学生成绩:\n",n);
		for(i = 0; i < n; i++)
		{
		//	scanf("%d",&p[i]);
			scanf("%d",p+i);
			sum += p[i];
		}
		printf("sum is %d\navg is %.2f\n",sum,(float)sum/n);
		//动态内存分配需要手动申请,手动释放
		free(p);//函数参数是申请空间的首地址,释放空间
	}
	return 0;
}		

四、位运算符与优先级

代码程序存储在电脑内存中是以补码形式存在的,所以熟练使用转化方法是必须的

1.位运算符

&按位与  1代表真,0代表假,同真为真,一假即假

|  按位或 1代表真,0代表假,同假为假,一真即真

 ^ 异或     1代表真,0代表假,相同为假,不同为真

 正数 原码 == 反码 == 补码
负数 原码 反码(原码的符号位不变,其它位取反) 补码(反码+1)

 练习:求一个int a = 10类型数据 求二进制位1 的个数

#include <stdio.h>

//方法一
int getBin(int num)
{
	int count = 0;
	while(num != 0)//num == 0循环结束
	{
		if(num % 2 == 1)//先%再/
		{
			count++;
		}
		num /= 2;//等价于 num = num / 2;
	}
	return count;
}
//方法二 
int getBin2(int num)
{//用位运算
	int i;
	int count = 0;
	for(i = 0; i < 32; i++)
	{
	//	if(num & (1<<i))//i = 0 1 2 3 4 ..31
		if((num & (1<<i)) != 0)//此if等价于上面的写法
		{
			count++;
		}
	}
	return count;
}

int main(int argc, const char *argv[])
{
	int num;
	scanf("%d",&num);
	printf("%d中1的个数是:%d\n",num,getBin2(num));
	return 0;
}

      置1 用 |       置 0用 &

2. 运算符优先级

优先级口诀:

括号成员第一 全体单目第二
乘除余三、加减四
移位五、关系六
按位与、异或、按位或 八九十

总结

       主要学习变量、结构体、内存管理和位运算符以及运算符的优先级,会各自进行C语言的基础拓展,重点是掌握局部变量、全局变量在生命周期、作用域的区别,以及关键字static、const、extern修饰下的区别;结构体的大小、使用、成员变量的访问;动态内存与静态内存;位运算符以及常见运算符的优先级问题

  • 1
    点赞
  • 2
    收藏
    觉得还不错? 一键收藏
  • 0
    评论

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

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

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值