嵌入式C語言基礎(四)

為什么要用結構體?
在實際問題中,一組數據往往具有不同的數據類型。例如,在學生登記表中,姓名應為字符型;學號可為整型或字符型;年齡應為整型;性別應為字符型;成績可為整型或實型。顯然不能用一個數組來存放這一組數據。因為數組中各元素的類型和長度都必須一致,以便于編譯系統處理。為了解決這個問題,C語言中給出了另一種構造數據類型——“結構(structure)”或叫“結構體”。 它相當于其它高級語言中的記錄。“結構”是一種構造類型,它是由若干“成員”組成的。每一個成員可以是一個基本數據類型或者又是一個構造類型。結構既是一種“構造”而成的數據類型,那么在說明和使用之前必須先定義它,也就是構造它。如同在說明和調用函數之前要先定義函數一樣。讓編程序的人自定義一個數據類型。

結構體的定義:

struct Datas  //結構體的定義用關鍵字struct,模板的作用
{int a;char c;float f;char*p;int array[2];
};

結構體的使用一:

#include <stdio.h>
#include <stdlib.h>
struct Student  //結構體的定義用關鍵字struct,模板的作用,相當于自定義的類型
{int score; //特征:分數char name[128];//特征;名字,這個是定義了可以存儲128個字節大小的數組,空格占一個字節void (*pintroduce)(char* pname);//這里是函數指針
};
int main()
{//結構體的使用://類型         變量名   初始值struct Student stu1 ={98,"feng nan nan"};//如何訪問結構體:printf("結構體中的score=%d\n",stu1.score);printf("結構體中的name=%s\n",stu1.name);struct Student stu2;stu2.score=99;/*stu2.name="馮楠楠"  在給結構體中的字符串賦值時,C++、java可以這樣寫C語言必須用字符串拷貝函數strcpy進行賦值*/char* str="馮楠楠";strcpy(stu2.name,str);printf("結構體中的score=%d\n",stu2.score);printf("結構體中的name=%s\n",stu2.name);system("pause");return 0;
}

結構體使用二:

#include <stdio.h>
#include <stdlib.h>void func(int data)
{printf("函數:data=%d\n",data);
}
struct Datas
{char*p1;//這里p1是指針int a;char c;float f;double d;char str[128];void (*p)(int a);
};
int main()
{/*char *str="hello";這樣寫可以char str[];str="hello!";這樣寫就不行了要寫為strcpy(str,"hello!");還可以這樣寫:char *str=NULl;//定義指針時不往指針里寫東西就不用=NULL//如果要是寫還要malloc并且memsetstr="hello!";//可以直接賦值,但最好都加*/char* str1=NULL;//定義一個指針沒有malloc不能往里面寫東西str1=(char*)malloc(128);memset(str1,'\0',128);strcpy(str1,"hello!");char str[]="你很帥!";struct Datas d1;d1.a=100;d1.c='d';d1.f=3.14;d1.d=123.2323;strcpy(d1.str,str);d1.p=func;d1.p1=(char*)malloc(128);//p1在結構體中沒有開辟空間是個野指針,不能指直接寫入,需要開辟空間memset(d1.p1,'\0',128);strcpy(d1.p1,"注意指針這是否開辟空間");printf("結構體輸出:%d\n",d1.a);printf("結構體輸出:%c\n",d1.c);printf("結構體輸出:%f\n",d1.f);printf("結構體輸出:%lf\n",d1.d);puts(d1.str);puts(d1.p1);d1.p(10);//結構體函數調用system("pause");return 0;
}

結構體數組:

#include <stdio.h>
#include <stdlib.h>struct Student
{int score;char *name;//這里盡量用指針,減小結構體的大小//結構體太大,傳參數占空間
};
int main()
{int i;struct Student stu[3];struct Student maxStudent;//找最高分最低分找的是人,也就是詳細的信息,用結構體struct Student minStudent;    for(i=0;i<sizeof(stu)/sizeof(stu[0]);i++){printf("請輸入第%d個學生的名字:\n",i+1);stu[i].name=(char*)malloc(128);scanf("%s",stu[i].name);//注意結構體內的指針使用前要開辟空間printf("請輸入第%d個學生的分數:\n",i+1);scanf("%d",&stu[i].score);        }for(i=0;i<sizeof(stu)/sizeof(stu[0]);i++){printf("%s:%d\n",stu[i].name,stu[i].score);}//maxStudent.score=stu[0].score;//minStudent.score=stu[0].score;minStudent=maxStudent=stu[0];//相同類型的結構體可以對等for(i=0;i<sizeof(stu)/sizeof(stu[0]);i++){if(maxStudent.score<stu[i].score)maxStudent=stu[i];if(minStudent.score>stu[i].score)minStudent=stu[i];}printf("最高分是:%s:%d\n最低分是:%s:%d\n",maxStudent.name,maxStudent.score,minStudent.name,minStudent.score);system("pause");return 0;
}

結構體指針:

#include <stdio.h>
#include <stdlib.h>
//1、如果用結構體指針,就不能用點運算符訪問結構體中的變量應該用->
//2、注意結構體指針是否是野指針或者NULL,若是則會出現段錯誤
struct Student
{int score;char name[128];
};
int main()
{struct Student stu1;stu1.score=100;strcpy(stu1.name,"馮楠楠");printf("姓名:%s\n分數:%d\n",stu1.name,stu1.score);int* a;//整型定義指針struct Student *p=NULL;//同樣的道理也可以定義結構體指針//這里這樣定義屬于野指針,對野指針進行寫操作要出現段錯誤p=(struct Student*)malloc(sizeof(struct Student));//不管是野指針還是等于NULL,//都不能對這個非法的內存訪問,否則出現段錯誤            p->score=150;//如果用結構體指針,就不能用點運算符訪問結構體中的變量,要用->strcpy(p->name,"馮楠楠");printf("姓名:%s\n分數:%d\n",p->name,p->score);free(p);//空間不用了就free掉防止內存泄漏p=&stu1;//指針是存放地址的變量,之前指向malloc那片空間,現在存放的是stu1的地址printf("姓名:%s\n分數:%d\n",p->name,p->score);    printf("地址是;%p\n",p++);//因為結構體大小為128+4=132,所以指針++偏移132個字節(十進制),結果:0060FE68printf("加加后地址是;%p\n",p);//結果:0060FEEC/*總結來說指針++,要看指針指向的對象是誰,并不是+1*/system("pause");return 0;
}

結構體指針操作學生成績表:

#include <stdio.h>
#include <stdlib.h>
/*
結構體指針訪問結構體內部元素方法:
結構體指針 ->成員名;如addr->country;
(*結構體指針).成員名;(*addr).country;//很少去進行使用,注意必須去使用(),,因為.優先級大于*
*/
struct Student
{int score;char*name;//4,linux 8
};
int main()
{int i;int len=2;struct Student stu[2];struct Student *p=stu;//結構體指針指向數組的頭,其實和整型數是一樣的for(i=0;i<sizeof(stu)/sizeof(stu[0]);i++){printf("請輸入名字;\n");p->name=(struct Student*)malloc(128);scanf("%s",p->name);printf("請輸入分數:\n");scanf("%d",&(p->score));p++;}p=stu;for(i=0;i<sizeof(stu)/sizeof(stu[0]);i++){printf("姓名:%s 分數::%d\n",p->name,p->score);p++;}struct Student *p2=(struct Student *)malloc(len*sizeof(struct Student));//上一行代碼是直接定義了結構體指針,并給他開辟5*sizeof(struct Student)怎么大的空間//相當于有5個結構體數組,可以存儲5個人的信息for(i=0;i<len;i++){printf("請輸入名字;\n");p2->name=(struct Student*)malloc(128);scanf("%s",p2->name);printf("請輸入分數:\n");scanf("%d",&(p2->score));p2++;}p2-=len;for(i=0;i<len;i++){printf("姓名:%s 分數::%d\n",p2->name,p2->score);p2++;}system("pause");return 0;
}

結構體指針函數綜合處理學生成績:

#include <stdio.h>
#include <stdlib.h>
//malloc在堆上面開辟空間,函數調用結束后空間不會被釋放
struct Student
{int score;char* name;
};
struct Student* initStuScores(int* len)//初始化函數,獲取用戶輸入完成初始化
{int i;printf("請輸入總人數:\n");scanf("%d",len);struct Student *p2=(struct Student *)malloc((*len)*sizeof(struct Student));//上一行代碼是直接定義了結構體指針,并給他開辟5*sizeof(struct Student)怎么大的空間//相當于有5個結構體數組,可以存儲5個人的信息//malloc開辟的空間不會消失,在函數內部定義的指針變量,不會對main函數中的指針有影響//p2是局部變量,返回的是p2的內容,不是p2for(i=0;i<(*len);i++){printf("請輸入名字;\n");p2->name=(struct Student*)malloc(128);scanf("%s",p2->name);printf("請輸入分數:\n");scanf("%d",&(p2->score));p2++;}return p2-*len;
}
void printMes(struct Student* p2,int len)
{int i;for(i=0;i<len;i++){printf("姓名:%s 分數::%d\n",p2->name,p2->score);p2++;}//p2=p2-len;
}
struct Student* findMaxStu(struct Student* p,int len)
{int i=0;struct Student* maxStudent;maxStudent=p;for(i;i<len;i++){if((p->score)>(maxStudent->score)){maxStudent=p;}p++;}return maxStudent;
}
struct Student* findMinStu(struct Student* p,int len)
{int i=0;struct Student* minStudent;minStudent=p;for(i;i<len;i++){if((p->score)<(minStudent->score)){minStudent=p;}p++;}return minStudent;}
float getAverage(struct Student*p,int len)
{int i;float toal=0;for(i=0;i<len;i++){toal=toal+p->score;p++;}return (float)toal/len;
}
int findSome(struct Student*p,int len,char*name)
{int i;for(i=0;i<len;i++){if(strcmp(name,p->name)==0){return 1;}p++;}return -1; 
}
int main()
{int len;struct Student *pstus=initStuScores(&len);printMes(pstus,len);struct Student* max=NULL;struct Student* min=NULL;max=findMaxStu(pstus,len);min=findMinStu(pstus,len);//函數傳參其實就是將地址值拷貝一份給函數//函數內的指針變量不會對main函數中的指針有影響//除非用二級指針printf("最高分:%d,姓名:%s\n",max->score,max->name);printf("最低分:%d,姓名:%s\n",min->score,min->name);printf("平均分是:%f\n",getAverage(pstus,len));if(findSome(pstus,len,"馮楠")==1){printf("找到此人\n");}else{printf("沒有此人\n");}system("pause");return 0;
}

結構體大小如何計算:

#include <stdio.h>
#include <stdlib.h>
/*由于存儲變量地址對齊的問題,結構體大小計算必須滿足兩條原則:一、結構體成員的偏移量必須是成員大小的整數倍(0被認為是任何數的整數倍)二、結構體大小必須是所有成員(數組和結構體除外)大小的整數倍三、對齊方式確實很浪費空間,可是按照計算機的訪問方式,這種對齊方式提高了效率*/
//簡單結構體
struct s1
{char ch1;//1  ch1相對于整個結構體的偏移量就是0,因為他是結構體的第一項char ch2;//1  ch2相對于整個結構體的偏移量就是1,因為結構體第一項是1個字節int i;//4     i相對于整個結構體的偏移量就是2,2不是4的倍數,邏輯偏移2,//實際按照對齊規則,要偏移4個字節,這樣ch2和i之間就右空余了兩個字節,//所以一共是8個字節 
};
//簡單結構體
struct s2{char ch1;//1  ch1偏移量是0,int i;//4     i的邏輯偏移值是1,要滿足第一條規則,所以偏移4//這樣ch1和i之間就有3個字節char ch2;//1   邏輯偏移量是8滿足條件一,但是結構體總大小為九//不滿足條件二,所以ch2要向后偏移3個字節,所以總大小是12
};
//成員包含數組的結構體
struct s3{char ch;//偏移值1int i;// 邏輯偏移值是1,實際偏移值4,ch和i之間有三個字節char str[10];//邏輯偏移值8,實際偏移值10,所以總大小是20//這個char類型的數組,只需要把它看做十個char連在一起即可
};
//成員包含結構體的結構體,若結構體內的結構體僅僅是聲明不占空間則可忽略
struct s4{char ch;//偏移量是1int i;//實際偏移量是1+3+4=8struct s{char ch1;int j;};//這個結構體大小是8,但是沒有定義所以忽略float f;//邏輯偏移量是8,實際偏移量是8,所以整個結構體大小為8+4=12//滿足條件一二
};
//成員包含結構體的結構體,若結構體內的結構體有定義,則占空間要計算
struct s5{char ch;//偏移量是1int i;//實際偏移量是1+3+4=8struct ss{char ch1;int j;}stemp;//這個結構體大小是8,滿足條件一float f;//邏輯偏移量是16,實際偏移量是16,所以整個結構體大小為16+4=20//滿足條件一二
};
//成員包含聯合體的結構體
struct s6{char ch;int i;union{//聯合體按照最大的計算就是4char ch1;int j;};
};
//指定對齊值:對齊值小于最大類型成員值
//如果最大成員超過了pack的要求,就按pack來對齊
//如果最大成員沒有超過pack,結構體總大小按最大成員開對齊
#pragma pack(4)  //指定向4對齊 最大是8
struct s7{char ch;int i;float f;double d;
};
//對齊值大于最大類型成員值,當指定對齊值大于自身對齊值時,向自身對其值對齊,大小是24.#pragma pack(10)
struct s8{char ch;int i;float f;double d;
};
int main()
{printf("char:%d\n",sizeof(char));//1printf("float:%d\n",sizeof(float));//4printf("int:%d\n",sizeof(int));//4printf("double:%d\n",sizeof(double));//8printf("s1:%d\n",sizeof(struct s1));//8printf("s2:%d\n",sizeof(struct s2));//12printf("s3:%d\n",sizeof(struct s3));//20printf("s4:%d\n",sizeof(struct s4));//12printf("s5:%d\n",sizeof(struct s5));//20printf("s6:%d\n",sizeof(struct s6));//12printf("s7:%d\n",sizeof(struct s7));//20printf("s8:%d\n",sizeof(struct s8));//24system("pause");return 0;
}

typedef關鍵字

#include <stdio.h>
#include <stdlib.h>
/*typedeftypedef關鍵字,作用是為一種數據類型定義一個新的名字這里的數據類型包括(int、char等等)和自定義的數據類型(struct等)
*//*在單片機開發中,寄存器有8位 16位 32位int data=0x1234;int是4個字節32位,如果是8位單片機的話可能裝不下所以有了 char data=0x11這樣的定義,因為數據類型的表示范圍都是有重合的地方的,比如0~128 int float double char 這四個數據類型都表示但是char表示數字就有了以下的寫法typedef unsigned char u_int8;表示(0~255這個區間的數)typedef unsigned short int u_int16;typedef unsigned short int u_int32;這樣定以后就可以用u_int8來代替unsigned charu_int16  nsigned shortu_int32  unsigned short然后就可以:u_int8 data=10;u_int16 data2=20;u_int32  data3=30;這種定義方式了
*//*
typedef struct Student
{int score;char* name;void (*p)(struct Student stu1);//定義一個函數指針要求參數類型是結構體類型的//可以用struct Student但是不可以用STU stu1 //因為STU定義在結構體外邊
}STU,*PSTU;//通常使用typedef重命名結構體時,會命名名稱和指針
*/
/*
typedef struct Student STU,*PSTU;也可以這樣重命名結構體
*/
typedef struct//也可以將Student去掉,直接給結構體命名
{int score;char* name;void (*p)(struct stu);
}STU,*PSTU;//通常使用typedef重命名結構體時,會命名名稱和指針int main()
{STU stu1;//直接可以用命名后的STU代替struct Studentstu1.score=100;printf("%d\n",stu1.score);PSTU stu2;//這個stu2就代表結構體指針,這行代碼等同于struct Student* stu2//PSTU就等同于struct Student*stu2=(PSTU)malloc(sizeof(STU));stu2->score=99;printf("%d\n",stu2->score);system("pause");return 0;
}

本文來自互聯網用戶投稿,該文觀點僅代表作者本人,不代表本站立場。本站僅提供信息存儲空間服務,不擁有所有權,不承擔相關法律責任。
如若轉載,請注明出處:http://www.pswp.cn/news/272282.shtml
繁體地址,請注明出處:http://hk.pswp.cn/news/272282.shtml
英文地址,請注明出處:http://en.pswp.cn/news/272282.shtml

如若內容造成侵權/違法違規/事實不符,請聯系多彩編程網進行投訴反饋email:809451989@qq.com,一經查實,立即刪除!

相關文章

命令行分析java線程CPU占用

1.使用top命令找出占用cpu最高的JAVA進程pid號 2. 找出占用cpu最高的線程&#xff1a; top -Hp pid -d 1 -n 1 3. 打印占CPU最高JAVA進程pid的堆棧信息 jstack pid > /tmp/stacktrace.log 4. 把占CPU最高線程號碼換算成16進制到stacktrace.log中尋找相應線程16進制值找到…

docker搜索鏡像

docker search 要下載的 OFFICIAL 為ok的表示是官方鏡像

C#操作HttpClient工具類庫

using System; using System.Collections.Generic; using System.Net.Http; using System.Windows.Forms; using System.Configuration; using System.IO; using Newtonsoft.Json; namespace Dcflow { public class HttpHelper { //獲取Configuration對象 public static string…

docker從倉庫找鏡像

docker search -s 數量 要下載的 數量表示倉庫start數

bzoj 1911: [Apio2010]特別行動隊 2011-12-26

1911: [Apio2010]特別行動隊 Time Limit: 4 Sec Memory Limit: 64 MBSubmit: 892 Solved: 359[Submit][Status][Discuss] DescriptionInputOutputSample Input4 -1 10 -20 2 2 3 4 Sample Output9HINT Source _________________________________________ 很簡單的動規方程&a…

嵌入式C語言基礎鏈表

什么是鏈表&#xff1f; 鏈表其實就是一種數據結構&#xff0c;所謂的數據結構就是數據存放的思想。 數組、鏈表優缺點&#xff1a; 增加一個元素或者刪除一個元素都很難&#xff0c;因為地址是連續的&#xff0c;刪除一個元素可能會挪動多個元素&#xff0c;不靈活。但是對于鏈…

docker pull 從倉庫拉取鏡像

docker pull 要拉取的鏡像名 等價于 docker pull 要拉取的鏡像名:lastest 拉取固定的鏡像&#xff1a;docker pull 要拉取的鏡像名:版本號 省略lastest表設計就是拉取的最新的

理解js中的原型鏈,prototype與__proto__的關系

說到prototype&#xff0c;就不得不先說下new的過程。 我們先看看這樣一段代碼&#xff1a; 1<script type"text/javascript">2 var Person function () { };3 var p new Person();4</script>很簡單的一段代碼&#xff0c;我們來看看這個new究竟做了什…

C#抓取網頁HTML內容

using System; using System.Collections.Generic; using System.Linq; using System.Web; using System.Net; using System.Text; using System.IO; using System.Text.RegularExpressions; namespace Web { /// <summary> /// 公共方法類 /// </summary> p…

項目一感應垃圾桶(Wemos)

硬件材料&#xff1a; Wemos D1、SG90舵機、HC-SR04、杜邦線若干、蜂鳴器3.3V&#xff08;可有可無&#xff09; 軟件材料&#xff1a; arduino IDE編譯器、USB轉串口驅動 Wemos D1&#xff1a; 特性&#xff1a; 基于ESP-8266EX及arduino做的一個融合arduino兼容&#xff0…

docker刪除本地所有鏡像

docker rmi -f ${docker images -qa}

PAT1069. The Black Hole of Numbers

//這是到水題&#xff0c;之前因為四位數的原因一直不能A&#xff0c;看了別人的程序&#xff0c;才明白&#xff0c;不夠四位的時候沒考慮到&#xff0c;坑啊。。。。。臉打腫 #include<cstdio>#include<algorithm>using namespace std;int main(){ //freopen(&qu…

WiFi避障小車

硬件清單&#xff1a; Wemos D1&#xff08;支持AP模式也就是路由模式和STA模式也就是上網設備&#xff09;、超聲波模塊、小車、L9110s步進電機控制器 軟件&#xff1a; eclipse、arduino IDE WiFi配置參考博文 ESP8266WiFi庫: 從上圖中可以看出ESP8266WiFi庫主要包含Stati…

yum常用命令整理

yum命令的形式一般如下。要說明的是以下演示中所使用到的PACKAGE、GROUP都是變量&#xff0c;需要保證運行yum命令的主機能連接外網&#xff0c;否則大部分命令將由于沒有網絡連接而不能輸出結果。yum [options] [command] [package]#以下演示中大寫的單詞是變量1.安裝操作yum …

CSS3 2D 轉換

CSS3 2D 轉換 先看兼容性 transform屬性向應用元素應用2d 或者 3d裝換&#xff1b;該屬性允許我們進行旋轉&#xff0c;縮放&#xff0c;移動或者傾斜&#xff1b; 基本語法&#xff1a; transform: none|transform-functions;transform-function&#xff1a;這東東有n的函數可…

程序猿最喜歡說的30句話

雖然代碼總會有這個那個問題&#xff0c;但程序猿卻總有謎一般的從容和自信。上圖來自&#xff1a;《當程序出問題時程序員最喜歡說的30句話》來看看程序猿經常說的話&#xff1a;1、在我的電腦上是正常的啊。。。2、不可能出現這種情況的3、快了&#xff0c;已經完成了90%。4、…

linux環境下Ncurses實現貪吃蛇游戲

游戲說明&#xff1a; linux環境下基于Ncurses圖形庫的C語言小游戲。 Ncurses介紹&#xff1a; Ncurses(new curses)是一套編程庫&#xff0c;它提供了一系列的函數以便使用者調用它們去生成基于文本的用戶界面。 Ncurses是一個能提供功能鍵定義(快捷鍵),屏幕繪制以及基于文本…

韓順平循序漸進學java 第13講 抽象類.接口

13.1抽象類 13.1.1 概念 當父類的一些方法不能確定時&#xff0c;可以用abstract關鍵字來修飾該方法&#xff0c;稱為抽象方法&#xff0c;用abstract來修飾該類&#xff0c;稱為抽象類。 13.1.2 抽象類-深入討論 抽象類是java中一個比較重要的類&#xff1a; 1、用abstract關鍵…

C#實現簡體繁體轉換代碼示例

//簡體轉繁體 public static string _ConvertChinTrad(string strInput) { EncodeRobert edControl new EncodeRobert(); string strResult ""; if (strInput null) return strResult; if (strInput.ToString().Length > 1) strResult edControl.SCTCConvert(…