1.字符串定义

1
2
3
4
5
// 定义字符串
char *str = "JACKOU";
// 注意这样定义字符串最后一定需要加'\0',否者系统会默认加入系统字符。
// 不加'\0'如下字符串长度为9,加了为6
char string[] = {'J', 'A', 'C', 'K', 'O', 'U','\0'};
1
2
3
4
5
6
7
8
9
10
11
int mainT2() {
char str[] = {'D', 'e', 'r', 'r', 'y', '\0'}; //"derry"保存在堆空间中
str[2] = 'z'; // 这里能修改? str把derry拷贝到栈空间,修改的栈空间可以
printf("第一种方式:%s\n", str); // printf 必须遇到 \0 才结束

char * str2 = "Derry"; // 隐士 Derry+\0 默认+\0
str2[2] = 'z'; // 会奔溃,为什么,不允许访问,修改的堆空间,所以报错
printf("第二种方式:%s\n", str);

return 0;
}

2.计算字符串长度

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
// 方式一
int getLen(char *string) {
int count = 0;
// 这种写法相当于: *string != '\0'
while (*string) {
string++;
count++;
}
return count;
}

// 方式二不能用作参数传递
int intArr[] = {1, 2, 3, 4, 5, 6, 7, 8, '\0'};
int len = sizeof(intArr) / sizeof(int);

// 说明,第二种方式不是完美的,有毛病,C/C++编译器,数组作为参数传递的时候,会把数组优化成指针
// 此时的len结果为:1
void getLen(int intArr[]) {
int len = sizeof(intArr) / sizeof(int);
}

// 方式三 #include<string.h>
int len = (int) strlen(string);
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
// C/C++编译器 数组作为参数传递,会把数组优化成指针(为了高效率)
void getLen(int * resultLen, int intarr[]) { // 模仿了 strLen函数

// 数组作为参数传递 就不能这样写了,这样写结果会为1,因为地址占用1个字节。
// sizeof(intarr)28 / sizeof(int)4 = 7
/*int len = sizeof(intarr) / sizeof(int);
printf("getLen len长度是:%d\n", len);*/

// 手动计算长度
int count = 0;
while (*intarr != '\0') {
intarr++;
count++;
}
*resultLen = count;
}

int mainT3() {
// int 4 char 1

// char string[] = {'A', 'B', 'C', 'D', '0', '\0'}; // printf方法能够停下来,不要打印系统值

int intarr[] = {1,2,3, 0,5,6,7}; // 0 \0 其他函数 for 其他调用判断的时候,这个有冲突 【int类型数组】

// int类型使用这种方式【第一种方式】
// sizeof(intarr)28 / sizeof(int)4 = 7
int len = sizeof(intarr) / sizeof(int);
printf("len长度是:%d\n", len);

int result; // &取出result遍历的地址给函数
getLen(&result, intarr);
printf("getLen len长度是:%d\n", result);

return 0;
}

3.字符串转换

1
2
3
4
5
6
7
8
9
10
11
// 字符串转int
atoi(num);

// 字符串转double
atof();

// 字符串转long
atol();

// 字符串转long long
atoll();

4.字符串比较

1
2
3
4
5
6
char *str1 = "jackou1";
char *str2 = "jackou";

result = strcmp(str1, str2);
// strcmp相等返回0 strcmp区分大小写
// strcmpi 不区分大小写

5. 字符串查找

1
2
3
4
5
6
7
8
char *str1 = "jackou1";
char *str2 = "k";
int *p = strstr(str1,str2);
// 返回结果:kou1
// str是源字符串,str2是目标字符串,返回从目标字符串开始的以后字符串

// 求位置
int index = p - str1;
1
2
3
4
5
void subString(char *result, char *str, int start, int end) {
for (int i = start; i < end; i++) {
*(result++) = *(str + i);
}
}

6.结构体

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
#include <stdio.h>

struct Dog {
char name[10];
int age;
char sex;
};

// 嵌套结构体
struct Study {
char *content;
};
struct Student {
char name[10];
int age;
char sex;

struct Study study;

struct Wan {
char *content;
} wan;
};

int main() {
struct Dog dog;
// 不赋值为系统值
printf("dog: name=%s, age=%d, sex=%d \n", dog.name, dog.age, dog.sex);
return 0;
}

7.结构体指针

1
2
3
4
5
6
7
8
9
10
11
12
struct Cat {
char *name;
int age;
};

int main() {
struct Cat cat = {"cat", 5};
struct Cat *catP = &cat;
printf("name=%s,age=%d \n", catP->name, catP->age);

return 0;
}

8.正确的方法结果接收写法

1
2
3
4
5
6
7
8
9
10
int main(){
char *result = "abc"; //赋过值的指针不能用于接收结果,因为result已经指向静态常量区的“abc”了
char *result1 = NULL; //原因同上,已经指向NULL了

char *result2 = "";
action(result2);

char result3[100] = "abc"; // 不会报错因为数组元素是在栈区分配空间
action(result3);
}

9. typedef

为了兼容方法内部的内容不做改变,使用typedef来定义结构体

1
2
3
4
5
6
7
8
9
10
typedef struct Dog{
char name[10];
int age;
} Dog;

// 匿名结构体
typedef struct {
char name[10];
int age;
} Person;

10.字符串拼接

1
2
3
4
5
6
7
char dest[25];
char* blank = "--到--";
char* cpp = "cpp";
char* java = "java";
strcpy(dest, cpp); // 拷贝
strcat(dest,blank); // 拼接
strcat(dest,blank);

11.字符串转化

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
#include <stdio.h>
#include <ctype.h>

// 指针的理解
void lower(char * dest, char * name) {
char * temp = name; // 临时指针,你只能操作,临时指针,不能破坏name指针
while (*temp) {
*dest = tolower(*temp);
temp ++; // 挪动指针位置 ++
dest ++; // 挪动指针位置 ++ 目的是为了 挪动一个存储一个 挪动一个存储一个 ...
}
// printf '\0'
*dest = '\0'; // 避免printf打印系统值

printf("不能破坏 name:%s\n", name); // temp的好处就是,不会破坏name
}

// 全部变成小写 derry
int mainT6() {
char * name = "DerrY";

// 先定义结果
char dest[20];
lower(dest, name);
printf("小写转换后的结构是:%s\n", dest);

/*char * str = "Derry is";
char * result;
函数(&result, str, 2, 5);
printf("%s\n", result); // 最终输出:rry*/

// 这样-不成功
/*char * a = "ABCDEFG";
char * b = "AB";
int r = b - a;
printf("r:%d\n", r);*/

return 0;
}

12.结构体定义与使用

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <malloc.h>

struct Dog {
// 成员
char name[10]; // copy进去
int age;
char sex;

}; // 必须给写;

int main() {
struct Dog dog; // 这样写完,成员是没有任何初始化的,成员默认值 是系统值(name:?@, age:3133440, sex:)
printf("name:%s, age:%d, sex:%c \n", dog.name, dog.age, dog.sex);

// 赋值操作
// dog.name = "旺财";
// 如果是数组,就必须copy进去,如果是指针可以直接赋值。
strcpy(dog.name, "旺财");
dog.age = 3;
dog.sex = 'G';
printf("name:%s, age:%d, sex:%c \n", dog.name, dog.age, dog.sex);

return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
struct Person {
// 成员
char * name; // 字符指针 = "赋值"
int age;
char sex;
} ppp = {"Derry", 33, 'M'},
ppp2,
ppp3,
pppp4,
pppp5
// ...
;
int main() {

// Person == ppp == struct Person ppp;
printf("name:%s, age:%d, sex:%c \n", ppp.name, ppp.age, ppp.sex);

// 赋值
// strcpy(pppp5.name, "JackOu5"); // Copy不进去
pppp5.name = "DerryO";
pppp5.age = 4;
pppp5.sex = 'M';
printf("name:%s, age:%d, sex:%c \n", pppp5.name, pppp5.age, pppp5.sex);
return 0;
}

13.结构体指针与动态开辟空间

如果是结构体指针,使用->来引用,如果是结构体,使用.来引用。

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
#include <stdio.h>
#include <string.h>

struct Cat {
char name[10];
int age;
};

int main() { // 栈

// 结构体
struct Cat cat = {"小花猫", 2};

// 结构体 指针 -> 调用一级指针成员
// VS的写法:Cat * catp = &cat;
struct Cat * catp = &cat;
catp->age = 3;
strcpy(catp->name, "小花猫2");
printf("name:%s, age:%d \n", catp->name, catp->age);

return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
#include <stdio.h>
#include <string.h>
#include <stdlib.h>

struct Cat2 {
char name[10];
int age;
};

int main() { // 堆

// VS的写法:Cat2 * cat = (Cat2 *) malloc(sizeof(Cat2));
struct Cat2 *cat = malloc(sizeof(struct Cat2));

strcpy(cat->name, "金色猫");
cat->age = 5;

printf("name:%s, age:%d \n", cat->name, cat->age);

// 堆区的必须释放
free(cat);
cat = NULL;

return 0;
}

14.结构体数组

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
53
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

struct Cat3 {
char name[10];
int age;
};

int main() {

// 栈区 静态范畴
struct Cat3 cat [10] = {
{"小黄", 1},
{"小白", 2},
{"小黑", 3},
{},
{},
{},
{},
{},
{},
{},
};

// VS的写法
// cat[9] = {"小黑9", 9},

// ClION的写法
struct Cat3 cat9 = {"小黑9", 9};
// cat[9] = cat9;
*(cat + 9) = cat9;
printf("name:%s, age:%d \n", cat9.name, cat9.age);

// 堆区 动态范畴 ==============================
struct Cat3 * cat2 = malloc(sizeof(struct Cat3) * 10);

// 【1元素地址的操作】给他赋值,请问是赋值,那个元素 (默认指向首元素地址)
strcpy(cat2->name, "小花猫000");
cat2->age = 9;
printf("name:%s, age:%d \n", cat2->name, cat2->age);

// 【8元素地址的操作】 给第八个元素赋值
cat2 += 7;
strcpy(cat2->name, "小花猫888");
cat2->age = 88;
printf("name:%s, age:%d \n", cat2->name, cat2->age);

free(cat2);
cat2 = NULL;

return 0;
}

15.结构体与结构体指针取别名

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
#include <stdio.h>
#include <stdlib.h>

struct Workder_ {
char name[10];
int age;
char sex;
};

// VS的写法:typedef Workder_
typedef struct Workder_ Workder_; // 给结构体取别名

typedef Workder_ * Workder; // 给结构体指针取别名

// C库的源码,系统源码...,为什么 typedef 还取一个和结构体一样的名字(兼容代码的写法,保持一致)
int main() {
// 以前 Clion工具 必须加上 struct VS又不用加 代码差异化大
// struct Workder_ workder1 = malloc(sizeof(struct Workder_));

// 现在 (兼容代码的写法,保持一致)
Workder_ workder1 = malloc(sizeof(Workder_));

// VS CLion 他们都是一样的写法
Workder workder = malloc(sizeof(Workder_));

return 0;
}
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
25
26
27
28
29
30
31
32
33
34
35
36
37
38
39
40
41
42
43
44
45
46
47
48
49
50
51
52
#include <stdio.h>
#include <stdlib.h>

struct DAO {
char name[10];
int age;
char sex;
};

// 匿名结构体的别名(这样写意义不大,因为没有名字)
typedef struct {
char name[10];
int age;
char sex;
};

// 源码是这样写的
// 给结构体AV 取了一个别名等于AV
typedef struct {
char name[10];
int age;
char sex;
} AV;

// 取一个别名
typedef struct DAO DAO;

void show(DAO dao) {} // 在不同工具上 有的要加,有的不用加 又差异化

int main() {
// VS 不需要这样写, Clion工具 要加入关键字 代码不统一
// struct DAO * dao = malloc( sizeof(struct DAO));

// 加别名后 代码的统一了

// VS
DAO * dao = malloc( sizeof(DAO));

// CLion工具也这样写
DAO * dao1 = malloc( sizeof(DAO));

// xxx 工具也这样写
DAO * dao2 = malloc( sizeof(DAO));

// 加别名后 代码的统一了
// C库的源码,系统源码...,为什么 typedef 还取一个和结构体一样的名字(兼容代码的写法,保持一致)
AV av = {"VideoInfo", 54, 'M'}; // 结构体 VS Clion xxx工具 兼容写法

AV * avp = malloc(sizeof(AV)); // 结构体指针

return 0;
}

16.枚举

1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22
23
24
#include <stdio.h>

// 枚举 int 类型的
enum CommentType {
TEXT = 10,
TEXT_IMAGE,
IMAGE
};

typedef enum CommentType CommentType;

int main() {
// Clion工具的写法如下:
enum CommentType commentType = TEXT;
enum CommentType commentType1 = TEXT_IMAGE;
enum CommentType commentType2 = IMAGE;

// VS工具的写法如下:
// CommentType commentType = TEXT;

printf("%d, %d, %d \n", commentType, commentType1, commentType2);

return 0;
}