嵌入式linux學習筆記:06_C語言_函數及數據組織

一、字符串函數

1、字符串在程序中如何保存使用?
char A[10] = “hello”; -> 將常量區"hello"拷貝到數組A內存空間。

char *p = “hello”; -> 將常量區"hello"首元素的地址保存在指針變量p中。

2、在linux下,有些關於字符串函數提供用戶使用。
1)計算字符串實際長度 ->strlen()
2)比較兩個字符串是否匹配 -> strcmp()
3)拷貝字符串到某段內存中 -> strcpy()
4)追加字符串 ->strcat()

1、計算字符串實際長度 strlen( )-> 不包含’\0’在內

Ubuntu:man 3 strlen

NAME -> 函數的功能

strlen - calculate the length of a string -> 校對字符串長度

#include <string.h> -> 頭文件

size_t strlen(const char *s); -> 函數原型

s: 需要計算的字符串的首元素的地址

返回值:字符的個數。

例子:

#include <stdio.h>
#include <string.h>
int main()
{
       char A[100] = "helloworld";

       char *p = "helloworld";

       printf("sizeof(A) = %d\n",sizeof(A));//100

       printf("sizeof(p) = %d\n",sizeof(p));//4

       printf("strlen(A) = %d\n",strlen(A));//10

       printf("strlen(p) = %d\n",strlen(p));//10

       return 0;
}

結論: sizeof()計算空間大小,strlen()計算字符串的長度。

2、比較兩個字符串是否匹配 -> strcmp()

1、與整型變量是否相等比較
int a = 200;
int b = 100;
if(a == b) -> 整型數據使用"=="來進行判斷

2、比較兩個字符串能不能用"=="?
char A[100] = “helloworld”;

char *p = “helloworld”;

if(A == p) -> 不可以,只能判斷兩個地址是否相等,這樣對比是沒有任何意義,只有對比內容纔有意義。

3、 如何比較兩個字符串? -> 只能使用strcmp() -> man 3 strcmp

NAME
strcmp, strncmp - compare two strings 比較兩個字符串

#include <string.h>

int strcmp(const char *s1, const char *s2);

int strncmp(const char *s1, const char *s2, size_t n);

s1:需要進行比較的字符串1的地址

s2:需要進行比較的字符串2的地址

n: 只匹配前n個字節

返回值:

s1s2匹配 -> 0

s1s2不匹配 -> 非0

4、例子:

#include <stdio.h>
#include <string.h>
int main()
{
     int ret;
     char A[100] = "helloworld";
    char *p = "hello";
       ret = strncmp(A,p);
       if(ret == 0){
              printf("match!\n");
       }
       else{
              printf("no match!\n");
       }
	return 0;
}

練習:有一張銀行卡,密碼是gec123456,請求用戶輸入密碼,如果密碼正確,則輸出密碼的長度,如果密碼錯誤,則重新輸入!如果輸入的次數超過5次,則程序直接退出。

#include <stdio.h
#include <string.h>
int main(int argc,char *argv[]) 
{
       char passwd[20] = "gec123456"; //銀行卡密碼
       char input_passwd[20] = {0}; //清空數組
       char *p = input_passwd;
       int count = 0;
       while(count < 5)
       {
              scanf("%s",p);
              if(strcmp(passwd,p) == 0)
              {
                    printf("passwd length = %d\n",strlen(passwd));
                     break;
              }
              else{
                     count++;
                     continue;
              }
       }      
       return 0;
}

3、拷貝字符串到某段內存中 -> strcpy()

char A[10] = “hello”;

char A[10] = {“hello”};

char A[10] = {‘h’,‘e’,‘l’,‘l’,‘o’};

char A[10]; -> 如果定義沒有初始化,則以後都不能整體初始化。

A[0] = ‘h’;

strcpy() -> 如果定義沒有初始化,則以後還能使用strcpy()整體初始化。 -> man 3 strcpy

char A[10];

A = “hello” //錯誤

strcpy(A,“hello”); //正確

NAME
strcpy, strncpy - copy a string

SYNOPSIS

#include <string.h>

char *strcpy(char *dest, const char *src);

char *strncpy(char *dest, const char *src, size_t n);

dest:需要把字符串拷貝到的空間的起始地址,這個空間必須足夠大。
src:需要拷貝的字符串的地址。
n: 只拷貝src前n個字節
返回值:

成功: 返回指向dest內存空間的地址

失敗: NULL

#include <stdio.h>
#include <string.h>
int main()
{
       char A[11] = "helloworld";
       char *p = "abc";
       int i;
       for(i=0;i<11;i++)
       {
              printf("A[%d] = %c\n",i,A[i]);
       }
       strcpy(A,p);
       for(i=0;i<11;i++)
       {
              printf("A[%d] = %c\n",i,A[i]);
       }
       printf("A = %s\n",A);
       return 0;
}

4、字符串函數 -> 追加字符串 strcat()

字符串函數 -> 追加字符串strcat()-> man 3 strcat

使用格式:
#include <string.h>

char *strcat(char *dest, const char *src);

char *strncat(char *dest, const char *src, size_t n);

src:需要追加到另一個字符串默認的字符串的地址。 -> 拷貝之後會覆蓋dest的\0。
dest:被追加的字符串的空間,空間必須足夠大。
返回值:指向dest區域的首元素的地址。
驗證: overwriting the terminating null byte (’\0’) at the end of dest, and then adds a terminating null byte.

src覆蓋dest的\0,並且會在拼接之後在字符串的默認添加一個\0。

#include <stdio.h>
#include <string.h>
int main()
{
       /* 可以 */
       char A[20] = "hello";
       strcat(A,"world");
       /* 可以 */
       char A[20] = "hello";
       char *p = A;
       strcat(p,"world");
       /* 不可以 */
       char *p = "hello";
       strcat(p,"world");
       printf("p = %s\n",p); //helloworld
       return 0;
}

總結:學習過4個字符串函數的使用場景

  1. strlen() -> 確定某些數據的字節數 -> 文件IO/系統編程/網絡編程 write()/send()
  2. strcmp() -> 檢索特徵數據 -> 鏈表/網絡編程 -> 對比特徵值/協議是否一致
  3. strcpy() -> 用於初始化字符數組
char A[10]="helloworld";  對
char A[10];
A = "helloworld";   不對
char A[10];
strcpy(A,"hello");
  1. strcat -> 拼接字符串,僅限追加功能 -> 後期使用sprintf() 替代 strcat()

5、 數組清零方式

1、定義數組的同時初始化0
例子: char str[50] = {0};

特點:只能初始化(清零)一次。

2、清空某段內存空間。 -> bzero() -> man 3 bzero
bzero - write zero-valued bytes -> 函數的功能

#include <strings.h> -> 頭文件

void bzero(void *s, size_t n); -> 函數原型

s:需要清零的內存的地址
n:需要清零的字節數
返回值:無
特點:多次調用,多次清零。

#include <stdio.h>
#include <strings.h>
int main()
{
       char A[10];
       int i;
       for(i=0;i<10;i++)
       {
              printf("A[%d] = %c\n",i,A[i]);
       }
       bzero(A,sizeof(A));
       for(i=0;i<10;i++)
       {
              printf("A[%d] = %c\n",i,A[i]);
       }
       return 0;
}

二、堆空間

1、堆空間的特點:主動申請,主動釋放

2、如何申請堆空間? -> malloc() -> man 3 malloc

#include <stdlib.h>

void *malloc(size_t size);

size:需要申請的字節數
The memory is not initialized. -> 內存沒有被初始化過。

返回值:
成功: 指向堆空間的起始地址

失敗: NULL

例子:

void *pa = malloc(4) -> 在堆空間申請4個字節,然後在棧空間申請一個指針變量pa指向堆空間。

int *p = pa; -> 把堆空間的pa賦值賦值給指針變量p

int pa; -> 在棧空間申請4個字節

int *p = &pa; -> 把棧空間pa變量的地址賦值給指針變量p

例題1: 申請了堆空間,堆空間的值會是什麼?

#include <stdio.h>
#include <stdlib.h>
int main()
{
       int A[3];

       printf("A = %p\n",A);

       int *p = malloc(sizeof(int)*3);  // int A[3];

       printf("p = %p\n",p);

       printf("p[0] = %d\n",p[0]); //0

       printf("p[1] = %d\n",p[1]); //0

       printf("p[2] = %d\n",p[2]); //0

       free(p);

       return 0;
}

3、如何釋放空間? -> free() -> man 3 free

#include <stdlib.h>

void free(void *ptr);

ptr:需要釋放堆空間的地址
返回值:無
一般做法:free掉指向堆區指針之後,會讓指針指向NULL。
free§;
p = NULL;

三、堆空間與棧空間在內存中容易出錯的點

下列代碼是否正確?如果正確,請指出代碼的含義,如果出錯,則說明錯誤的原因。

1、棧區

char A[10] = “hello”; //把常量區的hello拷貝到變量A數組中

strcpy(A,“world”); //把常量區的world拷貝到變量A數組中

============================
char *p = “hello”; //把常量區的hello的首元素的地址賦值給變量p

strcpy(p,“hello”); //段錯誤,因爲p只能存放地址,不能存放字符串。

============================

char A[10];

strcpy(A,“hello”); //可以

============================

char *p;

strcpy(p,“hello”); //段錯誤,因爲p只能存放地址,不能存放字符串。

============================

char A[10]; //在棧區中申請10個字節,使用變量A間接訪問這個數組

char *p = A; //在棧區申請4個字節,使用變量p間接訪問這片內存,將數組的A的首元素的地址賦值給p

strcpy(p,“hello”); //將常量區的hello拷貝到p指向的棧區空間

============================

2、堆區

char *p = malloc(sizeof(char)*10); //在堆區中申請10個字節,使用p間接訪問這片內存空間。

p = “hello”; //給p賦值了常量區hello的地址,就是說現在p不是指向堆,而是指向常量區。

============================

char *p = malloc(sizeof(char)*10); //在堆區中申請10個字節,使用p間接訪問這片內存空間。

strcpy(p,“hello”); //可以,把常量區的hello拷貝到堆區!

四、結構體

1、什麼是結構體?

將多個不同類型的變量加入到一個集合中,這個集合就稱之爲結構體

由於結構體中存在不同類型的變量,所以每一個變量都需要用戶自己定義。

可以在結構體中定義:
基本數據類型: char short int long float double

非基本數據類型:int A[3]int*pchar B[2][3]char *pxchar pa[5]int(*pfun)(int)

不可以在結構體中定義:函數

2、 如何定義結構體?

關鍵詞:struct
模型:

struct 結構體名字{
       /* 結構體的組成變量 */
       例子:
       int a;
       char b;
       int A[3];
       int *p;
};   -> 後面記住有一個分號,不然報錯。

其實結構體就是一種新的數據類型。
例子:

struct data{
       int a;
       char b;   
}; 

在這裏只是先說: “struct data” 這種新類型由 {int a;char b;}組成。

3、如何定義結構體的變量?

struct mydata{
       char name[20];
       int age;
};

struct mydata -> 新的數據類型

定義變量公式: 數據類型 + 變量名;

定義整型變量 int a;
定義結構體變量 struct mydata A;

4、結構體的指針如何定義?

定義結構體變量: struct mydata A;
1)先寫一個*

2)在*後面寫一個變量的名字 *p

3)確認指針指向的內容是什麼。struct mydata A;

4)將指向的內容的變量名去掉struct mydata

5)將第4步的結果寫在第2步的前面 struct mydata *p;

結果:struct mydata *p;
變量名: p
數據類型: struct mydata *

5、結構體的變量與指針如何訪問成員?

1)設計結構體模型

struct mydata{
       char name[20];
       int age;
};

2)定義一個結構體的變量
struct mydata gec;

3)結構體變量使用"."來對成員進行訪問。
公式: 結構體變量名.成員名字

例子:

strcpy(gec.name,"ggy");

gec.age = 10;

4)結構體指針使用"->"訪問成員。
公式: 結構體指針變量名->成員名字

例子:

strcpy(p->name,"ggy");

p->age = 10;

6、結構體初始化值

1)先定義一個變量,後使用./->對成員進行賦值
struct mydata gec;

strcpy(gec.name,“ggy”);

gec.age = 10;

2)使用初始化列表
struct mydata gec = {“helloworld”,20}; -> 等價於將"helloworld"拷貝到name成員的空間中,20就賦值給age;

struct mydata gec = {“helloworld”}; -> 後面沒有賦值的成員 變量爲0 指針爲NULL

3)使用另外一個結構體給某個結構體整體賦值
struct mydata gec;

struct mydata A = {“hello”,20};

gec = A;

練習: 做一個通訊錄,裏面存放三個同學信息,每一個同學包含: 姓名,年齡,電話號碼 -> 結構體數組。

  1. 先分別對三個同學註冊。

  2. 輸出三個同學的全部信息。

#include <stdio.h>

struct mydata{
       char name[20];
       int age;
       char tel[20];
};

int main()
{
       struct mydata A[3];
       int i; //0~2
       for(i=0;i<3;i++)
       {
              printf("pls input %d name",i+1);
              scanf("%s",A[i].name);
              printf("pls input %d age",i+1);
              scanf("%d",&A[i].age);
              printf("pls input %d tel",i+1);
              scanf("%s",A[i].tel);
       }
	printf("====================================================\n");
       for(i=0;i<3;i++)
       {
              printf("%s %d %s\n",A[i].name,A[i].age,A[i].tel);
       }
       return 0;
}

7、計算結構體類型在內存中佔用的字節數。

基本數據類型:char 、short、int 、long、 float、 double -> 佔用字節數固定。

例子: int a -> 佔用4個字節

自定義結構體數據類型佔用多少個?

struct mydata{
       char name[20];
       int age;
       char tel[20];
};

例子1:

struct mydata{
       char name[20];
       int age;
};

sizeof(struct mydata) = ? //24

例子2:

struct mydata{
       int age;
       char name[20];
};

sizeof(struct mydata) = ? //24

例子3:

struct mydata{
       int age;
       char name;
};

sizeof(struct mydata) = ? //8

例子4:

struct mydata{
       int age;
       char name;
       short a;
};

sizeof(struct mydata) = ? //8

例子5:

struct mydata{
       char a;
       char b;
       short c;
};

sizeof(struct mydata) = ? //4

=例子6:=

struct mydata{
       char a;
       short b;
       char c;   
};

sizeof(struct mydata) = ? //6

例子7:

struct mydata{
       char a;
       short b;
       char c;   
       int d;
       int e;
};

sizeof(struct mydata) = ? //16

例子

struct mydata{
       char a;
       int (*px)[3];
       char A[10];
       int b;
       char **p;
       short c;
       char a;
       short f;
       int e;
       char B[18];
};  //60

例子

struct mydata{
       short a;
       int (*px)(int,int);
       char b;
       char c;
      int d;
       char A[13];
       short e;
      int **p;
      int f;
       char *B[3];
}; //52

在這裏插入圖片描述
計算結構體佔用空間大小的方法:
1)從上往下計算,而不是根據類型的大小來計算。
2)看看當前結構體中最大的成員佔用是2/4 -> 2的話結果就是2的倍數 4的話結果就是4的倍數。
3)如果某個結構體成員計算完,但是當前沒有對齊,那麼剩餘的字節大小就應該與下一個成員大小進行比較(字節對齊

  1. 下一個成員的大小大於當前行剩餘的字節大小
    結果: 剩餘的字節補0,下一個成員開闢新的一行空間。
  2. 下一個成員的大小小於/等於當前行剩餘的字節大小
    結果:將下一個成員塞進剩餘的字節中
    4)全部結構體成員處理完後,看看2的倍數/4的倍數來進行補0。

六、聯合體

1、爲什麼會有聯合體?

爲了解決結構體在內存中佔用比較大情況。

例子:

struct mydata{
       char name[20];
       int age;
       char tel[20];
};

sizeof(struct mydata) = 44; -> 佔用非常多空間 -> 如果定義爲聯合體,則大大節省。

2、聯合體定義方式與結構體一致,只需要修改關鍵詞即可。

struct -> union

例子:

union mydata{
       char name[20];
       int age;
       char tel[20];
};

sizeof(union mydata) = 20

但是使用的時候,只能同時使用一個成員。
計算聯合體的空間大小:
1)看看聯合體哪個成員是佔用空間最大的。

2)看看當前結構體中最大的成員佔用是2/4 -> 2的話結果就是2的倍數 4的話結果就是4的倍數。

3)如果該成員佔用字節數是2/4的倍數,那麼聯合體的大小就是該變量佔用的字節數。

4)如果該成員佔用字節數不是2/4的倍數,那麼看情況來補0。

3、由於聯合體只能同時使用一個成員,不能整體賦值。

例子:

union data{
       char name[10];
     int age;
};

union data A = {“ggy”,10};

編譯警告; warning: excess elements in union initializer

==========================================================

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

union data{
       char name[10];
       int age;
};

int main()
{
       union data A;
       strcpy(A.name,"ggy");
       printf("A.name = %s\n",A.name);
       bzero(A.name,sizeof(A.name));
       A.age = 10;
       printf("A.age = %d\n",A.age)return 0;
}

=====================================================

4、在聯合體中,所有成員的起始地址都是一致的。

#include <stdio.h>
#include <string.h>
#include <strings.h>
union data{
       char name[10];
      int age;
};

int main()
{
       union data A;
       printf("A.name:%p\n",A.name);
       printf("A.age:%p\n",&A.age);
       return 0;
}

執行:
A.name:0xbfb3b220

A.age:0xbfb3b220

5、聯合體也是可以作爲函數的參數

#include <stdio.h>
#include <string.h>
#include <strings.h>
union data{

       char name[10];
       int age;
};

void fun(union data B)  //B = A
{
      printf("B.name = %s\n",B.name);
       return;
}

int main()
{
       union data A;
       strcpy(A.name,"ggy");
       fun(A);
       return;
}

七、枚舉類型

1、什麼是枚舉類型?

枚舉類型其實就是int類型常量,意義就是給常量一個身份。
例子: ok -> 1 warning -> 0 error -> -1

2、枚舉類型一般作用地方?

1)可以作用於switch語句。
2)在函數返回值。 return 枚舉類型數據類型

void fun()
{
       if(xxxx)
              return warning;  -> 別人看起來就知道返回值是什麼情況。
       if(yyyy)
              return ok;
       if(zzzz)
              return error;
}

3、如何定義枚舉類型?

關鍵詞: enum

模型:

enum mydata{
       ok,    //如果沒有賦值,第一個成員默認從0開始!   //0
      warning,  //後面沒有賦值的成員默認在前面的基礎+1  //1
       error,                                         //2
};
enum mydata{
       ok = 1,  
       warning = 0,
       error = -1,
}; 
enum mydata{
       ok = 10,  
       warning = 20,
      error, //21
};

八、typedef關鍵詞

1、什麼是typedef?作用是什麼?

typedef其實就是 type+ define,給一種數據類型(基本數據類型/非基本數據類型)取一個新的別名

例子: 給int這種類型取一個新的名字叫aaa。 -> 很少給基本數據類型取別名 1%

   給struct mydata這種數據類型取新的名字叫mydata。  -> 給非基本數據類型取別名  99%

作用: 簡化複雜的數據類型。

2、如何使用typedef給數據類型取別名?

使用格式: typedef + 數據類型 + 新的名字

1)給int這種類型取一個新的名字叫aaa。
typedef int aaa; -> 原則來typedef後面的這個"int aaa"看看,類型是int,剩下的就是aaa就是它的新名字。

在後面的代碼中,定義一個整型變量:aaa a;

例子:

#include <stdio.h>
int main()
{
       typedef int aaa; //int 等價於 aaa
       aaa a = 10;
       printf("a = %d\n",a);
       return 0;
}

2)給struct mydata這種數據類型取新的名字叫mydata。

typedef struct mydata{
       char name[20];
       int age;  
}mydata;  //struct mydata 等價於 mydata
 
mydata bbb;  -> 定義一個結構體變量。
發表評論
所有評論
還沒有人評論,想成為第一個評論的人麼? 請在上方評論欄輸入並且點擊發布.
相關文章