2019年7月15日(C语言)

2019-07-15

2019年7月15日(C语言)

一、字符串函数  -> 追加字符串 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");

4. strcat  -> 拼接字符串,仅限追加功能  -> 后期使用sprintf() 替代 strcat()

二、数组清零方式

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);
       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*p  char B[2][3]  char *px  char 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;

六、结构体初始化值

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;

}

. 计算结构体类型在内存中占用的字节数。

基本数据类型: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

};

2019年7月15日(C语言)

2019年7月15日(C语言)

原文地址:https://www.cnblogs.com/zjlbk/p/11190609.html