C

#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
//主函数
int main() {
	printf("222");
  return 0; 
#include <stdio.h>
int main() { 
	int num1;
	int num;
	scanf("%d %d", &num, &num1
	int	num2 = num + 
	printf("%d",num2);
	return 0;
}

全局变量的作用域是整个工程 整个程序的生命周期

extern int a;
void test() {
	printf("test---->%d", a);
}
int main() { 
	{
		printf("test---->%d", a); 
	}
	printf("test---->%d", a);
	test();
	return 0;
}

在c语言中,const修饰的a,本质是变量,但是不能被修改,有常量的属性。 #define max 100 标识符常量


	char arr1[] = "abc";
	char arr2[] = {'a','b','c'};
	printf("%s\n", arr1);
	printf("%s\n", arr2);
	 // \0在计算机中属于结束标志
	char arr3[] = "abcd";
	char arr4[] = { 'a','b','c','d','\0'};
	printf("%s\n", arr3);
	printf("%s\n", arr4);
	return 0;

逗号表达式就是逗号隔开的一串表达式 特点是:从左向右依次计算,整个表达式的结果是最后一个表达式的结果

	int a=10;
	int b=20;
	int c = 0;
	//			c=8    a=28        5
	int d = (c = a - 2, a = b + c, c - 3);
	printf("%d\n", d); 

常见的关键字

auto break caseswitch char const continue default do double else float int long short enum extern for goto if register return signed unsigned struct union return sizeof static typeof void volatile while

19/179

typedef 类型定义,类型重命名

typedef struct  Node
{
	int data;
	struct Node* next;
}Node;
typedef unsigned int unit;
int main() {  
	unsigned int num = 0;
	unit num2 = 0;
	struct Node n;
	Node n2;
	}

static修饰局部变量的时候不销毁(栈区 堆区 静态区)

static 修饰全局变量的时候,这个全局变量的外部链接属性就变成了内部链接属性。其他源文件.c就不能再使用了 修饰函数同理

指针

指针是内存中一个最小单元的编号,也就是地址

平时口语中说的指针,通常指的是指针变量,是用来存放内存地址的变量

内存单元 编号->地址->地址也被称为指针

打印地址 int* 存地址

int a = 10;
printf("%p", & a);
int* p = &a;//p就是指针变量int说明p Int说明p指向的对象是int类型*说明p是指针变量
*p = 20;//*解引用操作符,意思就是通过p中存放的地址,找到p所指向的对象,*p就是p指向的对象 a=20

/指针变量的大小取决于一个地址存放的时候需要大多空间 //32位平台下地址是32个bit位(即4个字节)//64位平台下地址是64个bit位(即8个字节)

指针类型决定了指针在被解引用的时候访问几个字节如果是int的指针,解引用访问4个字节 如果是char的指针,解引用访问1个字节

char* pc = (char*)&a;//int*
*pc = 0;

指针的类型决定了指针向前或者向后走一步有多大(距离)

char* pc
*pc 访问一个字节
pc+1
int * pi
*pi 访问四个字节
pi +1
int a = 0x11223344;
int* pa = &a;
char* pc = (char*)&a;
printf("pa = %p\n", pa);
printf("pa+1 = %p\n", pa + 1);
printf("pc = %p\n", pc);
printf("pc+1 = %p\n", pc + 1);

野指针

就是指针指向的位置是不可知的(随机的、不正确的、没有明确限制的)

int * p3=null;
*p3=100;//err

如何规避野指针 指针初始化 小心指针越界 指针指向空间释放即使置NULL 避免返回局部变量的地址 指针使用之前检查有效性

指针运算

	float values[5];
		float* vp;
		for (vp = &values[0]; vp < &values[5];)
		{
			*vp ++ = 0;
		}

不是所有的指针都能相减 指向同一块空间的2个指针才能相减

二级指针

int a=10;
int *pa=&a;//一级指针变量
int **ppa=&pa//二级指针变量
// *pa=20
//**ppa=20
printf("%d \n",a)

存放指针的数组就是指针数组

int * parr[10]={&a,&b}
printf("%d",*(parr[i])

指针进阶

指针数组 int *p[10]

数组指针int (*p)[10]

char* arr[5]={0}
char * (*pc)[5]=&arr;

数组名通常表示的都是数组首元素的地址'但是有2个例外: 数组名通常表示的都是数组首元素的地址‘但是有2个例外:

  1. sizeof(数组名),这里的数组名表示整个数组,计算的是整个数组的大小 1.相当大(数组名),这里的数组名表示整个数组,计算的是整个数组的大小)

2.8数组名,这里的数组名表示的依然是整个数组,所以&数组名取出的是整个数组的地址 2.8数组名,这里的数组名表示的依然是整个数组,所以&数组名取出的是整个数组的地址

题目名称:
下面代码关于数组名描述不正确的是( )a
int main()
int arr[10] = {0};
return 0;
题目内容:
A .数组名arr和&arr是一样的
B .sizeof(arr), arr表示整个数组
C .&arr, arr表示整个数组
D .除了sizef(arr)和&arr中的数组名,其他地方出现的数组名arr,都是数组首元素的地址。 

函数指针


	int Add(int x, int y) {
		return (x + y);
	}
	int main() {      
	  
		int (*pf)(int, int) = &Add;
		int ret = (*pf)(2, 3);
		//int ret = pf(2, 3);
		//int ret = Add(2, 3);
		printf("%d \n", ret);

int a = 10; // char* pa = &a; / /int* void* pv = &a; //void*是无具体类型的指针,可以接受任意类型的地址

/void*是无具体类型的指针,所以不能解引用操作,也不能+-整数

结构体

struct Peo{
char name[20];
char tele[12];
char sex[5];
int high;
}p1,p2;//p1,p2是两个全局变量的结构体

​ struct Stu s 局部

void refprint(struct Stu* ps) {
	printf("%s 年龄 %d", (*ps).name, (*ps).age);
	//->
	//结构体指针变量->成员名
	printf("%s 年龄 %d", ps->name,ps->age);
};
int main() {  
	struct Stu s = { "xiao",20 };//结构体变量
    printf("%s 年龄 %d",s.name,s.age );
	//结构体对象.成员名 
	refprint(&s); 
	return 0;
}
void refp(struct Stu ps) {
	printf("%s 年龄 %d", ps.name, ps.age);
};

结构的成员可以是标量、数组、指针,甚至是其他结构体。

int main(
print1(s);//传结构体
print2(&s);//传地址return 0;
}
上面的print1和print2函数哪个好些?
答案是:首选print2函数。
原因:
函数传参的时候,参数是需要压栈的。
如果传递一个结构体对象的时候,结构体过大,参数压栈的的系统开销比较大,所以会导致性能的下降。
结论:
结构体传参的时候,要传结构体的地址。

1.6结构体内存对齐 我们已经掌握了结构体的基本使用了。 现在我们深入讨论一个问题: 计算结构体的大小。 这也是一个特别热门的考点:结构体内存对齐

考点
如何计算?
首先得掌握结构体的对齐规则:
1.第一个成员在与结构体变量偏移量为0的地址处。
2.其他成员变量要对齐到某个数字(对齐数)的整数倍的地址处。
对齐数=编译器默认的-一个对齐数与该成员大小的较小值。
0 VS中默认的值为8
3.结构体总大小为最大对齐数(每个成员变量都有一一个对齐数)的整数倍。
4.如果嵌套了结构体的情况,嵌套的结构体对齐到自己的最大对齐数的整数倍处,结构体的整
体大小就是所有最大对齐数( 含嵌套结构体的对齐数)的整数倍。

为什么存在内存对齐? 大部分的参考 资料都是如是说的: 1.平台原因(移植原因): 不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特 定类型的数据,否则抛出硬件异常。

2.性能原因: 数据结构(尤其是栈)应该尽可能地在自然边界上对齐。 原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一-次访 问。

2.位段

结构体讲完就得讲讲结构体实现位段的能力。 2.1什么是位段 位段的声明和结构是类似的,有两个不同: . 1.位段的成员必须是int、unsigned int 或signed int 。 2.位段的成员名后边有一个冒号和一一个数字。

struct A
{
int _a:2;
int _b:5;
int _C:10;
int _d:30;
};

位段是可以节省空间的

2.2位段的内存分配 1.位段的成员可以是int unsigned int signed int或者是char (属于整形家族)类型 2.位段的空间上是按照需要以4个字节( int)或者1个字节( char)的方式来开辟的。 3.位段涉及很多不确定因素,位段是不跨平台的,注重可移植的程序应该避免使用位段。

2.3位段的跨平台问题
1. int位段被当成有符号数还是无符号数是不确定的。
2.位段中最大位的数目不能确定。(16位机器最大16, 32位机器最大32,写成27,在16位机器会出问题。
3.位段中的成员在内存中从左向右分配,还是从右向左分配标准尚未定义。
4.当一个结构包含两个位段,第二个位段成员比较大,无法容纳于第一个位段剩余的位时, 是舍弃剩余的位还是利用,这是不确定的。
总结:
跟结构相比, 位段可以达到同样的效果,但是可以很好的节省空间,但是有跨平台的问题存在。 

3.枚举

枚举顾名思义就是一- -列举。 把可能的取值一- -列举。 比如我们现实生活中: -周的星期一-到星期日是有限的7天,可以一- -列举。 性别有:男、女、保密,也可以 比特就兆遇专注IT大学生就业的精品课程 月份有12个月,也可以一- -列举 这里就可以使用枚举了。

enumT Day//星期
{
Mon,
Tues,
Wed ,
Thur,
Fri,
Sat,
Sun
};

3.2枚举的优点 为什么使用枚举? 我们可以使用#define定义常量,为什么非要使用枚举? 枚举的优点: 1.增加代码的可读性和可维护性 2.和#define定义的标识符比较枚举有类型检查,更加严谨。 3.防止了命名污染(封装) 4.便于调试

(预处理)----->编译--->------>链接-->. exe调试  

5.使用方便, - -次可以定义多个常量

4.联合(共用体)

4.1联合类型的定义 联合也是一种特殊的自定义类型 这种类型定义的变量也包含一系列的成员, 特征是这些成员公用同一块空间(所以联合也叫共用体) 比如:

union un{

}

判断当前计算机的大小端存储 4.3联合大小的计算 ●联合的大小至少是最大成员的大小。 ●当最大成员大小不是最大对齐数的整数倍的时候,就要对齐到最大对齐数的整数倍。

分支结构

	if (3 == 3)
		printf("hh");
	else
		printf("hh2");
		多条语句加括号同C#
	if (3 == 4)
		if(2==2)
		printf("hh");
	else
		printf("hh2");
//else与最近的if对齐,故此什么都不打印输出

C语言字符串为什么不用加& 数组名就代表数组的首地址 &数组名并不是对数组名取地址

scanf("格式控制","变量地址")

对于格式"%s",对应的参数应该是地址。作为字符数组的product1.cName、product1.cShape等,用作函数实参时,会被自动转化为指针,指针指向的就是地址,所以不需要加取址符&,所以
scanf("%s",product1.cName);是对的,而scanf("%s",&product1.cName);是错的。

语言输入缓存区getchar

 while(getchar()!='\n')
        continue;
char ch = '\0';
	while ((ch=getchar())!=EOF)
	{
		if (ch < '0' || ch>'9')
			continue;
		putchar(ch);
	} 
	//只能打印数字字符
	int arr[] = { 73,99,126,44 };
	int i = 0;
	int arrlength = sizeof(arr) / sizeof(arr[0]); 
	while (i< arrlength)
	{
		printf("%c", arr[i]);
		i++;
	}
	字符ascii码

sizeof(arr) -计算的是数组的总大小、单位是字节 sizeof(arr[0])-计算的是数组元素的大小

printf ( " month=%02d\n ", month) ; // 01

printf ( " month=%2d\n ", month) ; // 1

for循环

int i=0
for(i=0;i<10,i++)
c99编译之前不识别i=0;i<10,i++

二分查找

//有序数组二分查找
	int arr[] = {1,2,3,4,5,6,7,8,9,10};
	int k = 7;
	int sz = sizeof(arr) / sizeof(arr[0]);
	int left = 0;
	int right = sz-1;
	while (left<=right)
	{
		int mid = (left + right) / 2;//改进
		int mid = left + (right - left) / 2;
		if (arr[mid] > k) {
			right = mid - 1;
		}
		else if (arr[mid] < k) {
			left = mid + 1;
		}
		else {
			printf("找到了,下标是%d",mid);
			break;
		}
	}
	if ((left > right)) {
		printf("找不到");
	}

编写代码,演示多个字符从两端移动,向中间汇聚。

	char arr[] = "welcome to school!!!";
	char arr2[] = "$$$$$$$$$$$$$$$$$$$$";
	int left = 0;
	int right = strlen(arr) -1;
	int rightlength = sizeof(arr) / sizeof(arr[0])-2;//[还要减去 \0]
	 
	while (left<=right)
	{
		arr2[left] = arr[left];
		arr2[right] = arr[right];
		left++;
		right--;
		Sleep(500);
		system("cls");//清空屏幕 //system是个库函数,可以执行系统命令  
		printf("%s\n", arr2);
	}
	printf("%s\n", arr2);

随机数生成

生成随机数之前先进行播种

#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main() { 
		int a;
		srand((unsigned int)time(NULL));
		srand((unsigned)time(NULL));
		srand(time(NULL));
		a = rand()%10;//模100 得到0-100 的随机数,模10得到0-10 的整数
		printf("%d\n", a); 
    return 0;
} 

goto语句

again: 
	if (strcmp("2", "3") == 0) {
		printf("equal");
	}
	else {
		printf("o");
		goto again;
	}

交换ab

当实参传递给形参的时候,形参是实参的一份临时拷贝对形参的修改不会影响实参

swap(int *px,int * py) {
	int z = *px;
	*px = *py;
	*py = z;
} 
int main() {    
	int a=0;
	int b=0;
	scanf("%d %d",&a,&b);
	printf("交换前a=%d b=%d\n", a, b);
	swap(&a, &b);
	printf("交换后a=%d b=%d\n", a, b); 
	return 0;
}

传值调用 传址调用

#include <math.h>
int main() {     
	int a = sqrt(16);
	printf(" %d\n", a); 

链式访问

	printf("%d\n", printf("%d", printf("%d",43)));

4321 printf返回值是打印的个数

函数声明:

1.告诉编译器有一个函数叫什么,参数是什么,返回类型是什么。但是具体是不是存在,函数声明决定不了。 2.函数的声明一般出现在函数的使用之前。要满足先声明后使用。3.函数的声明一般要放在头文件中的。

函数定义; 函数的定义是指函数的具体实现,交待函数的功能实现。

#include "add.h" 
//导入静态库
#pragma comment(lib,"add.lib")
int add(int x, int y);

add.h

//函数的声明
int add(int x,int y)

而在Linux下,动态库是以.so为后缀,静态库则是以.a作为后缀名 在windows下,动态库的后缀是.dll,静态库的后缀是.lib

函数递归.1什么是递归?

程序调用自身的编程技巧称为递归( recursion) 。 递归做为一种算法在程序设计语言中广泛应用。一个过程或函数在其定义或说明中有直接或间接调用自身的 一种方法,它通常把一个大型复杂的问题层层转化为一个与原问题相似的规模较小的问题来求解,递归策略 只需少量的程序就可描述出解题过程所需要的多次重复计算,大大地减少了程序的代码量。递归的主要思考方式在于:把大事化小

//%d是打印有符号的整数(会有正负数)//%u是打印无符号的整数

递归调用 输入1234 输出1 2 3 4

void printdigui(unsigned int n) {
	if (n > 9) {
		printdigui(n / 10);
	}
	printf("%d ", n % 10);
};
int main() {      
	unsigned int num = 0;
	scanf("%u", &num);
	printdigui(num);
}

递归的两个必要条件 存在限制条件,当满足这个限制条件的时候,递归便不再继续。 每次递归调用之后越来越接近这个限制条件。

int mystr_len(char * str) {
	int count = 0;
	while (*str != '\0')
	{
		count++;
		str++;
	}
	return count;
};
int main() {      
	char arr[] = "abcdddd"; 
	int len = mystr_len(arr);
	printf("%d ", len);
	}

不用临时变量

int mystr_len(char * str) { 
	if (*str != '\0')
		return 1+ mystr_len(str+1);
	else
		return 0; 
};

数组 一维数组

//传入数组 arr[0]-->*(arr+0)

C99标准之前数组大小是常亮,c99之后数组的大小可以是变量 为了支持变长数组

数组名:传入后获取数组长度sz错误

计算二维数组的行列

int arr[3][4] = { 0 };
printf("%d \n", sizeof(arr) / sizeof(arr[0]));
printf("%d \n", sizeof(arr[0])/sizeof(arr[0][0]));

移位操作符

负数 原码 反码(原码的符号位不变,其他位按位取反就是反码)补码 (反码+1就是补码)

整数在计算机用补码表示

左移操作符: 2倍数(只针对整数 左边丢弃,右边补0

int a=7;
int b=a<<1;//左移
	printf("%d\n", b);

右移操作符: 算数移位

异或:相同为0;相异为1

&&左边为假,右边就不计算了

||左边为真,右边就不计算了

getchat() 读缓存

scanf(“ %c”,ch) 加空格==清缓存--清除下一个读取之前的全部空格

写一个函数返回参数二进制中1的个数。

	int num;
		scanf("enter a number: %d", &num);
		int n = count_binumber(num);
		printf("%d\n", n);
	  
	int count_binumber(int n) { 
		int count = 0;
		while (n)
		{
			if ( (n %2) == 1)
			{
				count++;
			}
			n = n / 2;
		} 
		return count;
	};

在给定的代码中,函数count_bin的目的是计算给定整数a的二进制表示中1的个数。然而,传递给函数的变量a的初始值为-1,它在进行无符号右移运算时可能会导致死循环。

在C#中,当使用右移运算符/作用于一个负数时,会将最高位的符号位进行复制,而不会补0

加个无符号unsigned就行

	int count_binumber(unsigned int n) { 
		int count = 0;
		while (n)
		{
			if ( (n %2) == 1)
			{
				count++;
			}
			n = n / 2;
		} 
		return count;
	};

或者使用二进制&的办法

	int count_binumber(int n) {
		int i = 0;
		int count = 0;
		for (size_t i = 0; i < 32; i++)
		{
			if (((n >> i) & 1) == 1)
			{
				count++;
			}
		}
		return count;
	};

or

	int count_binumber( int n) {
		int count = 0;
		while (n)
		{
			n = n & (n - 1);
				count++; 
		}
		return count;
	};

调试学习

数组死循环代码

		int i = 0;
		int arr[10] = { 1,2,3,4,5,6,7,8,9,10 };
		for ( i = 0; i <= 12; i++)
		{
			arr[i] = 0;
			printf("hehe\n");
		}	  

调试i=12时 , arr[12] = 0; 这时候发现i=0;然后i++=1;造成死循环,&取i的地址和&arr[12]的地址发现相同

1.栈区内存的使用习惯是先使用高地址处的空间,再使用低地址处的空间。2.数组随着下标的增长地址是由低到高变化的。
3.如果i和arr之间由适当的空间,利用数组的越界操作就可能会覆盖到i,就可能会导致死循环出现的。
//1.const放在*的左边
/意思是:p指向的对象不能通过p来改变了,但是p变量本身的值是可以改变的//*p = 20; //err
/ /2.const放在*的右边
//意思是:p指向的对象是可以通过p来改变的,但是不能修改p变量本身的值
int * const p=&num;
*p=0;//ok
p

scanf和gets

	char arr[100] = {0};
		scanf("%s", arr);
		printf("%s", arr);
		gets(arr);
		printf("%s", arr); 

unsigned char类型的取值范围是0~255

strlen 返回的是siez_t unsign int 始终大于0

字符串进阶

●strtok函数找到str中的下一个称记, 并将其用\0结尾,这回个个指向这个标记的指针。 (注: strtok函数会改变被操作的字符串,所以在使用strtok函数切分的字符串-一般都是临时拷贝的内容 并且可修改。) ●strtok函数的第一 个参数不为NULL, 函数将找到str中第一 个标记,strtok函数将保存它在字符串 中的位置。 ●strtok函数的第一 个参数为NULL, 函数将在同一个字符串中被保存的位置开始,查找下一个标 记。 ●如果字符串中不存在更多的标记,则返回NULL指针。

字符分类函数: 函数 如果他的参数符合下列条件就返回真 iscntrl 任何控制字符 isspace 空白字符:空格',换页\f,换行'\n',回车'\r, 制表符'"t'或者垂直制表符"\V' isdigit 十进制数字09 isxdigit 十六进制数字,包括所有十进制数字,小写字母af,大写字母AF islower 小写字母az isupper 大写字母AZ isalpha 字母az或AZ . isalnum 字母或者数字,az,AZ,09 ispunct 标点符号,任何不属于数字或者字母的图形字符(可打印) isgraph 任何图形字符

动态内存管理

本章重点 ●为什么存在动态内存分配 ●动态内存函数的介绍 0 malloc 0 free 0 calloc 0 realloc . ●常见的动态内存错误 ●几个经典的笔试题 ●柔性数组

1.为什么存在动态内存分配 我们已经掌握的内存开辟方式有: int val = 20;//在栈空间上开辟四个字节 char arr[10] = {0};//在栈空间上开辟10个字节的连续空间 但是上述的开辟空间的方式有两个特点: 1.空间开辟大小是固定的。 2.数组在申明的时候,必须指定数组的长度,它所需要的内存在编译时分配。 但是对于空间的需求,不仅仅是上述的情况。有时候我们需要的空间大小在程序运行的时候才能知道, 那数组的编译时开辟空间的方式就不能满足了。 这时候就只能试试动态存开辟了。

2.1malloctree
C语言提供了-一个动态内存开辟的函数:
void* malloc (size_ t size);
这个函数向内存申请一块连续可用的空间,并返回指向这块空间的指针。
●如果开辟成功,则返回一个指向开辟好空间的指针。
●如果开辟失败,则返回一个NULL指针,因此malloc的返回值一定要做检查。
●返回值的类型是void*,所以malloc函数并不知道开辟空间的类型,具体在使用的时候使用者自己
来决定。
●如果参数size 为0,malloc的行为是标准是未定义的,取决于编译器。

C语言提供了另外一个函数free, 专门是用来做动态内存的释放和回收的,函数原型如下:
void free (void* ptr);
free函数用来释放动态开辟的内存。
●如果参数ptr指向的空间不是动态开辟的,那free函数的行为是未定义的。
●如果参数ptr是NULL指针,则函数什么事都不做。
malloc和free都声明在std1ib.h头文件中。

2.2 calloc C语言还提供了一个函数叫calloc,cal11oc 函数也用来动态内存分配。原型如下: void* calloc (size_ t num, size_ t size); ●函数的功能是为num个大小为size的元素开辟一块空间, 并且把空间的每个字节初始化为0。 ●与函数mal1oc的区别只在于ca1loc会在返回地址之前把申请的空间的每个字节初始化为全0。 举个例子:

int p = (int)ca11oc(10, sizeof(int)); if(NULL != p)

2.3realloc realloc函数的出现让动态内存管理更加灵活。 有时会我们发现过去申请的空间太小了,有时候我们又会觉得申请的空间过大了,那为了合理的时 候内存,我们一定会对内存的大小做灵活的调整。那realloc函数就可以做到对动态开辟内存大小 的调整。 函数原型如下:void* realloc (void* ptr, size_ _t size); ●ptr 是要调整的内存地址 ●size 调整之后新大小 ●返回值为调整之后的内存起始位置。 ●这个函数调整原内存空间大小的基础上,还会将原来内存中的数据移动到新的空间。 ●realloc在调整内存空间的是存在两种情况: 。情况1:原有空间之后有足够大的空间

6.柔性数组

也许你从来没有听说过柔性数组(flexible array)这个概念,但是它确实是存在的。 C99中,结构中的最后-个元素允许是未知大小的数组,这就叫做[柔性数组J成员。 例如:

typedef struct st_ type
{
    int i;
    int a[0] ;//柔性数组成员,
}type_ a;
有些编译器会报错无法编译可以改成
typedef struct st_ _type
{
    int i;
    int a[];//柔性数组成员
}type_ _a;

6.1柔性数组的特点: ●结构中的柔性数组成员前面必须至少-个其他成员。 ●sizeof 返回的这种结构大小不包括柔性数组的内存。 ●包含柔性数组成员的结构用malloc ()函数进行内存的动态分配,并且分配的内存应该大于结构的大 小,以适应柔性数组的预期大小。 例如://柔性数组的使用

struct S* ps=(struct S*)malloc(sizeof(struct S) + 40);

ps->n = 100;
inti=0;
for(i=0;i<10;i++)
ps->arr[i] = i;
}
for(i=0;i<10;i++)
printf( "%d ", ps->arr[i]);
}
struct S* ptr = (struct S* )realloc(ps, sizeof(struct S)+80); 
if (ptr != NULL){
ps = ptr;
}
//释放
free(ps);
ps=NULL;

第一个好处是:方便内存释放 如果我们的代码是在一个给别人用的函数中, 你在里面做了二次内存分配,并把整个结构体返回给 用户。用户调用free可以释放结构体,但是用户并不知道这个结构体内的成员也需要free,所以你 不能指望用户来发现这个事。所以,如果我们把结构体的内存以及其成员要的内存一次性分配好 了,并返回给用户一个结构体指针,用户做一次free就可以把所有的内存也给释放掉。 第二个好处是:这样有利于访问速度. 连续的内存有益于提高访问速度I 也有益于减少内存碎片。(其实, 我个人觉得也没多高了,反正 你跑不了要用做偏移量的加法来寻址)

文件操作

3.2文件的打开和关团

文件在读写之前应该先打开文件,在使用结束之后应该关闭文件。 入不 " 在编写程序的时候,在打开文件的同时,都会返回一个FILE*的指针变量指向该文件,也相当于建立了指 针和文件的关系。 ANSIC规定使用fopen函数来打开文件, fclose来关闭文件。 //打开文件 FILE * fopen ( const char fi lename, const charmode ) ; //关闭文件 int fclose ( FILE * stream ); 打开方式如下:

 FILE*pf= fopen("test. txt","r");
if(pf==NULL)
//写文件
char i=0;
for (i = 'a'; i<= 'z'; i++){
fputc(i, pf);}
fputs("a, pf)
//关闭文件
fclose(pf);
pf = NULL;
fprintf(f,"%s %s %f",s.name,s.age,s.score)
fs(f,"%s %s %f",s.name,s.age,s.score)

5.文件的随机读写

5.1 fseek 根据文件指针的位置和偏移量来定位文件指针。

5.2 ftell 返回文件指针相对于起始位置的偏移量 1ong int fte11 ( FILE * stream);

5.3 rewind 让文件指针的位置回到文件的起始位置 void rewind ( FILE * stream ) ;

题目

输入一个整数求各位数之和

int sumOfDigits(int number) {
	if (number == 0) {
		return 0;
	}
	else {
		return (number % 10) + sumOfDigits(number / 10);
	}
}
int main() {      

	int number, sum;

	printf("请输入一个整数:");
	scanf("%d", &number);

	sum = sumOfDigits(number);

	printf("各位数之和为:%d\n", sum);
	}

九九乘法表

int i = 0;
	for (size_t i = 1; i <= 9; i++)
	{
		int j = 0;
		for (size_t j = 1; j <= i; j++)
		{
			printf("%d*%d=%-2d ", i, j, i * i);
		}
		printf("\n");
	}
	//-2d 左对齐

漏斗

int n = 11; //底部个数
		int i ,j;
		for ( i = n; i > 0; i-=2)
		{ 
			// 进来的时候, i =11 , 无空格 i=9的时候  一个空格
			for (j = n/2; j > i/2; j--) {
				printf(" ");
			}
			for (j = 0; j < i; j++) {
				printf("*");
			}
			printf("\n");  
		}
		//先写下面这个正常顺序输出 漏斗的下半部分
		for (i = 2; i< n; i += 2)
		{
			// 进来的时候, i =11 , 无空格 i=9的时候  一个空格
			for (j = n/2; j > i/2; j--) {
				printf(" ");
			}
			for (j = 0; j <= i; j++) {
				//if(j==i==0) 
				printf("*");
			}
			printf("\n");
		}

素数

素数又称质数。所谓素数是指除了 1 和它本身以外,不能被任何整数整除的数,例如17就是素数,因为它不能被 2~16 的任一整数整除。

思路1):因此判断一个整数m是否是素数,只需把 m 被 2 ~ m-1 之间的每一个整数去除,如果都不能被整除,那么 m 就是一个素数。
思路2):另外判断方法还可以简化。m 不必被 2 ~ m-1 之间的每一个整数去除,只需被 2 ~  之间的每一个整数去除就可以了。如果 m 不能被 2 ~  间任一整数整除,m 必定是素数。例如判别 17 是是否为素数,只需使 17 被 2~4 之间的每一个整数去除,由于都不能整除,可以判定 17 是素数。

		int T = 0, n, m, i, k = 0, sum = 0, num = 0;
		sqrt(k) == k; 
		scanf("%d", &T);
		while (T--) {
			scanf("%d %d", &n, &m);
			for (i = n; i <= m; i++) {
				if (i > 1) {
					  // 小于等于1的数不是素数
				int sqrt_n = sqrt(i);
				int k;
				for (k = 2; k <= sqrt_n; k++) { 
					if (i % k == 0)
						break;
				}
				if (k> sqrt_n ||i==2) {
					printf("%d ", i);
					sum += i;
					num += 1;
				}
				}
				/*		if (i == k) {
							printf("%d\n", i);
							sum += i;
							num += 1;
						}*/
			} 
			if (sum != 0)
				printf("\n%d\n", sum);
			sum = 0;
			if (num == 0)
				printf("NO\n");
			num = 0;
		}

C语言 ,根据输入的字母输出一个字母金字塔

#include <stdio.h>
 
int main()
{
    int j, k, l, h;
    int n;
    char c = 'A';
    printf("请输入:");
    scanf("%d", &n);
    //总行数
    for(h=1;h<=n;h++)
    {
        //随着行数的增加,空格的数也随着减少,就会产生一种三角形的感觉
        for(j=n;j>h;j--)
            printf("%c", 32);
        for(k=0;k<h;k++)
            printf("%c", k+c);
        //第一行只有A不需要倒叙输出,所以从B开始
        for(l=h-2;l>=0;l--)
            printf("%c",l+c);
        printf("\n");
    }
    return 0;
}
#include <stdio.h>
 
int main(void)
{
	int n,i,b,c,d;
	char ch='A';
	printf("请输入你要打印的行数:\n");
	scanf("%d",&n);
 
	for(i=1;i<=n;i++)
	{
		for(b=0;b<n-i;b++)
		{
			printf("%c",32);
		}
		for(c=0;c<i;c++)
		{
			printf("%c",ch++);
		}
		ch--;
		for(d=0;d<i-1;d++)
		{
			printf("%c",--ch);
		}
		printf("\n");
	}
	return 0;
}

小乐乐改数字

小乐乐喜欢数字,尤其喜欢0和1。他现在得到了一个数,想把每位的数变成0或1. 如果某一位是奇数,就把它变成1,如果是偶数,那么就把它变成0。请你回答他最 后得到的数是多少。 输入描述: 输入包含一个整数n (0≤n≤10 9) 输出描述: 输出一个整数,即小乐乐修改后得到的数字。 D 示例1 输入: 222222 输出: 0

int main( )
int input = 0;
int sum = 0;
//输入
scanf( "%d", &input);//123
inti=0;
while (input)
{
int bit = input % 10;
if(bit%2==1)
{
bit = 1;
}
else
{
bit = 0;
}
sum十=bit *pow(10, i++);
input /= 10;
 }
printf("%d\n", sum);
return 0;
}