【数据结构】C语言必备知识学习

1.  结构体类型

结构体是一种用户自定义类型,一般由基本数据类型复合而成,如学生的定义可以包括:学号、性别、英语成绩和数学成绩。下例定义并输出小明同学的性别和数学成绩。

#include<stdio.h>

 

int main() {

struct student

{

         int stdID;

         char gender;

         int English;

         int Math;

};

struct student Xiaoming;   // 声明结构体变量Xiaoming

Xiaoming.stdID=20190102; // 对结构体中的学号赋值

Xiaoming.gender='M';     // 对结构体中的性别赋值

Xiaoming.English=90;     // 对结构体中的英语成绩赋值

Xiaoming.Math=85;      // 对结构体中的数学成绩赋值

 

printf("Xiaoming\n");

printf("Gender:%c",Xiaoming.gender);  // 输出结构体中的性别

printf("\nMath:%d",Xiaoming.Math);   // 输出结构体中的数学成绩

return 0;

}

 

2.  typedef定义新的类型

请看如下语句:

typedef int ElemType;

其中,标识符 ElemType 是一个用户自定义标识符,其实来自 Element  Type,表示数据元素类型的含义。

typedef 则来自两个词 type definition,表示类型定义,是系统关键字。

int是系统关键字,表示整数类型。

 

typedef int ElemType;表示在程序中将用标识符ElemType替换int,可以用来声明变量。

如 ElemType a; 表示 a 就是一个整型变量。

 

类似的,typedef 可以将结构体类型替换。如下面语句将 sturct sqList 这个结构体替换为 SqList。注意 S 大小写是不同的。

typedef struct sqList {

    ElemType* elem;

    int length;

    int listsize;

} SqList;

 

因此可以用 SqList 声明结构体变量,如:

SqList s2;

它与下面声明语句是等价的:

struct sqList  s1;

 

也可以声明指针类型,如下例中的LinkList:

Typedef struct  LNode {

 ElemType      data;  // 数据域

 struct LNode   *next;  // 指针域

 } LNode, *LinkList; 

LinkList是指向结构体struct  LNode的指针类型,通过它可以声明指针变量:

LinkList p;   //本语句声明一个变量 p,它是一个指针变量。

 

 

3. 有关函数参数传递的说明与举例

函数参数传递方式:传值、传址和引用。 C语言只有前两种,C++提出引用的概念,因此有3种参数传递方式。本课程算法实现主要采用了传值和引用传递。下面以计算平方值的函数为例,说明3种参数传递方式。

 

函数的参数传递(一):传值

在主函数中,将变量a中存储的值赋值到函数fun的参数x中,a和x是不同变量,对应两个不同的存储空间。

#include<stdio.h>

float fun(float  x) { return x*x; }

int main() {

float a=2.5;

float b=fun(a);

printf("result=%f",b);

return 0;

}

 

函数的地址传递(二):传址

主函数中,将a的地址传到函数fun的参数p中,运行时函数对p的访问时就是对a的地址的访问,换言之p里面保存的就是a的地址。

#include<stdio.h>

float fun(float* p) { return *p**p; } // *p表示指针p所表示地址中存储的内容

int main() {

float a=2.5;

float b=fun(&a);

printf("result=%f",b);

return 0;

}

函数的引用传递(三):引用

引用是C++中的概念。主函数中,将a以引用形式传给函数fun的参数x, x和a共享a表示的存储空间,对x的操作就是对a的操作。与传址相比,引用没有指针操作,更简单明了。

例1:将数据传递到函数内

#include<stdio.h>

float fun(float& x) { return x*x; } // &表示参数x是引用传递,不是对x取地址

int main() {

float a=2.5;

// x与a共享a的存储空间

//在fun函数中对x的使用就是对a的使用

float b=fun(a);

printf("b=%f",b);

return 0;

}

 

例2:将函数处理结果传递到函数外

#include<stdio.h>

void fun(float& result, float x) { result=x*x; } // &表示参数x是引用传递

int main() {

float a=2.5;

float b;

// result与b共享相同的存储空间

//在fun函数中对result的修改就是对b的修改

fun(b,a);

printf("result=%f",b);

return 0;

}

 

4. 动态内存分配malloc

malloc函数的全称是memory allocation,即动态内存分配,用于申请一块连续的指定大小的内存区域。 malloc函数的参数是需要分配的字节数,该函数以void*类型返回分配的内存区域地址,使用时根据需要进行类型转换。

原型为:void* malloc (size_t size);

【参数说明】

size 为需要分配的内存空间的大小,以字节(Byte)计。

【函数说明】

malloc() 在堆区分配一块指定大小的内存空间,用来存放数据。这块内存空间在函数执行完成后不会被初始化,它们的值是未知的。

【返回值】

分配成功返回指向该内存的地址,失败则返回 NULL。

操作:

由于申请内存空间时可能有也可能没有,所以需要自行判断是否申请成功,再进行后续操作。

 

注意:函数的返回值类型是 void *,void 并不是说没有返回值或者返回空指针,而是返回的指针类型未知。所以在使用 malloc() 时通常需要进行强制类型转换,将 void 指针转换成所希望的类型。

 

下面程序通过malloc申请10个整数类型数据的存储空间,对数据存储后输出。

#include<stdio.h>

#include<stdlib.h>

 

int main()

{

  int *data;  //存储空间首地址(基址,第一个数据所在内存空间的地址)

  int i;

// sizeof用于计算一个int类型数据所占字节

// 下面语句分配10个整数所占的内存空间,并将第一个数据的地址保存在data变量中

  data = ( int * ) malloc( 10 * sizeof ( int ) );

  for (i=0;i<10;i++)

    data[i]=2*i;

  for (i=0;i<10;i++)

    printf("%d\t",data[i]);

  return 0;

}

输出10个整数:0  2  4  8,… …,16  18

 

5. 关于for循环的分析

算法的时间复杂度一般主要取决于最内层语句的执行频度。关于for循环,请看例子。

y=0;       // 执行1次

for(i=1; i<=n; i++)       // 执行n+1次

   for(j=1; j<=n; j++)   // 执行n(n+1) 次

      y++;  // 执行n^2次

 

外层循环正常执行n次后,i 继续自增后大于n,不再满足循环条件,因此外层for语句执行n+1次。内层for循环,在外层的 n 次循环中都会被执行,但是每次循环与外层for循环类似,也要执行n+1次,因此内层for循环执行n(n+1)次。而语句y++的执行次数是n的平方(n^2)。