Linux第一课:c语言 学习记录day10
六、函数
8、string函数族
3、strcat
#inlcude <string.h>
char *strcat(char *dest, const char *src);
功能:用于字符串拼接
参数:dest:目标字符串首地址
src:原字符串首地址
返回值:目标字符串首地址
示例:
#include <stdio.h>
#include <string.h>
int main(int argc, char const *argv[])
{
char s[32] = "world";
char a[32] = "hello";
strcat (s, a);
printf ("%s\n", s);
return 0;
}
#inlcude <string.h>
char *strcat(char *dest, const char *src);
功能:用于字符串拼接
参数:dest:目标字符串首地址
src:原字符串首地址
n:原字符串拼接个数
返回值:目标字符串首地址
#include <stdio.h>
#include <string.h>
int main(int argc, char const *argv[])
{
char s[32] = "world";
char a[32] = "hello";
strncat (s, a, 3);
printf ("%s\n", s);
return 0;
}
4、strcmp
#include <string.h>
int strcmp(const char *s1, const char *s2);
功能:用于字符串比较
参数:s1、s2 用于比较字符串首地址
返回值:
从字符串首个字符开始比较字符ASCII码的大小,如果相等继续比较第二个字符
s1 > s2 ASCII:s1 - s2
s1 == s2 0
s1 < s2 ASCII:s1 - s2
#include <stdio.h> #include <string.h> int main(int argc, char const *argv[]) { char a[3] = "aa"; char b[3] = "bb"; char s[3] = "aa"; int ret1 = strcmp (a, s); int ret2 = strcmp (a, b); int ret3 = strcmp (b, a); printf ("ret1 = %d\n", ret1); printf ("ret2 = %d\n", ret2); printf ("ret3 = %d\n", ret3); return 0; }
#include <string.h>
int strncmp(const char *s1, const char *s2, size_t n);
功能:用于字符串比较
参数:s1、s2 用于比较字符串首地址
n:两个字符串比较的前n位
返回值:
从字符串首个字符开始比较字符ASCII码的大小,如果相等继续比较第二个字符
s1 > s2 ASCII:s1 - s2
s1 == s2 0
s1 < s2 ASCII:s1 - s2
七、结构体
1、定义
用户自定义的数据类型,在结构体中可以包含若干个成员变量(数据类型可以不同也可以相同),使这些数据项组合起来反应某一个信息
2、格式
struct 结构体名 // 用户自己定义的数据类型
{
数据类型 成员变量 1;数据类型 成员变量 2;
……
数据类型 成员变量 n; // 描述信息的变量
}
3、结构体变量
1、概念
通过结构体类型定义的变量
2、格式
struct 结构体名 变量名;
1、先定义结构体,再定义结构体变量
struct 结构体名
{
成员变量 1;};
struct 结构体名 变量名;
#include <stdio.h> struct student { char name[32]; int id; int age; }; int main(int argc, char const *argv[]) { struct student stu; return 0; }
此时stu为局部变量
2、定于结构体的同时,定义结构体变量
struct 结构体名
{
成员变量
}变量名;
#include <stdio.h> struct student { char name[32]; int id; int age; }stu; int main(int argc, char const *argv[]) { return 0; }
此时stu为全局变量
3、缺省结构体名定义结构体变量
struct
{
成员变量;
}变量名;
4、赋值
1、定义变量的同时,直接用{}赋值
#include <stdio.h> struct student { char name[32]; int id; int age; }; int main(int argc, char const *argv[]) { struct student stu = {"Zhangsan", 123456, 18}; // 一一对应 return 0; }
2、定义变量时,未初始化,然后对变量单独赋值
#include <stdio.h> #include <string.h> struct student { char name[32]; int id; int age; }; int main(int argc, char const *argv[]) { struct student stu; stu.age = 18; stu.id = 1; strcpy(stu.name, "Zhangsan"); return 0; }
3、点等法赋值
#include <stdio.h>
#include <string.h>
struct student
{
char name[32];
int id;
int age;
};
int main(int argc, char const *argv[])
{
struct student stu = {
.age = 34,
.id = 1234,
.name = "Zhangsan",
};
return 0;
}
5、访问
通过 . 访问:结构体变量名. 成员变量名
#include <stdio.h>
#include <string.h>
struct student
{
char name[32];
int id;
int age;
};
int main(int argc, char const *argv[])
{
struct student stu;
scanf("%s %d %d", stu.name, &stu.id, &stu.age);
printf("%s %d %d\n", stu.name, stu.id, stu.age);
return 0;
}
6、重定义
typedef
typedef int int_num;
int a; == int_num a;
typedef int* int_p;
int *p = &a; == int_p p = &a;
1、定义结构体的同时重定义
typedef struct student
{
char name[32];
int id;
int age;
}STU; // typedef struct student STU
struct student stu; == STU stu;
2、先定义结构体,然后重定义
struct student
{
char name[32];
int id;
int age;
};
typedef struct student STU;
7、结构体数组
1、概念
结构体类型相同的变量组成的数组
2、格式
1、定义结构体的同时,定义结构体数组
struct student
{
int id;int age;
} stu[3];
2、先定义结构体,然后定义结构体数组
struct student
{
int id;int age;
} ;
struct student stu[3];
3、初始化
1、定义结构体数组同时赋值
#include <stdio.h>
struct student
{
char name[32];
int id;
int age;
} stu[3] = {
{"zhangsan", 1, 45}, // 第一个人的信息
{"lisi", 2, 32},
{"wangwu", 3, 123},
};
int main(int argc, char const *argv[])
{
return 0;
}
2、先定义结构体数组,再对结构体数组的每一个元素分别赋值
struct student
{
char name[32];
int id;
int age;
} stu[3];
strcpy(stu[0].name, "zhangsan");
stu[0].id = 2;
stu[1].age = 12;
4、结构体数组的大小
元素个数 * 结构体类型大小
sizeof(结构体数组名);
5、结构体数组输入输出(for循环)
#include <stdio.h>
struct student
{
char name[32];
int id;
int age;
} stu[3];
int main(int argc, char const *argv[])
{
for (int i = 0; i < 3; i++)
{
scanf("%s %d %d", stu[i].name, &stu[i].id, &stu[i].age);
}
for (int i = 0; i < 3; i++)
{
printf("%s %d %d", stu[i].name, stu[i].id, stu[i].age);
}
return 0;
}
8、结构体指针
1、概念
指向结构体的指针
2、格式
struct 结构体名* 指针变量名
示例:注意数据类型匹配
#include <stdio.h>
struct student
{
int id;
int age;
} stu1, stu2;
struct worker
{
int id;
int age;
} w1, w2;
int main(int argc, char const *argv[])
{
struct student* p = &stu1;
struct student* q = &w1; // 结构体类型不匹配
return 0;
}
3、赋值
格式:结构体指针变量名->成员变量名
(*结构体指针变量名).成员变量
#include <stdio.h>
#include <string.h>
struct student
{
int id;
int age;
} stu1;
int main(int argc, char const *argv[])
{
struct student* p = &stu1;
p -> id = 1;
(*p).age = 18;
return 0;
}
4、结构体指针大小
本质时指针,8字节
总结
1、不能把结构体类型变量作为整体引用,只能对结构体类型变量中的成员变量分别引用
2、如果成员变量本身属于另一个结构体类型,用若干个成员运算符一级一级找到你想要的成员变量
3、可以把成员变量当成普通变量运算
4、在数组中,数组之不能整体的彼此赋值,结构体变量可以整体相互赋值
int a[3] = {};
int b[3] = {1, 2, 3};
a = b; // 错误,数组名不能为左值
a [0] = b[0]; // 正确,单个的元素可以
struct student
{
int id;
int age;
} stu1, stu2;
int main ()
{
stu1.id = 10;
stu1.age = 20;
stu2 = stu1; // 正确,结构体变量可以整体相互赋值
return 0;
}
9、结构体大小
sizeof(struct 结构体名); // 结构体类型大小
#include <stdio.h> struct stu { char a; short b; int y; char w; }; int main(int argc, char const *argv[]) { printf("%d\n", sizeof(struct stu)); return 0; }
结构体大小遵循字节对齐原则
1、字节对齐
在实际使用中,访问特定数据类型变量时需要在特定的内存起始地址进行访问,这就需要各种数据类型按照一定的规则在空间上进行排列,而不是顺序地一个接一个地存放,这就是字节对齐
2、字节对齐原则
a、在64位系统下默认的value值为8字节,判断结构体类型中最大成员变量的字节大小,和默认的value值进行比较,按小的数进行对齐
b、结构体成员进行对齐时遵循地址偏移量是成员类型的整数倍
c、结构体成员按顺序进行存储,如果不满足以上条件时,需要填充空字节
3、为什么要进行字节对齐?
a、平台原因:不是所有的硬件平台都能访问任意地址上的任意数据的;某些硬件平台只能在某些地址处取某些特定类型的数据,否则抛出硬件异常。(提高程序的移植性)
b、性能原因:数据结构(尤其是栈)应该尽可能地在自然边界上对齐。原因在于,为了访问未对齐的内存,处理器需要作两次内存访问;而对齐的内存访问仅需要一次访问。
c、内存原因:在设计结构体时,通过对齐规则尽可能优化结构体的空间大小至最小空间
示例:
struct S
{
int a; // 4
char b; // 1
short c; // 2
double d; // 8
};
第一步:找出成员变量的最大字节数,让其与编译器的默认对齐数进行比较,取较小的值作为该成员变量的对齐数,相等就开8字节
第二步:根据每个成员对应的对齐数画出他们在内存中的相对位置
第一个是int类型的,从第0地址开始偏移,0是4的0倍,第0-3地址给int;第二个是char类型的,从第4字地址开始偏移,4是1的4倍,第4地址给char;第三个是short类型,从第5地址开始偏移,5不是2的倍数,所以给null,然后看第6地址,6是2的倍数,所以第6-7地址给short;第四个是double类型的,从第8地址开始偏移,8是8的1倍,所以第8-15地址给double
最终统计一共以8为对齐数,开两行,0-15一共16个字节
如果最后再多加一个char类型,那就再多开一行,第16地址给char,后面17-23地址全部都是null