c语言知识点8

C 字符串
在 C 语言中,字符串实际上是使用 null 字符 ‘\0’ 终止的一维字符数组。因此,一个以 null 结尾的字符串,包含了组成字符串的字符。
下面的声明和初始化创建了一个 “Hello” 字符串。由于在数组的末尾存储了空字符,所以字符数组的大小比单词 “Hello” 的字符数多一个。

char greeting[6] = {'H', 'e', 'l', 'l', 'o', '\0'};

注意点:
1.首先,strlen 是函数,sizeof 是运算操作符,二者得到的结果类型为 size_t,即 unsigned int 类型。大部分编译程序在编译的时候就把 sizeof 计算过了,而 strlen 的结果要在运行的时候才能计算出来。
对于以下语句:

char *str1 = "asdfgh";
char str2[] = "asdfgh";
char str3[8] = {'a', 's', 'd'};
char str4[] = "as\0df";

执行结果是:

sizeof(str1) = 4;  strlen(str1) = 6;
sizeof(str2) = 7;  strlen(str2) = 6;
sizeof(str3) = 8;  strlen(str3) = 3;
sizeof(str4) = 6;  strlen(str4) = 2;

解释:
str1是字符指针变量,sizeof 获得的是该指针所占的地址空间,32 位操作系统对应 4 字节,所以结果是 4;strlen 返回的是该字符串的长度,遇到 \0 结束, \0 本身不计算在内,故结果是 6。
str2 是字符数组,大小由字符串常量 “asdfgh” 确定,sizeof 获得该数组所占内存空间大小,包括字符串结尾的 \0 ,所以结果为 7;strlen 同理返回 6。
str3 也是字符数组,但大小确定为 8,故 sizeof 得到的结果是 8;strlen 统计 \0 之前所有字符的个数,即为 3;
str4 是常量字符数组,sizeof 得到字符总数即 6;strlen 计算至 \0 结束,因此返回 2;
总结一句就是 sizeof 计算的是变量的大小,而 strlen 计算的是字符串的长度,前者不受字符 \0 影响,后者以 \0 作为长度判定依据。
2. ‘a’ 表示是一个字符,“a” 表示一个字符串相当于 ‘a’+’\0’;‘a’里面只能放一个字符;"" 里面表示是字符串系统自动会在串末尾补一个 0。
3.
1、字符串的本质是以 \0 结束的字符数组。
2、字符串的字面量是常量,比如"hello world"。
3、字符串的定义与初始化。
1)数组形式
char hi[] = {‘h’,‘e’,‘l’,‘l’,‘o’,’\0’};
2)直接赋首地址:
char hi[50] =“hello” ;
3)省略长度
char hi[] = “hello”;
char hi[] = { “hello” };
字符指针:(注意指针不能直接赋给数组)
char *hi = “hello”;
4)字符串遍历:
char hi[] = “hello”;
for 遍历:
for(i==0, i<6,i++)
{
printf("%c",hi[i]);
}
直接输出:
printf(hi);
字符串格式(%s)输出:
printf("%s",hi);

C 结构体
C 数组允许定义可存储相同类型数据项的变量,结构是 C 编程中另一种用户自定义的可用的数据类型,它允许您存储不同类型的数据项。
定义结构
为了定义结构,您必须使用 struct 语句。struct 语句定义了一个包含多个成员的新的数据类型,struct 语句的格式如下:

struct tag { 
    member-list
    member-list 
    member-list  
    ...
} variable-list ;

tag 是结构体标签。
member-list 是标准的变量定义,比如 int i; 或者 float f,或者其他有效的变量定义。
variable-list 结构变量,定义在结构的末尾,最后一个分号之前,您可以指定一个或多个结构变量。下面是声明 Book 结构的方式:

struct Books
{
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
} book;

结构体变量的初始化

#include <stdio.h>

struct Books
{
   char  title[50];
   char  author[50];
   char  subject[100];
   int   book_id;
} book = {"C 语言", "STST", "编程语言", 123456};
 
int main()
{
    printf("title : %s\nauthor: %s\nsubject: %s\nbook_id: %d\n", book.title, book.author, book.subject, book.book_id);
}

执行输出结果为:
title : C 语言
author: STST
subject: 编程语言
book_id: 123456
举个例子

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

char * s_gets(char*st, int n);

#define MAXTITL 40
#define MAXAUTL 40
#define MAXBKS 100  // 书籍的最大数量

struct book {   //简历 book 模板
    char title[MAXTITL];
    char author[MAXAUTL];
    float value;
};

int main(void)
{
    struct book library[MAXBKS];  //book 结构类型数组
    int count = 0;
    int index;
    printf("请输入书名:\n");
    printf("按下 [enter] 键结束输入。\n");
    while (count < MAXBKS && s_gets(library[count].title, MAXTITL) != NULL && library[count].title[0] != '\0')
    {
        printf("请输入作者:\n");
        s_gets(library[count].author, MAXAUTL);
        printf("请输入价格:\n");
        scanf("%f", &library[count++].value);
        while (getchar() != '\n')
            continue;  //清理输入行
        if (count < MAXBKS)
            printf("输入下一本书。\n");
    }
    if (count > 0)  // 如果数组内有存书籍
    {
        printf("书的列表:\n");
        for (index = 0; index < count; index++)  // 遍历已存入的书籍,
            printf("%s - %s:$%.2f\n", library[index].title, library[index].author, library[index].value); // 将内容打印出来
    }
    else
        printf("没有书。\n");  // 否则就打印没书
    return 0;
}

char * s_gets(char * st, int n)  //输入文本(作家)函数
{
    char * ret_val;
    char * find;
    ret_val = fgets(st, n, stdin);
    if (ret_val)
    {
        find = strchr(st, '\n');  //查找换行符
        if (find)  //如果地址不是NULL
            *find = '\0';  //在此处放置一个空字符
        else
            while (getchar() != '\n')
                continue;
    }
    return ret_val;
}

知识点:

  1. .是成员访问符
  2. 结构体的成员可以是结构体数组的元素可以是结构体结构体的指针指向结构体
    补充:
    结构体内存大小对齐原则
  • 结构体变量的首地址能够被其最宽基本类型成员的大小所整除。
  • 结构体每个成员相对于结构体首地址的偏移量(offset)都是成员大小的整数倍,如有需要编译器会在成员之间加上填充字节(internal
    adding)。即结构体成员的末地址减去结构体首地址(第一个结构体成员的首地址)得到的偏移量都要是对应成员大小的整数倍。
  • 结构体的总大小为结构体最宽基本类型成员大小的整数倍,如有需要编译器会在成员末尾加上填充字节。

C 共用体
共用体是一种特殊的数据类型,允许您在相同的内存位置存储不同的数据类型。您可以定义一个带有多成员的共用体,但是任何时候只能有一个成员带有值。共用体提供了一种使用相同的内存位置的有效方式。
定义共用体
为了定义共用体,您必须使用 union 语句,方式与定义结构类似。union 语句定义了一个新的数据类型,带有多个成员。union 语句的格式如下:

union [union tag]
{
   member definition;
   member definition;
   ...
   member definition;
} [one or more union variables];

例子:

扫描二维码关注公众号,回复: 8876709 查看本文章
union Data
{
   int i;
   float f;
   char  str[20];
} data;

注意点:
共用体占用的内存应足够存储共用体中最大的成员。
位:"位(bit)“是电子计算机中最小的数据单位。每一位的状态只能是0或1。
字节:8个二进制位构成1个"字节(Byte)”,它是存储空间的基本计量单位。
字:"字"由若干个字节构成,字的位数叫做字长,不同档次的机器有不同的字长。例如一台8位机,它的1个字就等于1个字节,字长为8位。如果是一台16位机,那么,它的1个字就由2个字节构成,字长为16位。字是计算机进行数据处理和运算的单位。
访问共用体成员
为了访问共用体的成员,我们使用成员访问运算符(.)。成员访问运算符是共用体变量名称和我们要访问的共用体成员之间的一个句号。您可以使用 union 关键字来定义共用体类型的变量。下面的实例演示了共用体的用法:同一时间只用到一个成员。

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

union Data
{
   int i;
   float f;
   char  str[20];
};
 
int main(int argc,char *argv[])
{
   union Data data;        
 
   data.i = 10;
   data.f = 220.5;
   strcpy( data.str, "C Programming");
 
   printf( "data.i : %d\n", data.i);
   printf( "data.f : %f\n", data.f);
   printf( "data.str : %s\n", data.str);
 
   return 0;
}

结果如下:

data.i : 1917853763
data.f : 4122360580327794860452759994368.000000
data.str : C Programming

C 位域
有些信息在存储时,并不需要占用一个完整的字节,而只需占几个或一个二进制位。例如在存放一个开关量时,只有 0 和 1 两种状态,用 1 位二进位即可。为了节省存储空间,并使处理简便,C 语言又提供了一种数据结构,称为"位域"或"位段"。
所谓"位域"是把一个字节中的二进位划分为几个不同的区域,并说明每个区域的位数。每个域有一个域名,允许在程序中按域名进行操作。这样就可以把几个不同的对象用一个字节的二进制位域来表示。
典型的实例:

用 1 位二进位存放一个开关量时,只有 0 和 1 两种状态。
读取外部文件格式——可以读取非标准的文件格式。例如:9 位的整数。

位域的定义和位域变量的说明
位域定义与结构定义相仿,其形式为:
struct 位域结构名
{
位域列表
};
其中位域列表的形式为:
类型说明符 位域名: 位域长度
例如:

struct bs{
    int a:8;
    int b:2;
    int c:6;
}data;

访问方式:
位域的使用
位域变量名.位域名
位域变量名->位域名
例子
对于位域的定义尚有以下几点说明:
一个位域存储在同一个字节中,如一个字节所剩空间不够存放另一位域时,则会从下一单元起存放该位域。也可以有意使某位域从下一单元开始。例如:

struct bs{
    unsigned a:4;
    unsigned  :4;    /* 空域 */
    unsigned b:4;    /* 从下一单元开始存放 */
    unsigned c:4
}

在这个位域定义中,a 占第一字节的 4 位,后 4 位填 0 表示不使用,b 从第二字节开始,占用 4 位,c 占用 4 位。
由于位域不允许跨两个字节,因此位域的长度不能大于一个字节的长度,也就是说不能超过8位二进位。如果最大长度大于计算机的整数字长,一些编译器可能会允许域的内存重叠,另外一些编译器可能会把大于一个域的部分存储在下一个字中。
位域可以是无名位域,这时它只用来作填充或调整位置。无名的位域是不能使用的。例如:
struct k{
int a:1;
int :2; /* 该 2 位不能使用 */
int b:3;
int c:2;
};
从以上分析可以看出,位域在本质上就是一种结构类型,不过其成员是按二进位分配的。

#include <stdio.h>
#include <string.h>
 
struct
{
  unsigned int age : 3;
} Age;
 
int main( )
{
   Age.age = 4;
   printf( "Sizeof( Age ) : %d\n", sizeof(Age) );
   printf( "Age.age : %d\n", Age.age );
 
   Age.age = 7;
   printf( "Age.age : %d\n", Age.age );
 
   Age.age = 8; // 二进制表示为 1000 有四位,超出
   printf( "Age.age : %d\n", Age.age );
 
   return 0;
}

当上面的代码被编译时,它会带有警告,当上面的代码被执行时,它会产生下列结果:

Sizeof( Age ) : 4
Age.age : 4
Age.age : 7
Age.age : 0

例子:

// 位域内存测试
#include <stdio.h>
struct ONE_BYTE
{
    unsigned char _bool : 1;
    unsigned char del_flag : 1;
    unsigned char status : 4;
} one_byte;

struct TWO_BYTE
{
    unsigned char ccc1 : 4;
    unsigned char ccc2 : 4;
    unsigned char ccc3 : 4;
    unsigned char ccc4 : 4;
} two_byte;

struct THREE_BYTE
{
    unsigned char ccc1 : 4;
    unsigned char ccc2 : 4;
    unsigned char ccc3 : 4;
    unsigned char ccc4 : 4;
    unsigned char ccc5 : 4;
} three_byte;

struct FOUR_BYTE
{
    unsigned int ccc1 : 16;
    unsigned int ccc2 : 16;
} four_byte;


struct EIGHT_BYTE
{
    unsigned char ccc1 : 1;
    unsigned int ccc2 : 1;
} eight_byte;

int main(int argc, char const *argv[])
{
    printf("sizeof one_byte is : %lu\n", sizeof(one_byte));
    printf("sizeof two_byte is : %lu\n", sizeof(two_byte));
    printf("sizeof three_byte is : %lu\n", sizeof(three_byte));
    printf("sizeof four_byte is : %lu\n", sizeof(four_byte));
    printf("sizeof eight_byte is : %lu\n", sizeof(eight_byte));
    return 0;
}

输出结果为:
sizeof one_byte is : 1B
sizeof two_byte is : 2B
sizeof three_byte is : 3B
sizeof four_byte is : 4B
sizeof eight_byte is :8B
由输出,可以验证以下结论:
(1)结构体内存分配原则:
原则一:结构体中元素按照定义顺序存放到内存中,但并不是紧密排列。从结构体存储的首地址开始 ,每一个元素存入内存中时,它都会认为内存是以自己的宽度来划分空间的,因此元素存放的位置一定会在自己大小的整数倍上开始。
原则二: 在原则一的基础上,检查计算出的存储单元是否为所有元素中最宽的元素长度的整数倍。若是,则结束;否则,将其补齐为它的整数倍。
(2)定义位域时,各个成员的类型最好保持一致,比如都用char,或都用int,不要混合使用,这样才能达到节省内存空间的目的。
警告:

struct 
{
    unsigned int age : 3;
} Age;
/*age 变量将只使用 3 位来存储这个值,如果您试图使用超过 3 位,则无法完成 */
Age.age = 4;
printf("Sizeof( Age ) : %d\n", sizeof(Age));
printf("Age.age : %d\n", Age.age);

// 二进制表示为 111 有三位,达到最大值
Age.age = 7;
printf("Age.age : %d\n", Age.age);

// 二进制表示为 1000 有四位,超出
Age.age = 8;
printf("Age.age : %d\n", Age.age);

如果超出范围,则直接丢掉了,存不进去。

发布了31 篇原创文章 · 获赞 6 · 访问量 911

猜你喜欢

转载自blog.csdn.net/qq_44797965/article/details/104083639