C语言-更新中

文章目录

1、C语言控制语句

在这里插入图片描述

2、printf()格式字符

在这里插入图片描述

3、格式字符

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述
在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

4、Fibonacci数列

在这里插入图片描述

int  main(void)
{

  int f1 = 1, f2 = 1;
  for (int i = 1; i <= 20; i++)
  {
    printf("%d %d\n", f1, f2);
    f1 = f1 + f2;
    f2 = f2 + f1;

  }

  return 0;
}

二、函数

2.1 函数返回值

在这里插入图片描述

2.2 函数调用的方式

按函数在程序中出现的位置来分,可以有以下3种函数调用方式。
1. 函数语句
把函数调用作为一个语句。这时不要求函数带回值,只要求函数完成一定的操作。
2. 函数表达式
函数出现在一个表达式中,这种表达式称为函数表达式。这时要求函数带回一个确定的值以参加表达式的运算。
3. 函数参数
函数调用作为一个函数的实参。

1. 函数语句

#include <stdio.h>
int main(int argc, char *argv[])
{

  int c, a, b;
  max();

  return 0;
}

void max() { printf("ceshi"); }

2. 函数表达式

#include <stdio.h>
int main(int argc, char *argv[]) {

  int c, a, b;
  c = 2 * max(a, b);

  return 0;
}

float max(int x, int y) {

  int z;
  z = x > y ? x : y;
  return z;
}

3. 函数参数

#include <stdio.h>
int main(int argc, char *argv[]) {

  int c, a, b;
  c = max(1, max(a, b));

  return 0;
}

int max(int x, int y) {

  int z;

  z = x > y ? x : y;
  return z;
}

2.3 函数的嵌套调用

在这里插入图片描述
在这里插入图片描述

2.4 函数的递归调用

在这里插入图片描述
在这里插入图片描述

2.4.1 递归案例

有5个人坐在一起,问第5个人多少岁?他说比第4个人大2岁。问第4个人岁数,他说比第3个人大2岁。问第3个人,又说比第2个人大2岁。问第2个人,说比第1个人大2岁。最后问第1个人,他说是10岁。请问第5个人多大
在这里插入图片描述

/*
 * @Author: 贾继康
 * @Date: 2019-03-24 13:51:10
 * @Last Modified by: 贾继康
 * @Last Modified time: 2019-03-24 13:52:33
 */

#include <stdio.h>

int age(int n) {

  if (n == 1) {
    return 10;
  } else {
    return age(n - 1) + 2;
  }
}

int main(int argc, char *argv[]) {

  printf("%d\n", age(5));

  return 0;
}

2.4.2 递归案例

在这里插入图片描述

/*
 * @Author: 贾继康
 * @Date: 2019-03-24 13:51:10
 * @Last Modified by: 贾继康
 * @Last Modified time: 2019-03-24 14:00:35
 */

#include <stdio.h>

float fac(int n) {

  if(n ==0 || n == 1){
    return 1;
  }else
  {
    return n*fac(n-1);

  }
  
  
}

int main(int argc, char *argv[]) {

  printf("%f\n", fac(3));

  return 0;
}

三、局部变量和全局变量

3.1 局部变量

在这里插入图片描述

3.2 全局变量

程序的编译单位是源程序文件,一个源文件可以包含一个或若干个函数。在函数内定义的变量是局部变量,而在函数之外定义的变量称为外部变量,外部变量是全局变量。全局变量可以为本文件中其他函数所共用。它的有效范围为从定义变量的位置开始到本源文件结束。
有一个一维数组,内放10个学生成绩,写一个函数,求出平均分、最高分和最低分

 /*
 * @Author: jjk 
 * @Date: 2019-03-31 10:02:20 
 * @Last Modified by: jjk
 * @Last Modified time: 2019-03-31 10:41:10
 */

#include <stdio.h>
int MAX;
int Min;

float average(int score[], int n)
{

    int sum = 0;
    MAX = score[0];
    Min = score[0];
    for (int i = 0; i < n; i++)
    {
        sum += score[i];
        if (score[i] > MAX)
            MAX = score[i];
        if (score[i] < Min)
            Min = score[i];
    }

    return sum / n; // 平均值
}

void main(int argc, char *argv[])
{
    int score[10];
    int aver;

    for (int i = 0; i < 10; i++)
    {
        scanf("%d", &score[i]); // 扫描score
    }

    aver = average(score, 10);
    printf("aver = %d", aver);
}

四、变量的存储类别

4.1 动态存储方式和静态存储方式

在这里插入图片描述
在这里插入图片描述

在这里插入图片描述
在这里插入图片描述

4.1.1 auto变量

动态存储类别的变量

#include <stdio.h>

int f(int a)
{
    auto int b, c = 3; // 自动变量
}

void main()
{
    f(1);
}

4.1.2 static声明局部变量

在这里插入图片描述

#include <stdio.h>

int f(int a)
{
    auto int b;
    static int c = 0; // 静态变量
    b = b + 1;
    c = c + 1;
    printf("b=%d c=%d\n", b, c);
    return (a + b + c);
}

void main()
{
    int a = 2, i;
    f(1);

    for (i = 0; i < 3; i++)
    {
        printf("%d ", f(a));
    }
}

实例
输出1到5的阶乘值
如果初始化后,变量只被引用而不改变其值,则这时用静态局部变量比较方便,以免每次调用时重新赋值。但是应该看到,用静态存储要多占内存(长期占用不释放,而不能像动态存储那样一个存储单元可供多个变量使用,节约内存),而且降低了程序的可读性,当调用次数多时往往弄不清静态局部变量的当前值是什么。因此,若非必要,不要多用静态局部变量。


#include <stdio.h>

int f(int n)
{
    static int f = 1;
    f = f * n;
    return f;
}

void main()
{
    for (int i = 1; i <= 5; i++)
    {
        printf("%d!=%d\n", i, f(i));
    }
}

在这里插入图片描述

4.1.3 register变量

在这里插入图片描述

#include <stdio.h>

double fac(long n)
{
    register long i;
    register double f = 1.0;
    for (i = 1; i <= n; i++)
        f = f * i;
    return f;
}

void main()
{
    long i, n;
    scanf("%ld", &n);
    for (i = 1; i <= n; i++)
    {
        printf("%ld!=%e\n", i, fac(i));
    }
}

在这里插入图片描述

4.1.4 static 内部函数

在这里插入图片描述

#include <stdio.h>
static int power(int i)
{
    return i;
}

void main(int argc, char *argv[])
{
    printf("power = %d",power(2));

}

在这里插入图片描述

4.1.5 extern 外部函数

在这里插入图片描述
有一个字符串,内有若干个字符,今输入一个字符,要求程序将字符串中该字符删去。用外部函数实现。

在这里插入图片描述

在这里插入图片描述

4.1.6

在这里插入图片描述

#include <stdio.h>
float p(int n, float x);

void main()
{
	int n=1;
	float x=2.0;

	printf("%f\n", p(2, x));

	//(6-2-1)/2
}

float p(int n, float x)
{
	if(n==0)
		return 1;
	else if(n==1)
		return x;
	else
		return ((2*n-1)*x-p(n-1, x)-(n-1)*p(n-2, x))/n;
}

4.1.7

写一个判素数的函数,在主函数输入一个整数,输出是否素数的信息。

#include <stdio.h>

#include <math.h>

int judge(int n);

void main()
{
	int n;
	scanf("%d", &n);
	if(judge(n) == 1)
		printf("is a prime\n");
	else
		printf("is not a prime\n");
}

int judge(int n)
{
	for(int i=2; i<=(int)sqrt(n); i++)
		if(n % i == 0)
			break;
	
	if(i > (int)sqrt(n))
		return 1;
	else
		return 0;
}

4.1.8

写一个函数,使给定的一个3×3的二维整型数组转置,即行列互换。

#include <stdio.h>
void transform(int a[3][3]);
void print_array(int a[3][3]);

void main()
{
	int a[3][3]={{0,1,2},{3,4,5},{6,7,8}};

	printf("before:\n");

	print_array(a);

	transform(a);

	printf("after:\n");

	print_array(a);
}

void print_array(int a[3][3])
{
	for(int i=0; i<3; i++)
	{
		for(int j=0; j<3; j++)
			printf("%d ", a[i][j]);
		printf("\n");
	}
}

void transform(int a[3][3])
{
	for(int i=0; i<3; i++)
		for(int j=0; j<=i; j++)
		{
			//a[j][i]<->a[i][j]
			int temp;
			temp=a[j][i];
			a[j][i]=a[i][j];
			a[i][j]=temp;
		}
}

4.1.9

写一个函数,使输入的一个字符串按反序存放,在主函数中输入和输出字符串

#include  <stdio.h>

void myconnect(char str1[], char str2[]);

char str3[200];

void main()
{
	char str1[]="hello ";
	char str2[]="world!";

	//char * pStr3;

	myconnect(str1, str2);

	printf("%s\n", str3);
}

void myconnect(char str1[], char str2[])
{
	int i=0;
	int p=0;
	while(str1[i] != '\0')
		str3[p++]=str1[i++];

	i=0;
	while(str2[i] != '\0')
		str3[p++]=str2[i++];

	str3[p]='\0';
	//return str3;
}

4.1.10

写一个函数,将两个字符串连接

#include  <stdio.h>
#include "string.h"

void reverse(char c[], int n);

void main()
{
	char c[]={"hello world!"};

	printf("%s\n", c);

	reverse(c, strlen("hello world!"));

	printf("%s\n", c);
}


void reverse(char c[], int n)
{
	//hello
	char temp[200];

	int p=0;
	for(int i=n-1; i>=0; i--)
	{
		temp[p]=c[i];
		p++;
	}
	temp[p]='\0';

	for(i=0; i<n; i++)
		c[i]=temp[i];
}

4.1.11 补充(动态二维数组)

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

// 非连续矩阵
// 手动输入x,y,创建一个动态数组p[x][y]
// 从0开始初始化,一直初始化到p[x-1][y-1]这个元素,一直递增

void main8() {

	int x, y;
	scanf_s("%d%d", &x, &y);// 初始化x,y横纵坐标

	// 二级指针可以存储指针数组的地址
	// 动态分配一片内存,存放指针数组,每一个元素都是一个地址
	// 然后将指针数组的首地址传递给pp保存
	int **pp = malloc(sizeof(int*)*x); // 指向指针的指针
	for (int i = 0; i < x; i++)
	{

		// 分配内存,有多少列,一维数组
		// 每个指针都存储这样一片内存的地址
		pp[i] = malloc(sizeof(int)*y);
 
	}


	//  赋值
	int num = 0;
	for (int i = 0; i < x; i++)
	{
		for (int j = 0; j < y; j++)
		{
			pp[i][j] = num;// *(*(pp+i) +j) 等价
			// *(*(pp + i) + j) = num;
			num++;
			printf("%4d",pp[i][j]); // 打印
		}

		printf("\n");// 换行
	}

	// 释放内存
	for (int i = 0; i < x; i++)
	{
		free(pp[i]);
	}

	free(pp);

	system("pause");


}


// 手动输入x,y,创建一个动态数组p[x][y]
// 从0开始初始化,一直初始化到p[x-1][y-1]这个元素,一直递增

// 二、动态数组
void main7() {
	int x, y;
	scanf_s("%d%d",&x,&y);// 初始化x,y,8*9二维数组
	void *p = malloc(sizeof(int)*x*y); // 分配内存,连续的内存 :必须是常数指定的
	// y必须是一个已知的常量,才能将这片内存当做一个二维数组来使用

	int(*px)[9] = p; // 
	int num = 0;
	for (int i = 0; i < x; i++)
	{
		for (int j = 0; j < 9; j++)
		{
			px[i][j] = num;
			num++;
			printf("%4d",px[i][j]);
		}
		printf("\n");
	}


	system("pause");


}




//三、静态二维数组
void main6(){

	int a[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
	int(*p)[4] = a; // 创建一个指针,存储二维数组的首地址
	// 一个指向有四个元素的一维数组的指针
	//打印二维数组内容
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			printf("%5d", a  [i][j]);

		}
		printf("\n");
	}
	// 打印内容还有地址
	for (int *p = &a[0][0]; *p < &a[0][0]; p++)
	{
		printf("\n%d,%p",*p,p);

	}
	// 

	system("pause");
}

五、预处理命令

ANSI C标准规定可以在C源程序中加入一些“预处理命令”,以改进程序设计环境,提高编程效率。这些预处理命令是由ANSI C统一规定的,但是它不是C语言本身的组成部分,不能直接对它们进行编译(因为编译程序不能识别它们)。必须在对程序进行通常的编译(包括词法和语法分析、代码生成、优化等)之前,先对程序中这些特殊的命令进行“预处理”,即根据预处理命令对程序作相应的处理(例如,若程序中用#define命令定义了一个符号常量A,则在预处理时将程序中所有的A都置换为指定的字符串。若程序中用#include命令包含一个文件“stdio.h”,则在预处理时将stdio.h文件中的实际内容替代该命令)。

5.1 预处理功能

在这里插入图片描述

5.1.1 宏定义

5.1.1.1 不带参数的宏定义

在这里插入图片描述

#include <math.h>
#include <stdio.h>
#include <string.h>

#define PI 3.1415926

// 主函数
void main(int argc, char *argv[]) {
  float l, s, r, v;
  printf("input radius:");
  scanf("%f", &r);

  l = 2.0 * PI * r;
  s = PI * r * r;
  #undef PI
  v = 4.0 / 3 * PI * r * r * r;
  
  printf("l=%10.4f\ns=%10.4f\nv=%10.4f\n", l, s, v);
} 

说明
在这里插入图片描述

#include <math.h>
#include <stdio.h>
#include <string.h>

#define R 3.0
#define PI 3.1415926
#define L 2*PI*R
#define S PI*R*R

5.1.1.2 带参数的宏定义

在这里插入图片描述


#include <math.h>
#include <stdio.h>
#include <string.h>

#define PI 3.14
#define S(r) PI *r *r
//#define S(a,b) a*b

// 主函数
void main(int argc, char *argv[]) {

  //   int area;
  //   area = S(3,2);// area = 3*2
  //   printf("area = %d",area);
  float a, area;
  a = 3.6;
  area = S(a); // area = PI*a*a
  printf("r =%f\narea=%f\n", a, area);

  
}

在这里插入图片描述

说明
在这里插入图片描述

5.1.1.3 宏代表输出格式

/*
 * @Author: jjk
 * @Date: 2019-03-31 10:02:20
 * @Last Modified by: jjk
 * @Last Modified time: 2019-04-02 13:15:13
 */

#include <math.h>
#include <stdio.h>
#include <string.h>

#define PR printf
#define NL "\n"
#define D "%d"
#define D1 D NL
#define D2 D D NL
#define D3 D D D NL
#define D4 D D D D NL
#define S "%s"

// 主函数
void main(int argc, char *argv[]) {

  int a, b, c, d;
  char string[] = "CHINA"; // 字符数组初始化
  a = 1;
  b = 2;
  c = 3;
  d = 4;
  
  // 调用宏
  PR(D1, a);          // printf("%d \n", a);
  PR(D2, a, b);       // printf("%d%d \n", a, b);
  PR(D3, a, b, c);    // printf("%d%d%d\n", a, b, c);
  PR(D4, a, b, c, d); // printf("%d%d%d%d \n", a, b, c, d);
  PR(S, string);


}

在这里插入图片描述

5.1.2 文件包含

在这里插入图片描述
主文件:main.c

#include <math.h>
#include <stdio.h>
#include <string.h>
#include "format.h"



// 主函数
void main(int argc, char *argv[]) {

  int a, b, c, d;
  char string[] = "CHINA"; // 字符数组初始化
  a = 1;
  b = 2;
  c = 3;
  d = 4;

  // 调用宏
  PR(D1, a);          // printf("%d \n", a);
  PR(D2, a, b);       // printf("%d%d \n", a, b);
  PR(D3, a, b, c);    // printf("%d%d%d\n", a, b, c);
  PR(D4, a, b, c, d); // printf("%d%d%d%d \n", a, b, c, d);
  PR(S, string);


}

次文件:format.h

#define PR printf
#define NL "\n"
#define D "%d"
#define D1 D NL
#define D2 D D NL
#define D3 D D D NL
#define D4 D D D D NL
#define S "%s"

5.1.1 说明

在这里插入图片描述
file1.c


#include <stdio.h>
#include "file2.h"

int main(int argc, char const *argv[])
{
    printf("%d\n",get_a());
    return 0;
}

file2.h

#include "file3.h"
// int a = 10


int get_a(){
    a = 1;
    return a;
}

file3.h

int a = 10;

在这里插入图片描述

5.1.3 条件编译

在这里插入图片描述

5.1.3.1 条件编译形式

在这里插入图片描述

在这里插入图片描述

在这里插入图片描述

#include <stdio.h>

#define COMPUTER_A 1

#ifdef COMPUTER_A 
    #define INTENER_SIZE 16
#else
    #define INTENER_SIZE 32
#endif
 


// 主函数
void main(int argc, char *argv[]) {

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

}

在这里插入图片描述
输入一行字母字符,根据需要设置条件编译,使之能将字母全改为大写输出,或全改为小写字母输出

#include <stdio.h>

#define LETTER 1 // a -> A
//#define LETTER 0//A -> a

// 主函数
int main(int argc, char *argv[]) {
    
  char str[20] = "C Language";

  for (int i = 0; str[i] != '\0'; i++) {
#if LETTER
    if (str[i] >= 'a' && str[i] <= 'z')
      str[i] -= 32;
#else
    if (str[i] >= 'A' && str[i] <= 'Z')
      str[i] += 32;
#endif
    printf("%c", str[i]);
  }
  printf("\n");

  return 0;
}

在这里插入图片描述

5.1.3.2 条件编译形式说明案例

1、定义一个带参数的宏,使两个参数的值互换,并写出程序,输入两个数作为使用宏时的实参。输出已交换或的两个值

#include <stdio.h>
#define SWAP(A, B)                                                             \
  int T;                                                                       \
  T = A;                                                                       \
  A = B;                                                                       \
  B = T;

// 主函数
int main(int argc, char *argv[]) {

  int a = 1, b = 2;

  printf("a=%d b=%d\n", a, b);

  SWAP(a, b); // int T;T=a;a=b;b=T;

  printf("a=%d b=%d\n", a, b);

  return 0;
  
}

在这里插入图片描述

2、输入两个整数,求它们相除的余数。用带参数的宏来实现,编程序

#include <stdio.h>
#define MOD(A, B) A % B

// 主函数
int main(int argc, char *argv[]) {

  int a = 1, b = 2;
  printf("%d\n", MOD(a, b)); // a%b

  return 0;
}

在这里插入图片描述

3、三角形的面积为area=sqrt(s(s-a)(s-b)(s-c)其中s=(a+b+c)/2。a、b、c为三角形的三边。定义两个带参数的宏,一个用来求s,另一个宏用来求area。写程序,在程序中用带实参的宏名来求面积area。

#include <stdio.h>
#include <math.h>
#define S(A, B, C) (A + B + C) / 2
#define AREA(A, B, C)                                                          \
  sqrt(S(A, B, C) * (S(A, B, C) - a) * (S(A, B, C) - b) * (S(A, B, C) - c))
// 主函数
int main(int argc, char *argv[]) {

  float a, b, c;
  a = 3.0;
  b = 4.0;
  c = 5.0;

  printf("%f\n", AREA(a, b, c));
  return 0;
}

在这里插入图片描述
4、给年份year定义一个宏,以判别该年份是否闰年。提示:宏名可定为LEAP_YEAR,形参为y,即定义宏的形式为#define LEAP_YEAR(y) (读者设计的字符串)在程序中用以下语句输出结果:

	if (LEAP_YEAR(year)) printf(%d is a leap year.\n”, year); 
	else printf(%d is not a leap year.\n”, year);
#include <stdio.h>
#define LEAP_YEAR(Y) ((Y % 4 == 0 && Y % 100 != 0) || Y % 400 == 0)



int main(int argc, char *argv[]) {
  int year = 1980 + 1;
  if (LEAP_YEAR(year))
    //
    printf("%d is a leap year.\n", year);
  else
    printf("%d is not a leap year.\n", year);

  return 0;
}

在这里插入图片描述

5、请设计输出实数的格式,实数用“%6.2f”格式输出。要求:
(1)一行输出1个实数;
(2)一行内输出2个实数;
(3)一行内输出3个实数。

#include <stdio.h>
#define F "%6.2f"
#define PR printf
#define NL "\n"
#define F1 F NL
#define F2 F F NL
#define F3 F F F NL

int main(int argc, char *argv[]) {

  float a = 1.0, b = 2.0, c = 3.0;

  PR(F1, a);
  PR(F2, a, b);
  PR(F3, a, b, c);

  return 0;
}

在这里插入图片描述

6、设计所需的各种的输出格式(包括整数、实数、字符串等),用一个文件名“format.h”把这些信息都放到此文件内,另编一个程序文件,用#include “format.h”命令,以确保能使用这些格式。

主程序

#include "format.h"
#include <stdio.h>


int main(int argc, char *argv[]) {
    
  PR(D1, 1);
  PR(S, "hello");
  PR(F1, 2.0);

  return 0;
}

次程序

#define PR printf
#define NL "\n"
#define D "%d"
#define D1 D NL
#define D2 D D NL
#define D3 D D D NL
#define D4 D D D D NL
#define S "%s\n"

#define F "%6.2f"
//#define PR printf
//#define NL "\n"
#define F1 F NL
#define F2 F F NL
#define F3 F F F NL


在这里插入图片描述

7、分别用函数和带参数的宏,从3个数中找出最大数。

#include <stdio.h>

#define MAX(A, B, C) (A > B ? A : B) > C ? (A > B ? A : B) : C

int main(int argc, char *argv[]) {

  // int a=1, b=2, c=3;
  // float a=1.0, b=2.0, c=3.0;
  char a = 'a', b = 'b', c = 'c';

  printf("%c\n", MAX(a, b, c));

  return 0;
}

在这里插入图片描述

8、输入一行电报文字,可以任选两种输出:一为原文输出;一为将字母变成其下一字母,其他非字母字符不变。用#define命令来控制是否要译成密码。例如:

#define CHANGE 1
则输出密码。若
#define CHANGE 0
则不译成密码,按源码输出。

#include <stdio.h>
#define CHANGE 1

int main(int argc, char *argv[]) {

  char str[] = {"abcde"};

  for (int i = 0; str[i] != '\0'; i++) {
#if CHANGE
    if (str[i] >= 'a' && str[i] <= 'z' || str[i] >= 'A' && str[i] <= 'Z') {
      if (str[i] == 'z' || str[i] == 'Z')
        str[i] -= 25;
      else
        str[i]++;
    }
#endif
    printf("%c", str[i]);
  }
  printf("\n");

  return 0;
}

在这里插入图片描述

六、结构体和共用体

      基本类型(或称简单类型)的变量(如整型、实型、字符型变量等),也介绍了一种构造类型数据–数组,数组中的各元素是属于同一个类型的。但是只有这些数据类型是不够的。有时需要将不同类型的数据组合成一个有机的整体,以便于引用。
      这些组合在一个整体中的数据是相互联系的。应当把它们组织成一个组合项,在一个组合项中包含若干个类型不同的数据项(当然也可以相同)。C语言允许用户自己指定这样一种数据结构,它称为结构体。它相当于其他高级语言中的“记录”。

例如:
在这里插入图片描述

6.1 声明结构体

在这里插入图片描述

struct student
{
   int num;
   char name[20]; // 字符数组
   char sex: //性别
   int age;
   float score;
   char addr[30];

};



#include <stdio.h>
#include <string.h>

// 定义一个结构体
struct student {
  int num;
  char name[20];
  char sex;
  int age;
  float score;
  char addr[30];
};


int main(int argc, char *argv[]) {
  struct student s; // 结构体变量定义
  s.num = 10010;    // 访问结构体变量中的成员
  // s.name[0] = 'a';
  // s.name[1] = 'b';
  // s.name[2] = 'c';
  // s.name[3] = '\0';
  strcpy(s.name, "hello world"); // 第二种赋值方式
  s.sex = 'm';
  s.age = 18;
  s.score = 99.5;
  strcpy(s.addr, "gansu");

  printf("num=%d name=%s sec=%c age=%d score=%f addr=%s\n", s.num, s.name,
         s.sex, s.age, s.score, s.addr);

  return 0;
}

在这里插入图片描述

6.2 定义结构体类型变量的方法

	前面只是指定了一个结构体类型,它相当于一个模型,但其中并无具体数据,系统对之也不分配实际内存单元。
	为了能在程序中使用结构体类型的数据,应当定义结构体类型的变量,并在其中存放具体的数据。可以采取以下三种方法定义结构体类型变量。
	1、先声明结构体类型再定义变量名
	2、在声明类型的同时定义变量
	3、直接定义结构体类型变量
在这里插入代码片

6.2.1 第一种

/*
 * @Author: 贾继康
 * @Date: 2019-03-24 16:46:01
 * @Last Modified by:   贾继康
 * @Last Modified time: 2019-03-24 16:46:01
 */

#include <stdio.h>
#include <string.h>

// 结构体声明
struct student {
  int num;
  char name[20];
  char sex;
  int age;
  float score;
  char addr[30];
};

int main(int argc, char *argv[]) {

  struct student s; // 结构体定义变量

  return 0;
}

6.2.2 第二种

/*
 * @Author: 贾继康
 * @Date: 2019-03-24 16:46:01
 * @Last Modified by: 贾继康
 * @Last Modified time: 2019-03-24 16:49:39
 */

#include <stdio.h>
#include <string.h>

// 结构体声明
struct student {
  int num;
  char name[20];
  char sex;
  int age;
  float score;
  char addr[30];
} s1, s2; // 同时定义结构体变量

int main(int argc, char *argv[]) {

  s1.num = 10010;
  strcpy(s1.name, "hello world!");
  s1.sex = 'm';
  s1.age = 18;
  s1.score = 87.5;
  strcpy(s1.addr, "Beijing");

  printf("num=%d name=%s sec=%c age=%d score=%f addr=%s\n", s1.num, s1.name,
         s1.sex, s1.age, s1.score, s1.addr);

  return 0;
}

在这里插入图片描述

6.2.3 第三种

/*
 * @Author: 贾继康
 * @Date: 2019-03-24 16:46:01
 * @Last Modified by: 贾继康
 * @Last Modified time: 2019-03-24 16:51:38
 */

#include <stdio.h>
#include <string.h>

// 结构体声明
struct {
  int num;
  char name[20];
  char sex;
  int age;
  float score;
  char addr[30];
} s1, s2; // 同时定义结构体变量

int main(int argc, char *argv[]) {

  s1.num = 10010;
  strcpy(s1.name, "hello world!");
  s1.sex = 'm';
  s1.age = 18;
  s1.score = 87.5;
  strcpy(s1.addr, "Beijing");

  printf("num=%d name=%s sec=%c age=%d score=%f addr=%s\n", s1.num, s1.name,
         s1.sex, s1.age, s1.score, s1.addr);

  return 0;
}

在这里插入图片描述

6.2.4 说明

(1)类型与变量是不同的概念,不要混同。只能对变量赋值、存取或运算,而不能对一个类型赋值、存取或运算。在编译时,对类型是不分配空间的,只对变量分配空间。
(2)对结构体中的成员(即“域”),可以单独使用,它的作用与地位相当于普通变量。
(3)成员也可以是一个结构体变量。
(4)成员名可以与程序中的变量名相同,二者不代表同一对象。
/*
 * @Author: 贾继康
 * @Date: 2019-03-24 16:46:01
 * @Last Modified by: 贾继康
 * @Last Modified time: 2019-03-24 17:06:11
 */

#include <stdio.h>
#include <string.h>

// 结构体声明
struct date {

  int month int day;
  int year;
};

// 结构体声明
struct {
  int num;
  char name[20];
  char sex;
  int age;
  float score;
  struct date birthday; // 声明结构体变量(结构体中套用结构体(3))
  char addr[30];
} s1, s2; // 同时定义结构体变量

int main(int argc, char *argv[]) {
  int num; // 和结构体成员中的num是两回事(4)

  s1.num = 10010;
  strcpy(s1.name, "hello world!");
  s1.sex = 'm';
  s1.age = 18;
  s1.score = 87.5;
  strcpy(s1.addr, "Beijing");

  // 结构体当中、结构体变量当中的结构体成员
  s1.birthday.month = 2;
  s1.birthday.day = 3;
  s1.birthday.year = 1998;


  // printf("num=%d name=%s sec=%c age=%d score=%f addr=%s\n", s1.num, s1.name,
  //        s1.sex, s1.age, s1.score, s1.addr);
  // printf("%d\n",sizeof(s1));
  // printf("%d\n",sizeof(s1.num));

  return 0;
}

6.3 结构体变量的引用

在定义了结构体变量以后,当然可以引用这个变量。但应遵守以下规则:

(1)不能将一个结构体变量作为一个整体进行输入和输出。
(2)如果成员本身又属一个结构体类型,则要用若干个成员运算符,一级一级地找到最低的一级的成员。只能对最低级的成员进行赋值或存取以及运算。
(3)对结构体变量的成员可以像普通变量一样进行各种运算(根据其类型决定可以进行的运算)。
(4)可以引用结构体变量成员的地址,也可以引用结构体变量的地址。

/*
 * @Author: 贾继康
 * @Date: 2019-03-24 16:46:01
 * @Last Modified by: 贾继康
 * @Last Modified time: 2019-03-24 17:43:29
 */

#include <stdio.h>
#include <string.h>

// 结构体声明
struct date {

  int month;
  int day;
  int year;
};

// 结构体声明
struct {
  int num;
  char name[20];
  char sex;
  int age;
  float score;
  struct date birthday; // 声明结构体变量(结构体中套用结构体(3))
  char addr[30];
} s1, s2; // 同时定义结构体变量



int main(int argc, char *argv[]) {
   

  s1.num = 10010;
  strcpy(s1.name, "hello world!");
  s1.sex = 'm';
  s1.age = 18;
  s1.score = 87.5;
  strcpy(s1.addr, "Beijing");

  // 结构体当中、结构体变量当中的结构体成员
  s1.birthday.month = 2;
  s1.birthday.month += 2;

  s1.birthday.day = 3;
  s1.birthday.year = 1998;


  // printf("num=%d name=%s sec=%c age=%d score=%f addr=%s\n", s1.num, s1.name,
  //        s1.sex, s1.age, s1.score, s1.addr);
  // printf("%d\n",sizeof(s1));
  // printf("%d\n",sizeof(s1.num));

  printf("%x\n",&s1);
  printf("%x\n",s1.addr);  
  printf("%x\n",&s1.age);   
  return 0;
}

6.4 结构体变量的初始化

和其他类型变量一样,对结构体变量可以在定义时指定初始值。
例如: 对结构体变量初始化

/*
 * @Author: 贾继康
 * @Date: 2019-03-24 16:46:01
 * @Last Modified by: 贾继康
 * @Last Modified time: 2019-03-24 17:49:44
 */

#include <stdio.h>
#include <string.h>

struct student {
  long int num;
  char name[20];
  char sex;
  char addr[20];
} a = {89031, "Li Lin", 'M', "123 Beijing Road"};

int main(int argc, char *argv[]) {

  printf("num:%ld\nname:%s\nsex:%c\naddr:%s\n", a.num, a.name, a.sex, a.addr);

  return 0;
}

6.5 结构体数组

一个结构体变量中可以存放一组数据(如一个学生的学号、姓名、成绩等数据)。如果有10个学生的数据需要参加运算,显然应该用数组,这就是结构体数组。结构体数组与以前介绍过的数值型数组不同之处在于每个数组元素都是一个结构体类型的数据,它们都分别包括各个成员(分量)项。

/*
 * @Author: 贾继康
 * @Date: 2019-03-24 16:46:01
 * @Last Modified by: 贾继康
 * @Last Modified time: 2019-03-24 17:54:53
 */

#include <stdio.h>
#include <string.h>

struct student {
  long int num;
  char name[20];
  char sex;
  float score;
  char addr[20];
} stu[3];


int main(int argc, char *argv[]) {

  // struct student stu[3]; // 声明结构体变量数组
  return 0;
}

6.5.1 结构体数组的初始化

在这里插入图片描述

/*
 * @Author: 贾继康
 * @Date: 2019-03-24 16:46:01
 * @Last Modified by: 贾继康
 * @Last Modified time: 2019-03-24 18:01:30
 */

#include <stdio.h>
#include <string.h>

struct student {
  
  long int num;
  char name[20];
  char sex;
  float score;
  char addr[20];
} stu[3] = {{10101, "jjk01", 'm', 18, 98.4, "gansu"},
            {10101, "jjk02", 'm', 18, 98.4, "gansu"},
            {10101, "jjk03", 'm', 18, 98.4, "gansu"}};

int main(int argc, char *argv[]) {

  // struct student stu[3]; // 声明结构体变量数组
  
  return 0;
}

6.5.2 结构体数组案例

对候选人得票的统计程序。设有3个候选人,每次输入一个得票的候选人的名字,要求最后输出各人得票结果

/*
 * @Author: 贾继康
 * @Date: 2019-03-24 16:46:01
 * @Last Modified by: 贾继康
 * @Last Modified time: 2019-03-24 18:09:13
 */

#include <stdio.h>
#include <string.h>

struct person {
  /* data */
  char name[20];
  int count;
};

int main(int argc, char *argv[]) {

  struct person leader[3] = {
      {"jia01", 0},
      {"jia02", 0},
      {"jia03", 0}}; // 声明结构体变量数组,每一个元素是一个结构体


  char name[20];
  
  for (int i = 0; i < 10; i++) {
    
    scanf("%s", name);
    for (int j = 0; j < 3; j++) {
      if (strcmp(name, leader[j].name) == 0) {
        leader[j].count++;
      }
    }

    for (i = 0; i < 3; i++) {
      printf("name=%s\n", leader[i].name);
      printf("count=%d\n", leader[i].count);
    }
  }
  return 0;
}

在这里插入图片描述

6.6 指向结构体类型数据的指针

6.6.1 使用指针打印结构体成员

一个结构体变量的指针就是该变量所占据的内存段的起始地址。可以设一个指针变量,用来指向一个结构体变量此时该指针变量的值是结构体变量的起始地址。指针变量也可以用来指向结构体数组的元素。

为了使用方便和使之直观,可以把(*p).num改用p->num来代替,它表示p所指向的结构变量中的num成员。也就是说,以下三种形式等价:
(1)结构体变量.成员名
(2)(*p).成员名
(3)p->成员名
其中->称为指向运算符。

/*
 * @Author: 贾继康
 * @Date: 2019-03-24 16:46:01
 * @Last Modified by: 贾继康
 * @Last Modified time: 2019-03-24 18:28:00
 */

#include <stdio.h>
#include <string.h>

struct student // 结构布局:student
{
  long num;
  char name[20];
  char sex;
  float score;
};

int main(int argc, char *argv[])
{

  struct student stu_1; // 声明结构体变量名
  struct student *p;    // 指向结构体类型的指针
  p = &stu_1;           // 首地址赋值给指针变量p

  // 结构体变量成员赋值
  stu_1.num = 3123;
  strcpy(stu_1.name, "jiajikang");
  stu_1.sex = 'M';
  stu_1.score = 98.5;

  printf("No.:%ld\nname:%s\nsex:%c\nscore:%f\n", stu_1.num, stu_1.name,
         stu_1.sex, stu_1.score);

  printf("***********************\n*");
  printf("No.:%ld\nname:%s\nsex:%c\nscore:%f\n", (*p).num, (*p).name, (*p).sex,
         (*p).score); //*p==stu_1

  printf("***********************\n*");
  printf("No.:%ld\nname:%s\nsex:%c\nscore:%f\n", p->num, p->name, p->sex,
         p->score); //*p==stu_1

  return 0;
}

在这里插入图片描述

6.6.2 结构体数组及其元素使用指针或指针变量

/*
 * @Author: 贾继康
 * @Date: 2019-03-24 16:46:01
 * @Last Modified by: 贾继康
 * @Last Modified time: 2019-03-24 18:37:58
 */

#include <stdio.h>
#include <string.h>

struct student // 结构布局:student
{
  int num;
  char name[20];
  char sex;
  int age;
};

// 初始化结构体变量
struct student stu[3] = {{10101, "Li Lin", 'M', 18},
                         {10102, "Zhang Fun", 'M', 19},
                         {10104, "Wang Min", 'F', 20}};

int main(int argc, char *argv[]) {

  // struct student stu_1; // 声明结构体变量名
  struct student *p; // 指向结构体类型的指针
  // p = &stu_1;           // 首地址赋值给指针变量p

  for (p = stu; p < stu + 3; p++) { // p = stu:指向数组的首地址,stu + 3:数组的长度
    printf("num:%d name:%s sex:%c age:%d\n", p->num, p->name, p->sex, p->age);
  }

  return 0;
}

在这里插入图片描述

6.6.3 结构体变量和指向结构体的指针作函数参数

将一个结构体变量的值传递给另一个函数,有3个方法:
(1)用结构体变量的成员作参数。用法和用普通变量作实参是一样的,属于“值传递”方式。
(2)用结构体变量作实参(不提倡奥)。用结构体变量作实参时,采取的也是“值传递”的方式,将结构体变量所占的内存单元的内容全部顺序传递给形参,形参也必须是同类型的结构体变量。在函数调用期间形参也要占用内存单元。这种传递方式在空间和时间上开销较大,如果结构体的规模很大时,开销是很可观的。
(3)用指向结构体变量(或数组)的指针作实参,将结构体变量(数组)的地址传给形参。

6.6.3.1 案例

有一个结构体变量stu,内含学生学号、姓名和3门课的成绩。要求在main函数中赋以值,在另一函数print中将它们打印输出

/*
 * @Author: 贾继康
 * @Date: 2019-03-24 16:46:01
 * @Last Modified by: 贾继康
 * @Last Modified time: 2019-03-24 19:12:26
 */

#include <stdio.h>
#include <string.h>



struct student // 结构布局:student
{
  int num; // 学号
  char name[20];
  float score[3];
};



void print(struct student s) { // 参数类型student ,形参名称:s

  printf("num:%-6d name:%20s\n", s.num, s.name, s.score);
  for(int i=0;i<3;i++){
    printf("score[%d]=%f ",i,s.score[i]);
  }
  printf("\n");
}


// 主函数
int main(int argc, char *argv[]) {

  struct student stu; // 声明结构体变量名
  // struct student *p; // 指向结构体类型的指针
  // p = &stu;           // 首地址赋值给指针变量p
  stu.num = 12345;
  strcpy(stu.name, "jiajikang");
  stu.score[0] = 67.5;
  stu.score[1] = 89;
  stu.score[2] = 78.6f;

  // void print(struct student); // 声明
  print(stu);

  return 0;
}

在这里插入图片描述

6.6.3.2 案例

将上题改用指向结构体变量的指针作实参

/*
 * @Author: 贾继康
 * @Date: 2019-03-24 16:46:01
 * @Last Modified by: 贾继康
 * @Last Modified time: 2019-03-24 19:15:16
 */

#include <stdio.h>
#include <string.h>



struct student // 结构布局:student
{
  int num; // 学号
  char name[20];
  float score[3];
};



void print(struct student *p) { // 参数类型student ,形参名称:s

  printf("num:%-6d name:%20s\n", p->num, p->name, p->score);
  for(int i=0;i<3;i++){
    printf("score[%d]=%f ",i,p->score[i]);
  }
  printf("\n");
}


// 主函数
int main(int argc, char *argv[]) {

  struct student stu; // 声明结构体变量名
  // struct student *p; // 指向结构体类型的指针
  // p = &stu;           // 首地址赋值给指针变量p
  stu.num = 12345;
  strcpy(stu.name, "jiajikang");
  stu.score[0] = 67.5;
  stu.score[1] = 89;
  stu.score[2] = 78.6f;

  // void print(struct student); // 声明
  print(&stu);

  return 0;
}

在这里插入图片描述

6.7 共用体

6.7.1 共用体的概念

在这里插入图片描述

#include <stdio.h>
#include <malloc.h>

// 定义共用体类型
union data {
  int i;
  char ch;
  float f;
};

int main(int argc, char *argv[]) // *argv[]:指针数组
{

  union data a, b, c; // 声明共用体变量
  a.i = 1;
  a.f = 2.0;
  a.ch = 'j';

  printf("a.ch=%c\n", a.ch);
  printf("a.f = %f\n", a.f);
  printf("a.i=%d\n", a.i);
  printf("sizeof(union data) = %d\n",sizeof(union data));

  return 0;
}

在这里插入图片描述

6.7.2 共用体变量的引用方式

在这里插入图片描述

#include <stdio.h>
#include <malloc.h>

// 定义共用体类型
union data {
  int i;
  char ch;
  float f;
};

int main(int argc, char *argv[]) // *argv[]:指针数组
{

  union data a, b, c; // 声明共用体变量  ,不用引用共用体变量a,b,c
  a.i = 1;
  a.f = 2.0;
  a.ch = 'j';

  printf("a.ch=%c\n", a.ch);
  printf("a.f = %f\n", a.f);
  printf("a.i=%d\n", a.i);
  printf("sizeof(union data) = %d\n",sizeof(union data));

  return 0;
}

6.7.3 共用体类型数据的特点

(1)同一个内存段可以用来存放几种不同类型的成员,但在每一瞬时只能存放其中一种,而不是同时存放几种。也就是说,每一瞬时只有一个成员起作用,其他成员不起作用,即不是同时都存在和起作用。
(2)共用体变量中起作用的成员是最后一次存放的成员,在存入一个新的成员后原有的成员就失去作用。
(3)共用体变量的地址和它的各成员的地址都是同一地址。

(4)不能对共用体变量名赋值,也不能企图引用变量名来得到一个值,又不能在定义共用体变量时对它初始化。
(5)不能把共用体变量作为函数参数,也不能使函数带回共用体变量,但可以使用指向共用体变量的指针。
(6)共用体类型可以出现在结构体类型定义中,也可以定义共用体数组。反之,结构体也可以出现在共用体类型定义中,数组也可以作为共用体的成员。

6.7.3.1 案例说明

设有若干个人员的数据,其中有学生和教师。学生的数据中包括:姓名、学号、性别、职业、班级。教师的数据包括:姓名、号码、性别、职业、职务。可以看出,学生和教师所包含的数据是不同的。现要求把它们放在同一表格中

在这里插入图片描述

#include <stdio.h>
#include <malloc.h>

// 定义结构体类型

struct record
{
  int num;
  char name[10];
  char sex;
  char job; //if job = s student;job = t teacher
  union     // 声明共用体
  {
    int banji;
    char position[10]; // 职位

  } category; // union变量,包含两个成员

} person[2];

// 主函数
int main(int argc, char *argv[]) // *argv[]:指针数组
{

  for (int i = 0; i < 2; i++)
  {
    scanf("%d %s %c %c", &person[i].num, &person[i].name, &person[i].sex, &person[i].job);
    if (person[i].job == 's')
    {
      scanf("%d", &person[i].category.banji);
    }
    else
    {
      scanf("%s", person[i].category.position);
    }
  }



  for (int i = 0; i < 2; i++)
  {
    if (person[i].job == 's')
    {
      printf("%d %s %c %c %d\n", person[i].num, person[i].name, person[i].sex, person[i].job, person[i].category.banji);
    }
    else
    {
      printf("%d %s %c %c %s\n", person[i].num, person[i].name, person[i].sex, person[i].job, person[i].category.position);
    }
  }
  

  return 0;
}

在这里插入图片描述

6.7.4 枚举类型

在这里插入图片描述

#include <stdio.h>
#include <malloc.h>


enum weekday{sum, mon, tue, wed, thu,fri,sat}; // 定义一个枚举类型



// 主函数
int main(int argc, char *argv[]) // *argv[]:指针数组
{

  enum weekday day; // 声明枚举类型变量
  day = sum; 
  day = mon;
   
  return 0;
}

6.7.4 说明

(1)在C编译中,对枚举元素按常量处理,故称枚举常量。它们不是变量,不能对它们赋值。
(2)枚举元素作为常量,它们是有值的,C语言编译按定义时的顺序使它们的值为0,1,2,…。
(3)枚举值可以用来做判断比较。
(4)一个整数不能直接赋给一个枚举变量。

6.7.4.1 案例

口袋中有红、黄、蓝、白、黑5种颜色的球各一个。每次从口袋中先后取出3个球,问得到3种不同色的球的可能取法,输出每种排列的情况

#include <malloc.h>
#include <stdio.h>


enum color { red, yellow, blue, white, black }; // 定义一个枚举类型

// 主函数
int main(int argc, char *argv[]) // *argv[]:指针数组
{

  enum color i, j, k;
  int n = 0;

  for (i = red; i <= black; i++) { // 遍历枚举常量
    for (j = red; j <= black; j++) {
      for (k = red; k <= black; k++) {
        if (i != j && i != k && j != k) {

          
          n++;
          switch (i) {
          case red:
            printf("first: red\n   ");
          case yellow:
            printf("first: yellow\n");
          case blue:
            printf("first: blue\n  ");
          case white:
            printf("first: white\n ");
          case black:
            printf("first: black\n ");
          }

          switch (j) {
          case red:
            printf(" second: red\n   ");
          case yellow:
            printf(" second: yellow\n");
          case blue:
            printf(" second: blue\n  ");
          case white:
            printf(" second: white\n ");
          case black:
            printf(" second: black\n ");
          }

          switch (k) {
          case red:
            printf(" third: red\n   ");
          case yellow:
            printf(" third: yellow\n");
          case blue:
            printf(" third: blue\n  ");
          case white:
            printf(" third: white\n ");
          case black:
            printf(" third: black\n ");
          }
        }
      }
    }
  }

  return 0;
}

6.7.5 用typedef定义类型

在这里插入图片描述

#include <malloc.h>
#include <stdio.h>

typedef int INTEGER; // typedef声明新的类型名
typedef float REAL;
typedef int ARR[10];
typedef char *STRING; //字符指针类型
typedef int (*POINTER)(int,float); // 指向函数类型的指针


typedef struct date // 结构体类型:date
{

  int month;
  int day;
  int year;

} DATE;
 
// 主函数
int main(int argc, char *argv[]) // *argv[]:指针数组
{

  INTEGER i, j;  // int i,j;
  REAL a, b;     // float a,b;
  DATE birthday; // DATE代表就是结构体类型,无需再加struct:struct date birthday
  ARR arr;       // int arr[10];
  STRING p1, p2; // char *p1,*p2

  POINTER p3,p4; 

  for (i = 0; i < 9; i++)
  {

    arr[i] = i;
    printf("%d ", arr[i]);
  }

  return 0;
}

6.7.5.1 说明

(1)用typedef可以声明各种类型名,但不能用来定义变量。用typedef可以声明数组类型、字符串类型,使用比较方便。
(2)用typedef只是对已经存在的类型增加一个类型名,而没有创造新的类型。
(3)typedef与#define有相似之处。
(4)当不同源文件中用到同一类型数据时,常用typedef声明一些数据类型,把它们单独放在一个文件中,然后再需要用到它们的文件中用#include命令把它们包含进来。
(5)使用typedef用利于程序的通用与移植。

6.7.6 案例

1、 编写一个函数print,打印一个学生的成绩数组,该数组中有5个学生的数据记录,每个记录包括num、name、score[3],用主函数输入这些记录,用print函数输出这些记录。

#include <malloc.h>
#include <stdio.h>

typedef struct student
{
  int num;
  char name[20];
  float score[3];
} STUDENT;




void input(struct student *p, int n)
{

  for (int i = 0; i < n; i++)
  {
    printf("input element i:\n", i);
    scanf("%d %s %f %f %f", &p[i].num, p[i].name, &p[i].score[0], &p[i].score[1], &p[i].score[2]);
  }

}

void print(struct student *p, int n)
{

  printf("num        name      score[0]     score[1]     score[2]\n");
  for (int i = 0; i < n; i++)
    printf("%5d %20s %10.2f %10.2f %10.2f\n", (p + i)->num, (p + i)->name, (p + i)->score[0], (p + i)->score[1], (p + i)->score[2]);

}


// 主函数
int main(int argc, char *argv[]) // *argv[]:指针数组
{

  STUDENT s[2];
  for(int i = 0; i < 2; i++)
  {
    printf("input s[%d]:\n",i);
    scanf("%d %s %f %f %f", &s[i].num, &s[i].name, &s[i].score[0], &s[i].score[1], &s[i].score[2]);

  }
  print(s, 2);

  return 0;
}

在这里插入图片描述

2、 在上题的基础上,编写一个函数input,用来输入5个学生的数据记录。

#include <malloc.h>
#include <stdio.h>

typedef struct student
{
  int num;
  char name[20];
  float score[3];
} STUDENT;

void input(struct student *p, int n)
{

  for (int i = 0; i < n; i++)
  {
    printf("input element i:\n", i);
    scanf("%d %s %f %f %f", &p[i].num, p[i].name, &p[i].score[0], &p[i].score[1], &p[i].score[2]);
  }
}

void print(struct student *p, int n)
{

  printf("num        name      score[0]     score[1]     score[2]\n");
  for (int i = 0; i < n; i++)
    printf("%5d %20s %10.2f %10.2f %10.2f\n", (p + i)->num, (p + i)->name, (p + i)->score[0], (p + i)->score[1], (p + i)->score[2]);
}

// 主函数
int main(int argc, char *argv[]) // *argv[]:指针数组
{

  STUDENT s[2];
  input(s, 2);
  print(s, 2);

  return 0;
}

在这里插入图片描述

3、 编写一个函数new,对n个字符开辟连续的存储空间,此函数应返回一个指针(地址),指向字符串开始的空间。new(n)表示分配n个字节的内存空间。

#include <malloc.h>
#include <stdio.h>

char *mynew(int n)
{
  char *p; // 字符指针
  p = (char *)malloc(n);
  return p; // 返回指针地址
}

void myfree(char *p)
{
  free(p);
}

// 主函数
int main(int argc, char *argv[]) // *argv[]:指针数组
{

  char *head = mynew(20);
  for (int i = 0; i < 20; i++)
  {
    // head[i] = 'a' + i;
    *(head + i) = 'a' + i;
    printf("%c ", head[i]);
  }

  myfree(head);

  return 0;
}

在这里插入图片描述

3、 写一函数free,将上题用new函数占的空间释放。Free§表示将p(地址)指向的单元以后的内存段释放。

代码同上所示!!!

4、已有a、b两个链表,每个链表中的结点包括学号、成绩。要求把两个链表合并,按学号升序排列。

#include <malloc.h>
#include <stdio.h>

// 创建结构体
struct student
{
  long num;
  float score;
  struct student *next; // 链接下一个节点的指针
};

int n = 0;
struct student *create(void)
{
  struct student *head;
  struct student *p;
  struct student *tail;

  head = NULL;

  p = (struct student *)malloc(sizeof(struct student));
  scanf("%ld %f", &p->num, &p->score);

  while (p->num != 0)
  {
    if (head == NULL)
      head = p;
    else
      tail->next = p;

    tail = p;

    n++;

    p = (struct student *)malloc(sizeof(struct student));
    scanf("%ld %f", &p->num, &p->score);
  }

  tail->next = NULL;

  return head;
}


void print(struct student * head)
{
	struct student * p=head;
	while(p != NULL)
	{
		printf("node[num=%ld,score=%f]\n", p->num, p->score);
		p=p->next;
	} 
}



struct student *del(struct student *head, long num)
{
  struct student *p1, *p2;

  if (head == NULL)
  {
    return head;
  }
  else
  {
    p1 = head;
    p2 = NULL;
    while (p1 != NULL && p1->num != num)
    {
      p2 = p1;
      p1 = p1->next;
    }
    if (p1 != NULL)
    //if(p1->num == num)
    {
      if (p1 == head)
        head = p1->next;
      else
        p2->next = p1->next;

      free(p1);
    }
  }

  return head;
}

struct student *insert(struct student *head, long num, float score)
{
  struct student *p = (struct student *)malloc(sizeof(struct student));

  p->num = num;
  p->score = score;

  if (head == NULL)
  {
    head = p;
    p->next = NULL;
  }
  else
  {
    p->next = head;
    head = p;
  }
  return head;
}

// 主函数
int main(int argc, char *argv[]) // *argv[]:指针数组
{

  struct student *a_head; // 头指针
  struct student *b_head;
  // 链表a
  printf("create link a:\n");
  a_head = create();
  print(a_head);

  // 链表b
  printf("create link b:\n");
  b_head = create();
  print(b_head);

  // 链表c
  struct student *c_head;
  c_head = NULL; // 初始化

  struct student *p_a; // 创建指针
  struct student *p_b;

  p_a = a_head;
  p_b = b_head;

  while (p_a != NULL && p_b != NULL)
  {
    if (p_a->num < p_b->num)
    {
      c_head = insert(c_head, p_b->num, p_b->score);
      p_b = p_b->next;
    }
    else
    {
      c_head = insert(c_head, p_a->num, p_a->score);
      p_a = p_a->next;
    }
  }

  if (p_a == NULL)
  {
    while (p_b != NULL)
    {
      c_head = insert(c_head, p_b->num, p_b->score);
      p_b = p_b->next;
    }
  }
  else
  {
    while (p_a != NULL)
    {
      c_head = insert(c_head, p_a->num, p_a->score);
      p_a = p_a->next;
    }
  }

  printf("print link c:\n");
  print(c_head);

  return 0;
}

在这里插入图片描述

七、指针

1、指向元素指针和指向数组的指针

	int a[5] = {1,2,3,4,5};
	int *p = a;// 指向元素的指针
	int(*pa)[5] = &a;// 指向数组的指针
	printf("\n%d,%d",sizeof(*p),sizeof(*pa));

2、指针引用多维数组

int a[3][4] = {1,2,3,4,5,6,7,8,9,10,11,12};
	printf("%d,%d,%d",a,&a,*a);
	// a是一行指针,指向一个有四个元素的数组,16
	// &a是一个指向二维数组的指针,二维数组有12个元素,48
	// *a是一个指向int类型数据的指针,4
	printf("%p,%p,%p", a, a+1, a+2);// 代表某一行的首地址
	printf("%p,%p,%p", *a, *(a + 1), *(a + 2));// 代表某一行第一列的首地址
	printf("%p,%p,%p", a[0], a[1], a[2]);// 代表某一行第一列的首地址 
	// *a = *(a+0) = a[0]


	// 指针指向的值与地址完全一样
	printf("\n%d,%p",*(a[1]+2),a[1]+2);
	printf("\n%d,%p", *(*(a + 1)+2), *(a + 1)+2);
	printf("\n%d,%p", a[1][2],&a[1][2]);

	// a[i][j] = *(a[i]+j) = *(*a(a+i)+j)
	// &a[i][j] = *(a+i) + j

	  
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			printf("%d,%p",a[i][j],&a[i][j]);

		}

	}

	printf("\n%p,%p,%p",a,a+1,a+2);// a是一个行指针,指向的数据是一行有四个int类型的数组
	printf("\n%p,%p,%p", *a, *a + 1, *a + 2);// *a是一个指向第一行第一列的指针
	printf("\n%p,%p,%p", *(a + 1), *(a + 1) + 1, *(a + 2) + 2);// *(a+1)指向第二行第一个元素的指针
	// a[i][j] = *(*(a+i)+j) &a[i][j] = *(a+i) +j

3、指针遍历二维数组

int a[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
	// 线性方式循环二维数组
	for (int *p = &a[0][0]; p < &a[0][0]+12; p++)
	{
		printf("%d,%p\n",*p,p);

	}
	// 二维数组循环
	for (int i = 0; i < 3; i++)
	{
		for (int j = 0; j < 4; j++)
		{
			printf(" %d,%p", a[i][j], &a[i][j]); 
			printf("%d,%p",*(*(a + i) + j),*(a+i)+j); // *(a+i)+j:代表地址// 指针输出

		}
		printf("\n");

	}

4、 输出任意二维数组元素

	// 指针方式输出二维数组任意元素
	int a[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
	printf("%d",sizeof(*a));// a是一个行指针,16个字节,每一行有四个元素
	int(*p)[4] = a;// 二维数组的指针就是一个指向一维数组的指针,元素是确定的

	int i = 0;
	int j = 9;
	scanf_s("%d%d",&i,&j);
	// 输出p[i][j] 与*(*(p+i)+j)等价
	printf("%d,%d,%d,%d",i,j,p[i][j],*(*(p+i)+j));

5、指针作为数组名参数


	// 指针作为数组名参数
	
	// 一维数组
	// int a[10]数组作为函数参数,传递的是地址,地址就是指针占四个字节
	// 函数的参数对于数组没有副本机制,为了节约内存,拷贝数组浪费空间与CPU
	void test(int a[10]) {
	
		printf("\ntest=%d",sizeof(a)); // 实际上传递的是地址

	}

	void showa10(int *p) { // int a[10] ,int *p=a;指针变量作为一维数组的参数
		a = a + 1;// 形参可以被赋值改变,往下移动 

		for (int i = 0; i < 10; i++)
		{
			printf("%d\n",p[i]);

		}
	
	}
	void main() {

		int a[10]= { 1,2,3,4,5,6,7,8,9,10};
		printf("\ntest=%d", sizeof(a));

		showa10(a); // 打印数组内容

	}



	// 二维数组
	void showb12(int (*p)[4])  // int b[3][4] int (*p)[4] = b; 二维数组参数
	{ 
		p = p + 1;// 数组往下移动一行,p可再次被赋值

		for (int i = 0; i < 3; i++)
		{
			for (int j = 0; j < 4; j++)
			{
				printf("%6d",p[i][j]);

			}
			printf("\n");

		}

	}
	void main() {

		int b[3][4] = { 1,2,3,4,5,6,7,8,9,10,11,12 };
		printf("\ntest=%d", sizeof(a));

		showa12(b); // 打印数组内容

	}

案例:数组反向输出
在这里插入图片描述

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

void change(int a[], int n) { // 数组,我也副本机制,等价于直接操作

	for (int i = 0; i < n/2; i++) // 数据的循环对调
	{
		int temp = a[i]; //数据的交换
		a[i] = a[n - 1 - i];
		a[n - 1 - i] = temp;

	}


}
void main()
{

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

	}

	printf("\n\n");
	change(a,10);
	for (int i = 0; i < 10; i++)
	{
		printf("%d\n", a[i]);

	}

	system("pause");
	 
}

6、函数返回指针

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


int *mindata(int a[],int n) {

	int *p = NULL; // 保存最小数的地址
	int min = a[0];
	p = &a[0];
	for (int i = 0; i < n; i++) // 选择法
	{
		if (min>a[i])
		{
			min = a[i];// min始终最小
			p = &a[i];// p指向最小数的地址

		}
	}

	printf("最小值:%d",min);
	return p;

}


void main()
{

	int a[10];
	time_t ts;
	srand((unsigned int)time(&ts)); // 按照时间设定随机数种子
	
	for (int i = 0; i < 10; i++)
	{
		a[i] = rand() % 100;// 限定随机数的范围
		printf("%d\n",a[i]);

	}

	int *p = mindata(a, 10);// 获取最小数的地址
	// 修改最小数
	*p = 45;
	// 查看修改以后的数组
	printf("\n\n");
	for (int i = 0; i < 10; i++)
	{
		a[i] = rand() % 100;// 限定随机数的范围
		printf("%d\n", a[i]);

	}

	system("pause");

 
}

7、清零

void main()
{
	char str[30] = "china is gread";//字符串
	int num[5] = {1,2,3,4,5};
	memset(str,'A',5); // 从str的首地址开始,前进五个字符,进行赋值
	// 赋值一个字符‘A’
	printf("%s",str);
	memset(num,0,20); // 对20个字节全部复制为0,对于数组清零
	
	for (int i = 0; i < 5; i++)
	{
		printf("\n%d",num[i ]);

	}
	 
}

8、malloc,realloc,calloc

#include <stdlib.h>
#include <stdio.h>
#include <Windows.h>
/*

  1、 malloc  以字节为单位申请内存
  2、 calloc  根据有多少个元素,元素有多大来申请内存
  3、 realloc 分配内存不够用了,需要再次分配

*/

void main1() {

	
	int num;//
	scanf_s("%d",&num);
	//double *p = (double *)malloc(sizeof(double)*num);
	double *p = (double *)calloc(num, sizeof(double)); // 第一个参数是个数,第二个参数是大小

	for (double i = 1.0; i < num; i++ )
	{
		p[(int)i] = i;// 对于指针指向的内存,用下标方式访问
		printf("\n%f,%x",p[(int)i],&p[(int)i]);
	}

	free(p);
	system("pause");
}

void main() {


	int num;//
	scanf_s("%d", &num);
	int *p = (int *)malloc(sizeof(int)*num);

	printf("%x", p);// 打印地址
	for (int i = 0; i < num; i++)
	{
		p[i] = i;
		printf("%d,%x", p[i], &p[i]);
	}


	int newnum;// 数组的大小
	scanf_s("%d", &newnum); // 根据键盘初始化num的值
	int *newp = realloc(p, newnum); // 分配内存不够用了,需要再次分配
	for (int i = num; i < newnum; i++)
	{
		p[i] = i;
		printf("%d,%x", newp[i], &newp[i]);
	}
	 
	system("pause");


}

动态内存分配

#include <stdlib.h>
#include <stdio.h>
#include <Windows.h>
/*

  1、 malloc  以字节为单位申请内存
  2、 calloc  根据有多少个元素,元素有多大来申请内存
  3、 realloc 分配内存不够用了,需要再次分配

*/

void main() {

	
	int num;//
	scanf_s("%d",&num);
	int *p = (int *)malloc(sizeof(int)*num);
	// double *p = (double *)calloc(num, sizeof(double)); // 第一个参数是个数,第二个参数是大小

	if (p ==NULL)
	{
		printf("动态内存分配失败");

	}
	else 
	{
		printf("内存分配成功");
		for (int i = 0; i < num; i++)
		{
			p[i] = i; // 按照数组的方式访问内存
			printf("%d\n ",p[i]); // 打印数据
		}

		free(p);

	}	
	system("pause");
}

9、补充

9.1 利用指针对二维数组进行输入和输出

void main()
{
    // int a[3][5], i, j;
    // printf("please input:\n");
    // for (i = 0; i < 3; i++) /*控制二维数组的行数*/
    // {
    //     for (j = 0; j < 5; j++) /*控制二维数组的列数*/
    //     {
    //         scanf("%d", a[i] + j); /*给二维数组元素赋初值:第i行第j列*/
    //     }
    // }
    // printf("the array is:\n");
    // for (i = 0; i < 3; i++)
    // {
    //     for (j = 0; j < 5; j++)
    //     {
    //         printf("%5d", *(a[i] + j)); /*输出数组中元素*/
    //     }
    //     printf("\n");
    // }

    // 改写
    int a[3][5], i, j,*p;
    p = a[0];
    printf("please input:\n");
    for (i = 0; i < 3; i++) /*控制二维数组的行数*/
    {
        for (j = 0; j < 5; j++) /*控制二维数组的列数*/
        {
            scanf("%d",  p++); /*给二维数组元素赋初值:第i行第j列*/
        }
    }
    p = a[0];// 调整指针位置
    printf("the array is:\n");
    for (i = 0; i < 3; i++)
    {
        for (j = 0; j < 5; j++)
        {
            printf("%5d", *p++); /*输出数组中元素*/
        }
        printf("\n");
    }

}

9.2 将一个3行5列的二维数组的第3行元素输出

#include<stdio.h>
main()
{
	int a[3][5],i,j,(*p)[5];
	p=&a[0];
	printf("please input:\n");
	for(i=0;i<3;i++)								/*控制二维数组的行数*/
		for(j=0;j<5;j++)							/*控制二维数组的列数*/
			scanf("%d",(*(p+i))+j);					/*为二维数组中的元素赋值*/
		p=&a[2]; 								/*p为第一个元素的地址*/
		printf("the third line is:\n");
			for(j=0;j<5;j++)
				printf("%5d",*((*p)+j));				/*输出二维数组中的元素*/
			printf("\n");
}

在这里插入图片描述

9.3 将一个3行5列的二维数组的第3行元素输出

void main()
{
    int a[3][5], i, j;
    printf("please input:\n");
    for (i = 0; i < 3; i++)                                       /*控制二维数组的行数*/
        for (j = 0; j < 5; j++)                                   /*控制二维数组的列数*/
            scanf("%d", *(a + i) + j); /*为二维数组中的元素赋值*/ /*p为第一个元素的地址*/
    printf("the second line is:\n");
    for (j = 0; j < 5; j++)
        printf("%5d", *(*(a + 1) + j)); /*输出二维数组中的元素*/
    printf("\n");
}

注:*((a+n)+m):第n行第m列;*(a[n]+m):第n行第m列

9.4 字符串数组

#include<stdio.h>
void main()
{
	int i;
	char *month[]=
	{
               "January", 
               "February", 
               "March", 
               "April", 
               "May", 
               "June", 
               "July", 
               "August", 
               "September", 
               "October", 
               "November", 
               "December" 
	};													/*给指针数组中的元素赋初值*/
	for(i=0;i<12;i++)
		printf("%s\n",month[i]); 								/*输出指针数组中的各元素*/
}

9.5 指向指针的指针

int i 20;
int *p1,*p2;
p1 = &i;
p2 = &p1;

整型变量i的地址是&i,将其传递给指针变量p1,则p1指向i;将p1的地址&p1传递给p2,
则p2指向p1.p2就是指向指针变量的指针变量,即指针的指针。
 int **p; // 其含义为定义一个指针变量p,它指向另一个指针变量,该指针变量又指向一个基本整型变量。由于指针运算符*是自右至左结合。所以:int **p = int *(*p)

使用指向指针的指针输出12个月

#include<stdio.h>
void main()
{
	int i;
	char **p; // char *(*p);
	char *month[]=
	{
               "January", 
               "February", 
               "March", 
               "April", 
               "May", 
               "June", 
               "July", 
               "August", 
               "September", 
               "October", 
               "November", 
               "December" 
	};													/*给指针数组中的元素赋初值*/
	for(i=0;i<12;i++)
		printf("%s\n",*p); 								/*输出指针数组中的各元素*/
}

利用指向指针的指针输出一维数组中是偶数的元素,并统计元素的个数

#include<stdio.h>
int a[10], *p1, **p2, i, n = 0; /*定义数组、指针、变量等为基本整型*/
    printf("please input:\n");
    for (i = 0; i < 10; i++)
        scanf("%d", &a[i]); /*给数组a中各元素赋值*/
    p1 = &a[0];             // p1 =a;/*将数组a的首地址赋给p1*/
    p2 = &p1;               /*将指针p1的地址赋给p2*/
    printf("the array is:");
    for (i = 0; i < 10; i++)
    {
        /* code */
        if (*(*p2+i)%2 ==0)
        {
            /* code */
            printf("%5d", *(*p2 + i)); 
/*输出数组中的元素:指针变量p2指向的是指针变量p1所存放的内容,即数组a的首地址,要想获取数组a中的元素,就必须在*p2前面再加一个指针运算符“*”*/
            n++;
        }
        
    }
    printf("\n");
    printf("the number is:%d\n", n);

在这里插入图片描述

9.6 指针变量做函数参数

1:调用自定义函数交换两个变量的值

void swap(int *a, int *b)
{
    int tmp;
    tmp = *a;
    *a = *b;
    *b = tmp;
}
void main()
{
    int x, y;
    int *p_x, *p_y;
    printf("请输入两个数:\n");
    scanf("%d", &x);
    scanf("%d", &y);
    p_x = &x;
    p_y = &y;
    swap(p_x, p_y);
    printf("x=%d\n", x);
    printf("y=%d\n", y);
}

在这里插入图片描述
或者

void swap(int a, int b)
{
    int tmp;
    tmp = a;
    a = b;
    b = tmp;
}
void main()
{
    int x, y;
    
    printf("请输入两个数:\n");
    scanf("%d", &x);
    scanf("%d", &y);
    swap(x, y);
    printf("x=%d\n", x);
    printf("y=%d\n", y);
}

2:嵌套的函数顶用

#include<stdio.h>
void swap(int *p1, int *p2) 								/*自定义交换函数*/
{
    int temp;
    temp =  *p1;
    *p1 =  *p2;
    *p2 = temp;
}
void exchange(int *pt1, int *pt2, int *pt3) 						/*三个数由大到小排序*/
{
    if (*pt1 <  *pt2)
        swap(pt1, pt2); 								/*调用swap函数*/
    if (*pt1 <  *pt3)
        swap(pt1, pt3);
    if (*pt2 <  *pt3)
        swap(pt2, pt3);
}
void main()
{
    int a, b, c,  *q1,  *q2,  *q3;
    puts("Please input three key numbers you want to rank:");
    scanf("%d,%d,%d", &a, &b, &c);
    q1 = &a; 								/*将变量a地址赋给指针变量q1*/
    q2 = &b;
    q3 = &c;
    exchange(q1, q2, q3); 					/*调用exchange函数*/
    printf("\n%d,%d,%d\n", a, b, c);
}

在这里插入图片描述
3:任意输入10个数据,先将这10个数据中奇数输出,再求10个数据中所有奇数之和

void SUM(int *p, int n) /*自定义函数odd查找数组中的奇数*/
{
    int i, sum = 0;
    printf("the odd:\n");
    for (i = 0; i < n; i++)
        if (*(p + i) % 2 != 0) /*判断数组中的元素是否为奇数*/
        {
            printf("%5d", *(p + i));
            sum = sum + *(p + i);
        }
    printf("\n");
    printf("sum:%d\n", sum);
}
void main()
{
    int *pointer, a[10], i;
    pointer = a; /*指针指向数组首地址*/
    printf("please input:\n");
    for (i = 0; i < 10; i++)
        scanf("%d", &a[i]);
    SUM(pointer, 10); /*调用odd函数*/
}

在这里插入图片描述
4:使用指针实现冒泡排序

#include <stdio.h>
void order(int *p, int n)
{
    int i, t, j;
    for (i = 0; i < n - 1; i++)
        for (j = 0; j < n - 1 - i; j++)
            if (*(p + j) > *(p + j + 1)) /*判断相邻两个元素的大小*/
            {
                t = *(p + j);
                *(p + j) = *(p + j + 1);
                *(p + j + 1) = t; /*借助中间变量t进行值互换*/
            }
            
    printf("排序后的数组:");
    for (i = 0; i < n; i++)
    {
        if (i % 5 == 0) /*以每行5个元素的形式输出*/
            printf("\n");
        printf("%5d", *(p + i)); /*输出数组中排序后的元素*/
    }
    printf("\n");
}

void main()
{
    int a[20], i, n;
    printf("请输入数组元素的个数:\n");
    scanf("%d", &n); /*输入数组元素的个数*/
    printf("请输入各个元素:\n");
    for (i = 0; i < n; i++)
        scanf("%d", a + i); /*给数组元素赋初值*/
    order(a, n);            /*调用order函数*/
}

在这里插入图片描述
如何使用指针的指针指向函数参数
5:对英文的12个月份按字母顺序排序

#include <stdio.h>
#include <string.h>
void sort(char *strings[], int n) /*自定义排序函数*/
{
    char *temp;
    int i, j;
    for (i = 0; i < n; i++)
    {
        for (j = i + 1; j < n; j++)
        {
            if (strcmp(strings[i], strings[j]) > 0) /*比较两个字符串的大小*/
            {
                temp = strings[i];
                strings[i] = strings[j];
                strings[j] = temp; /*如果前面字符串比后面的大,则互换*/
            }
        }
    }
}

void main()
{
    int n = 12;
    int i;
    char **p; /*定义字符型指向指针的指针*/
    char *month[] =
        {
            "January",
            "February",
            "March",
            "April",
            "May",
            "June",
            "July",
            "August",
            "September",
            "October",
            "November",
            "December"

        };
    p = month;
    sort(p, n); /*调用排序函数*/
    printf("排序后的12月份如下:\n");
    for (i = 0; i < n; i++)
        printf("%s\n", month[i]); /*输出排序后的字符串*/
}

在这里插入图片描述
6:二维数组使用指针变量作函数参数-求数组每行中最大的数,并将这些书相加求和

#include <stdio.h>
#define N 4
void max(int (*a)[N], int m) /*自定义man函数,求二维数组中每行最大元素*/
{
    int value, i, j, sum = 0;
    for (i = 0; i < m; i++)
    {
        value = *(*(a + i)); /*将每行中的首个元素赋给value*/
        for (j = 0; j < N; j++)
            if (*(*(a + i) + j) > value) /*判断其他元素是否小于value的值*/
                value = *(*(a + i) + j); /*把比value大的数重新赋给value*/
        printf("第%d行:最大数是:%d\n", i, value);
        sum = sum + value;
    }
    printf("\n");
    printf("每行中最大数相加之和是:%d\n", sum);
}
void main()
{
    int a[3][N], i, j;
    int(*p)[N];
    p = &a[0];
    printf("please input:\n");
    for (i = 0; i < 3; i++)
        for (j = 0; j < N; j++)
            scanf("%d", &a[i][j]); /*给数组中的元素赋值*/
    max(p, 3);                     /*调用min函数,指针变量作函数参数*/
}

在这里插入图片描述
7:返回指针值的函数

八、字符串

发布了213 篇原创文章 · 获赞 303 · 访问量 49万+

猜你喜欢

转载自blog.csdn.net/Jiajikang_jjk/article/details/88755060
今日推荐