由于打算捡起嵌入式,从c语言基础开始进行学习。
1. C中的类型转换
原则:占用内存少的类型自动向多的类型转换,有符号自动向无符号转换。
printf("%d\n", 5 / 2);
printf("%lf\n", 5.0 / 2);
int a1 = -8; unsigned int b1 = 7;
if (a1 + b1 > 0) { printf("a1 + b1 > 0 \n"); }
double a2 = 4.2; float b2 = 5.8f;
printf("%d\n", int(a2 + b2));
2. 原/反/补码
正数:原码=反码=补码。 负数:反码等于原码除符号位外,每一位进行取反;补码等于反码+1.
3. 变量
普通全局变量:作用范围项目中所有程序。 静态全局变量:作用范围为所在的.c文件。
普通局部变量:生命周期为所在的复合语句或函数开始调用到结束。 静态局部变量:生命周期为所在的复合语句或函数第一次调用开始,之后不进行释放。
4. C语言编译过程
1.预编译:将.c的头文件和宏展开,生成.i文件。 2.编译:将.i文件生成.s汇编文件。 3.汇编:将.s文件生成.o目标文件。 4.链接:将多个.o文件链接成目标文件-可执行程序。
5. 带参宏
#define S(a,b) a*b
int main()
{
int num;
num = S((3 + 5), 4);
printf("%d\n", num);
return 0;
}
6. 指针
野指针:指向非法内存空间的指针。
int* p = (int *)0x1100;
cout << *p << endl;
system("pause");
常量指针-const在前:指针的指向可以修改,但是指向的值不可以更改。 指针常量-const在后:指针的指向不可以修改,指向的值可以改。 常量指针常量–如const int * const p:都不可以改。 普通指针操作:
int a = 100, b = 200;
int* p1, * p2 = &b;
p1 = &a;
printf("%d\n", *p1);
printf("%d\n", sizeof(p1));
printf("%d\n", *p2);
int a[5] = {0, 0, 0, 0, 0};
int* p;
p = a;
p[2] = 100;
*(p + 1) = 100;
*(a + 3) = 100;
for (int i = 0; i < 5; i++) {
printf("%d\n", p[i]);
}
int a[5] = {0, 0, 0, 0, 0};
int* p = &a[0], * q = &a[2];
printf("%d\n", q - p);
q = p;
void fun(const char** q, int x)
{
for (int i = 0; i < x; i++) {
printf("q[%d]=%s\n", i, q[i]);
}
}
int main()
{
const char* p[3] = { "hello", "world", "kitti" };
fun(p, 3);
return 0;
}
int (*p)[5];
int a[10];
a; a + 1;
&a;
int a = 0x12345678;
int* p;
int** q;
int*** m;
p = &a;
q = &p;
m = &q;
printf("&a = %p ; p = % p\n", &a, p);
printf("&p = %p ; q = % p\n", &p, q);
printf("&q = %p ; m = % p\n", &q, m);
char* fun() {
static char str[] = { "hello world" };
return str;
}
int main() {
char* p;
p = fun();
printf("p=%s\n", p);
return 0;
}
int(*p)(int, int);
int max(int x, int y);
p=max;
int add(int x, int y) {
return x + y;
}
int process(int(*p)(int, int), int x, int y) {
int ans;
ans = (*p)(x, y);
return ans;
}
int main()
{
int num;
num = process(add, 10, 20);
printf("%d\n", num);
return 0;
}
7. 字符串
7.1 字符串的可修改性
1.数组(无const修饰)中的字符串,可以修改。 2.文字常量区的字符串,不可修改:
char* str = (char*)"12345";
printf("%s\n", str);
*str = 'y';
printf("%s\n", str);
3.堆区的字符串可以修改
#pragma warning(disable:4996)
int main()
{
char* str;
str = (char*)malloc(20);
strcpy_s(str, 20, "I LOVE C#");
printf("str=%s\n", str);
return 0;
}
7.2 字符串处理函数
int main()
{
char a[] = { "sssssssssssss" };
char b[] = { "world" };
strcpy_s(a, strlen(b) + 1, b);
strncpy_s(a, b, 2);
printf("%s\n", a);
printf("%d\n", strcmp(a, b));
char a[20] = { "ssss\0sssssssss" };
strcat_s(a, strlen(a)+strlen("world")+1, "world");
strncat_s(a, "world", 2);
char b[] = { "world" };
char* str = b;
char* p = strchr(str, 'w');
char* p = strrchr(str, 'w');
if (p == NULL) {
printf("Not found\n");
return 0;
}
printf("p-str=%d\n", p - str);
char c[] = { "rl" };
char* p = strstr(b, c);
if (p == NULL) {
printf("Not found\n");
return 0;
}
printf("p-b=%d\n", p-b);
char b[] = { "123" };
printf("b=%d\n", atoi(b));
char a[] = { "aabaaabaaabababaaab" };
char* ans = NULL;
char* buf = NULL;
ans = strtok_s(a, "b", &buf);
while (ans != NULL) {
printf("切下:%s\n", ans);
printf("剩余待切割:%s\n", buf);
ans = strtok_s(NULL, "b", &buf);
}
char a[2];
sprintf_s(a, sizeof(a), "%d,%d,%d", 2022, 10, 12);
printf("a=%s\n", a);
return 0;
}
8. 动态内存分配
8.1 动态申请内存:
int main()
{
int* p;
int i, n;
printf("请输入您要申请的int数组的元素个数\n");
scanf_s("%d", &n, 4);
p = (int*)malloc(n * 4);
if (p == NULL) {
printf("malloc err\n");
return 0;
}
for (i = 0; i < n; i++) {
p[i] = i;
printf("p[%d]=%d\n", i, p[i]);
}
free(p);
return 0;
}
p = (int*)calloc(n, 4);
char *p;
p = (char *)malloc(100);
p = (char *)realloc(p, 150);
8.2 内存泄漏:
概念:申请的内存首地址丢失,既不能访问,也无法释放,就是内存泄漏。 案例一:
char* p;
p = (char*)malloc(50);
p = (char *)"hello";
案例二:
void fun() {
char* p;
p = (char*)malloc(50);
}
int main() {
fun();
return 0;
}
char* fun(){
char* p;
p = (char*)malloc(50);
return p;
}
int main() {
char* q;
q = fun();
free(q);
return 0;
}
8.3 空间设定函数memset:
void* memset(void *prt, int value, size_t num) 功能:将ptr指向的内存空间的num个字节全部赋值位value参数。
char b[] = { "hello world" };
memset(b, '\0', 1);
printf("b=%s\n", b);
9. 结构体
9.1 结构体定义,声明和成员调用:
typedef struct date {
int month;
int day;
}Birthday;
struct stu {
int age;
char name[10];
char sex;
Birthday birthday;
};
int main() {
Birthday Bob_birthday = { 2, 14 };
stu Bob={12, "Bob", '男', Bob_birthday};
strcpy_s(Bob.name, 10, "bob");
cout << "名字:" << Bob.name + "\n";
cout << "生日:" << Bob.birthday.month << "." << Bob.birthday.day;
stu edu[3];
return 0;
}
9.2 结构体指针:
结构体定义同上。
void printf1(stu x) {
x.age = 99;
cout << x.age << x.name << x.sex << x.birthday.month <<endl;
}
void printf2(const stu* x) {
cout << (*x).age << (*x).name << (*x).sex << (*x).birthday.month << endl;
}
int main()
{
Birthday Bob_birthday = { 2, 14 };
stu Bob={12, "Bob", "f", Bob_birthday};
stu* p = &Bob;
printf1(Bob);
printf2(&Bob);
cout << (*p).name << p->name;
return 0;
}
9.3 共用体:
结构体的每个成员都有自己的内存空间,共用体则是所有成员公用一段内存空间,具有同样的地址,其空间大小由占据内存长度最大的成员大小决定。 共用体起作用的成员是最后一次存放的成员,会覆盖上一个成员的值。
typedef union date {
int month;
int day;
}Birthday;
union date a = {12};
10. 枚举
enum week {
一 = 1, 二, 三, 四, 五, 六, 日
};
int main()
{
week workday;
workday = 日;
cout << workday << endl;
return 0;
}
11. 文件
11.1 文件指针及顺序读写
在程序中代表一个文件,对文件的操作转化为对文件指针的操作。 顺序读写指的是从头开始读写文件,顺序读写各个数据。
int main() {
FILE* fp;
fp = fopen("a.txt", "r");
if (fp == NULL) { cout << "打开失败" << endl; }
int fl = fclose(fp);
if (fl == 0) { cout << "关闭成功" << endl; }
FILE* fp, *fp_read, *fp_write;
char str[100];
fp_read = fopen("a.txt", "r");
if (fp_read == NULL) { cout << "打开失败" << endl; }
fp_write = fopen("b.txt", "w");
if (fp_write == NULL) { cout << "打开失败" << endl; }
fgets(str, 6, fp_read);
printf("str=%s\n", str);
fputs(str, fp_write);
return 0;
}
struct stu {
char name[10];
int num;
int age;
}boya[2], boyb[2];
int main()
{
FILE* fp;
fp = fopen("a.txt", "wb+");
if (fp == NULL) { cout << "打开失败" << endl; }
for (int i = 0; i < 2; i++) {
cout << "请输入第" << i << "结构体的参数" << endl;
scanf("%s %d %d", boya[i].name, &boya[i].num, &boya[i].age);
}
fwrite(boya, sizeof(stu), 2, fp);
rewind(fp);
fread(boyb, sizeof(stu), 2, fp);
for (int i = 0; i < 2; i++) {
cout << boyb[i].name
<< boyb[i].num
<< boyb[i].age << endl;
}
fclose(fp);
return 0;
}
11.2 随机读写
只想读取文件的某一部分,所以要去移动光标到位置再进行读写,这种读写称为随机读写。
int len = ftell(fp);
fseek(fp, 10, SEEK_CUR);
|