一、結構體的定義和使用

char* 不算基本數據類型

結構體(struct)是什麼

結構體:把不同類型的數據組合成一個整體。

struct Person {
    char name[20];
    int age;
    float height;
};
  • struct Person類型名
  • 裏面的 name / age / height 是成員

結構體本身不佔內存,只是定義了一種類型。

方式一

#define _CRT_SECURE_NO_WARNINGS  // windows 加上這個 抑制警告!否則不能運行
#include <stdio.h>
#include <string.h>

// 方式一
struct Worker{ // 定義一個結構體,相當於java的class
	char name[10];
	int age;
	double salary;
};

// 結構體的定義和使用
int main() {
	// struct Worker w1; 不初始化的時候,裏面的值是隨機的垃圾值
	struct Worker w1 = { "xaye", 18, 5000.5 }; // 定義並初始化結構體變量

	// 賦值
	w1.age = 28;
	strcpy(w1.name, "zhangsan");

	// 方式一 賦值 // name=zhangsan, age=28, salary=5000.50
	printf("name=%s, age=%d, salary=%.2f\n", w1.name, w1.age, w1.salary);
	return 0;
}

方式二

#define _CRT_SECURE_NO_WARNINGS  // windows 加上這個 抑制警告!否則不能運行
#include <stdio.h>
#include <string.h>

// 方式二 , 這種方式會有一個默認初始值
struct Worker { // 定義一個結構體,相當於java的class
	char name[10]; // 默認 ""
	int age;
	double salary; // 默認 0.00
} jack;

// 結構體的定義和使用
int main() {
	// 賦值
	jack.age = 28;
	strcpy(jack.name, "zhangsan");

	// 方式二 賦值 // name=zhangsan, age=28, salary=0.00
	printf("name=%s, age=%d, salary=%.2f\n", jack.name, jack.age, jack.salary);
	return 0;
}

方式三

#define _CRT_SECURE_NO_WARNINGS  // windows 加上這個 抑制警告!否則不能運行
#include <stdio.h>
#include <string.h>

struct Work{
	char name[10];
	char grade[10];
};

// 方式三,結構體嵌套
struct Worker{ // 定義一個結構體,相當於java的class
	char name[10];
	int age;
	double salary;

	Work work;
};


int main() {
	struct Worker w1 = { "xaye", 18, 5000.5, {"engineer", "A"} }; // 定義並初始化結構體變量

	// name=xaye, age=18, salary=5000.50, work_name=engineer, work_grade=A
	printf("name=%s, age=%d, salary=%.2f, work_name=%s, work_grade=%s\n",
		w1.name, w1.age, w1.salary, w1.work.name, w1.work.grade);
	return 0;
}

方式四

#define _CRT_SECURE_NO_WARNINGS  // windows 加上這個 抑制警告!否則不能運行
#include <stdio.h>
#include <string.h>


// 方式三,結構體嵌套
struct Worker{ // 定義一個結構體,相當於java的class
	char name[10];
	int age;
	double salary;

	struct Work {
		char name[10];
		char grade[10];
	};

	Work work;
};

int main() {
	struct Worker w1 = { "xaye", 18, 5000.5, {"engineer", "A"} }; // 定義並初始化結構體變量

	// name=xaye, age=18, salary=5000.50, work_name=engineer, work_grade=A
	printf("name=%s, age=%d, salary=%.2f, work_name=%s, work_grade=%s\n",
		w1.name, w1.age, w1.salary, w1.work.name, w1.work.grade);
	return 0;
}

二、結構體指針和動態內存開闢

為什麼要用結構體指針?
  • 結構體可能很大
  • 函數傳參時避免拷貝
  • 動態內存分配只能返回指針

情況

用法

結構體變量

p.age

結構體指針

pp->age

結構體 + 動態內存開闢
Person *p = (Person *)malloc(sizeof(Person));
  • malloc 返回的是 void *
  • sizeof(Person),不是 sizeof(Person *)

示例:

#define _CRT_SECURE_NO_WARNINGS  // windows 加上這個 抑制警告!否則不能運行
#include <stdio.h>
#include <string.h>
#include <cstdlib>

struct Worker{ // 定義一個結構體,相當於java的class
	char name[10];
	int age;
	double salary;
};
 
// 結構體指針和動態內存開闢
// 示例一
//int main() {
//	struct Worker worker = { "xaye", 18, 5000.5 }; // 定義並初始化結構體變量
//
//	struct Worker* pWorker = &worker; // 定義結構體指針,並指向worker變量
//
//	// 通過指針訪問結構體成員
//	pWorker->age = 28; // 修改年齡
//	pWorker->salary = 6000.0; // 修改薪水
//	pWorker->name[0] = 'X'; // 修改名字的首字母
//
//	// name=Xaye, age=28, salary=6000.00
//	printf("name=%s, age=%d, salary=%.2f\n", pWorker->name, pWorker->age, pWorker->salary);
//  free(pWorker);
//}

// 示例二
int main() {
	struct Worker* pWorker;
	//pWorker->age = 30; // 未初始化指針,訪問會出錯

	pWorker = (struct Worker*)malloc(sizeof(struct Worker)); // 動態分配內存
	pWorker->age = 27;

	// age=27
	printf("age=%d\n", pWorker->age);
  
  free(pWorker);
	return 0;
}

三、結構體數組

數組裏每個元素都是一個結構體

定義
typedef struct {
    char name[20];
    int age;
} Person;

定義結構體數組

Person arr[3];

內存佈局是連續的

arr[0] | arr[1] | arr[2]

每一格都是一個 Person

使用

訪問成員

arr[0].age = 18;
strcpy(arr[1].name, "Tom");
結構體數組和指針的關係

數組名本質是指針

Person arr[3];
Person *p = arr;   // 等價於 &arr[0]

所以:

p[1].age = 30;     // 合法
(*(p + 1)).age = 30; // 等價

因此:

arr[i].age == (arr + i)->age

注意:arr[i]->age 等價於 (arr[i])->agearr[i]是一個結構體變量本身,不是指針,所以不能用 -> ,arr + i   類型是 Person *,所以它可以用 ->,這是一個比較迷的地方。