C语言高级编程
一.gcc
gcc支持的后缀名解释
编译器的主要主件
gcc的基本用法
最常用的就是gcc 文件名 -o 生成的可执行文件名
-l 链接库,比如我们需要用一下数学运算的时候就需要链接相应的库
gcc常见的错误类型与对策
gcc编译过程
二.gdb调试
gcc -g test.c -o test
使用gdb调式必须在gcc 的时候加上-g
进入调试模式:gdb test
设置断点:b 行号 如:b 20 在代码的20设置断点
查看断点:info b
执行代码:r
一行一行执行代码:n
查看变量的值:p a a是变量名
在main函数中执行到调用的fun函数,如果我们不想进入fun函数就直接n接续往下执行就行,如果想进入fun函数就输入 s 进入fun函数执行
循环完代码q退出gdb
c是自动运行代码
三.条件编译
#ifdef xxx 如果定义了xxx就执行下面代码
#ifndef xxx 如果没有定义xxx就执行下面代码
下面这个常用于防止头文件被重复包含
#ifndef xxxx
#define xxxx
#endif
四.结构体
struct student
{int num;char name[10];float core;
};
int mian()
{struct student stu1;
}
这里要讲的是name的赋值
这个是不可以直接stu1.name="zhangshan";的
如果想要直接赋值需要在定义的时候赋值如下
struct student stu1={2,"zhangshan",90};
不这样子还可以如下
strcpy(stu1.name,"zhangshan");
还可以如下
struct student
{int num;char name[10];float core;
}stu1={1,"zhangshan",90},stu2={2,"lisi",90};
使用这种方式的时候我们结构体名字student可以省略,但是不建议
字节对齐
我们使用sizeof(struct student)计算结构体的大小时得出的是20
怎么来?
struct student
{
int num; //四字节
char name[10];//十字节
float core;//四字节
};
这里也就18,为什么得出20?
这里就涉及字节对齐,每四个字节对齐,不够的进行补零
struct student
{
int num; //****
char name[10]; //**** **** **00 补够四个字节
float core; //****
};
所有得出了20字节的大小
五.结构体数组
先定义一个结构体
struct student
{int num;char name[10];float core;
};
struct student stu[4];//结构体数组
stu[0].num=10;
strcpy(stu[0].name,"zhangshan");stu[1].num=10;
strcpy(stu[1].name,"zhangshan");也可以
struct student stu[4]={{1,"zhanghan",90},{2,"lisi",68}};
还可以
struct student
{int num;char name[10];float core;
}stu[4]={{1,"zhanghan",90},{2,"lisi",68}};
六.结构体指针
struct student
{int num;char name[10];float core;
};int main()
{struct sdudent *p;struct student stu1={1,"zhagnshan",90};p=&stu1;printf("%d %s %.2f\n",(*P).num,(*p).name,(*p).core);printf("%d %s %.2f\n",P->num,p->name,p->core);return 0;
}
*p是取地址内的内容,就是取{1,"zhagnshan",90};
易错点,指针没有分配内存导致段错误
下面代码我们定义了一个结构体指针,但是没有分配内存就去通过指针访问内存导致段错误
#include<stdio.h>
#include "string.h"struct student
{int num;char name[10];float core;
};int main(int argc,const char *argv[])
{struct student *p;p->num=10;p->core=20;strcpy(p->name,"zahgnshan");printf("%d %s %.2f\n",(*p).num,(*p).name,(*p).core);printf("%d %s %.2f\n",p->num,p->name,p->core);return 0;
}
~
正确的应该如下
1.在栈上分配内存
#include <stdio.h>
#include <string.h>struct student
{int num;char name[10];float core;
};int main(int argc, const char *argv[])
{struct student stu1; // 在栈上分配内存struct student *p = &stu1; // 让p指向stu1p->num = 10;p->core = 20;strcpy(p->name, "zhangshan"); printf("%d %s %.2f\n", (*p).num, (*p).name, (*p).core);printf("%d %s %.2f\n", p->num, p->name, p->core);return 0;
}
2.在推上分配内存
#include <stdio.h>
#include <string.h>
#include <stdlib.h> // 包含malloc和free的头文件struct student
{int num;char name[10];float core;
};int main(int argc, const char *argv[])
{struct student *p = (struct student *)malloc(sizeof(struct student));if (p == NULL) { // 检查内存分配是否成功fprintf(stderr, "内存分配失败\n");return 1;}p->num = 10;p->core = 20;strcpy(p->name, "zhangshan"); printf("%d %s %.2f\n", (*p).num, (*p).name, (*p).core);printf("%d %s %.2f\n", p->num, p->name, p->core);free(p); // 释放分配的内存return 0;
}
七.共用体
从下面代码我们可以看到,我没有给b赋值,但是它也是有内容的,这就是共用体
而且你改变一个的内容,另一个内容也会改变
八.typedef
struct student
{int num;char name[10];float core;
};int main()
{typedef struct student STU;//将struct student 重新命名为STUSTU stu1;//等同于 struct student stu1;stu1.num=1;return 0;
}还可以直接这样子重命名
typedef struct student
{int num;char name[10];float core;
}STU,*STU_P;int main()
{STU *p;//STU_P p;这两个是一样的效果 return 0;
}
九.内存管理
动态存储分配
堆内存的分配与释放
char *p =NULL;
p=(char *)malloc(10);
free(p);
//此时如果p成为了野指针
p =NULL;//让p指向NULL;此时p没有分配内存,我们不可以在对p进行访问内存的操作