函数的形参和实参的特点:形参变量只有在被调用时才分配内存单元,在调用结束时,即刻释放所分配的空间。
实际上,main函数可以带参数,这个参数可以认为是main函数的形参。C语言规定main函数的参数只能有2个,习惯上这两个参数写为argc和argv。arg(译:参数)
C语言还规定argc(第一个形参)必须是整型,argv(第二个形参)必须是指向字符串的指针数组。
void main(int argc, char* argv[])
条件编译
#ifdef 标识符
程序段1
#else
程序段2
#endif
防止头文件被多次引用
#ifndef LED_H
#define LED_H
*
*
#endif
// 或者这样
#pragma once //需要编译器的支持。
**指针(Pointer)其实就是地址,地址就是内存编号。**其一般形式为:*变量名
int* p1; // 表示p1是一个指针变量,它的值是某个整型变量的地址。
char *pc = "C Language"; // 并不是把整个字符串装入指针变量,而是把存放该字符串的字符数组的首地址装入指针变量pc
/*定义一个函数*/
void Function(int *pt){
int a = *pt + 1;
}
// 在调用该函数时,需要传递进去变量的地址,&a
C语言中规定数组代表所在内存位置的首地址.
C语言中没有String这个数据类型,一般用char *表示字符串,或者用char A[]字符数组表示字符串
C语言中操作字符串是通过它在内存中的存储单元的首地址进行的,这是字符串的终极本质。
char *s = "China";
s为一个地址,字符串常量的本质表现是它的第一个字符的地址。char *和char a[]的本质区别
:当定义char a[10]时,编译器会给数组分配10个单元,每个单元的数据类型为字符。而定义char *s时,这是个指针变量,只占4个字节,用来保存一个地址。char *s = "hello";等价于char str[] = "hello"
字符串没有单独的类型,所以,它可以用数组或是指针来表示。
用数组表示:
char str[] = {'b','i','t','\0'};//第一种表示方法
// 第一种写法不常用,注意加结束符 \0
char str[] = "bit";//第二种表示方法,实际其中存储为 b i t \0
char *parray[3]; // 存储3个字符串
用指针表示:
char *str2 = "bit";
前面两个字为修饰词,类型为后面的两个字。优先级:() > [] > *
#include
int main(int argc, char *argv[])
{
const int max = 3;
static array[] = {1, 2, 3};
for (int i = 0; i < max; i++)
{
printf("array[%d] = %d\n",i,array[i]);
}
int *p[max];
for (int i = 0; i < max; i++)
{
p[i] = &array[i];
printf("array[%d] = %p\n",i,&array[i]);
}
return 0;
}
#include
int main(void)
{
int a = 1;
int *p = &a; // 绛変环浜庢崲涓€琛屽啓 p = &a
printf("变量a的地址为: %p\n", p);
printf("变量a的值为: %d\n", a);
printf("变量a的值为: %d\n", *p);
return 0;
}
// ==================指针的运算
static int array[] = {1, 2, 3}; // 这样每次执行时,cpu就不会再重新分配地址了
int i;
int *p = array; // 数组名本身就是一个指针,代表数组元素的首地址
for (i = 0; i < 3; i++)
{
printf("array[%d]= %p\n", i, p + i);
printf("array[%d]= %d\n", i, *(p + i)); // 输出数组的值
}
// 指针的指针
#include
int main(int argc, char *argv[])
{
int a = 1;
int *p1;
int **p2; // 相当于*(*p2)
p1 = &a;
p2 = &p1;
printf("a= %d\n", a);
printf("p1 = %p\n", p1);
printf("p1 = %d\n", *p1); // *表示解引用
printf("p2 = %p\n", p2); // p2 = &p1;
printf("**p2 = %d\n", **p2); // *表示解引用
return 0;
}
// 在调用时,采用&取地址进行变量传递
#include
float average(int *array, int size)
{
float sum = 0;
for (int i = 0; i < size; i++)
{
sum += array[i];
}
float avg = sum / size;
return avg;
}
int main(int argc, char *argv[])
{
int student[] = {10,20,30};
float avg = average(student,3); // 数组的名字就是一个指针
printf("平均值:%f\n",avg);
return 0;
}
#include
#include
int *GetNumber()
{
static int array[10] = {0}; // C语言不支持调用函数时返回局部变量的地址,所以加一个static
int size = sizeof(array) / sizeof(int); // 数组大小的计算
srand(time(NULL)); // 随机种子
for (int i = 0; i < size; i++)
{
array[i] = rand();
printf("%d\n", array[i]);
}
return array; // 数组名就是一个指针地址
}
int main()
{
int *p = GetNumber();
for (int i = 0; i < 10; i++)
{
printf("*(p+[%d]) =%d\n ", i, *(p + i));
}
return 0;
}
结构体(struct)、联合体(union)、枚举(enum)
struct stu *pstu;
(*pstu).num; // 或pstu->num
为了提高程序的运行效率,最好的办法是使用指针,即用指针变量作为函数参数进行传送,这时由实参传向形参的只是地址,从而减少了时间和空间的开销。
示例:结构体赋值
#include
typedef struct
{
int num;
char name[20];
char sex;
int age;
float score;
char address[30];
} Student;
int main()
{
Student stu = {0}; // 结构体实例化
// stu.name = "张三"; 报错,字符串采用下面这种方法进行赋值
strcpy_s(stu.name, "张三"); // _s表示安全类型
stu.age = 1;
stu.sex = 'M'; // 字符类型赋值
return 0;
}
示例:结构体指针的应用(重要)
#include
typedef struct
{
int num;
char name[20];
char sex;
int age;
float score;
char address[30];
} Student;
/*采用指针的方式进行结构体实例化,调用时可以提高程序的运行效率*/
Student *stu;
int main()
{
stu->age = 1;
stu->sex = 'M';
strcpy(stu->name, "张三");
return 0;
}
示例:结构体指针形参
#include
typedef struct
{
int num;
char name[20];
char sex;
int age;
float score;
char address[30];
} Student;
Student stu;
// 如果不用指针,相当于把整个结构体传入过去,使用指针只传递地址就行,大大提升了程序的运行速度
void Print_Student(Student *pt)
{
printf("age = %d\n", pt->age);
printf("name = %s\n", pt->name);
}
int main()
{
stu.age = 1;
strcpy(stu.name, "张三");
Print_Student(&stu);
return 0;
}
结构体与共用体的区别:
枚举只是一种基本的数据类型,不是一种构造函数,枚举值是常量,不是变量,可以让数据简洁和已读。注:第一个枚举成员的值为整型0(也可以把第一个元素定义为1),后面的成员值+1。
定义形式
enum 枚举名{枚举值表};
例如:
enum weekday{sun,mou,tue,wed,thu,fri,sat};
enum weekday a,b,c;
或者为:
enum weekday{sun,mou,tue,wed,thu,fri,sat} a,b,c;
或者为:
enum {sun,mou,tue,wed,thu,fri,sat} a,b,c;
#include
enum DAY{
MON=1, TUE, WED, THU, FRI, SAT, SUN
} day;
int main(){
// 遍历枚举元素
for (day = MON; day <= SUN; day++) {
printf("枚举元素:%d \n", day);
}
}
最常用的内存管理函数是malloc,调用格式:(类型说明符*) malloc(size)
功能:在内存的动态存储区中分配一块长度为 size 字节的联系区域,函数的返回值为该区域的首地址。例如:
pc = (char*)malloc(100);
表示分配100个字节的内存空间,并强制转换为字符数组类型,函数的返回值为指向该字符数组的指针,把该指针赋予指针变量pc
调用形式:free(void *ptr);
功能:释放ptr所指向的一块内存空间,被释放区应是由malloc或calloc函数所分配的区域。
malloc():memory, allocation,内存分配
位域的分配方式分配空间只能用在结构体和类中。
// 进行位域划分,一个int为4个字节,32bit
// 使用方法,在变量名后加一个:即可
struct Date{
int year:12; //分配12个bit
int month:4; // 分配4个字节
int day:5; // ....
int hour:5;
int minute:6;
int second:6;
};
由C/C++编译的程序占用的内存分为以下几个部分:
由编译器自动分配释放
,存放函数的参数值、局部变量的值等由程序员分配释放内存
,若程序员不释放,程序结束时可能由OS回收。注:与数据结构中的堆不同,分配方式类似于链表malloc()函数
:memory allocation,动态内存分配,用于申请一块连续的指定大小的内存,new()也是申请动态内存calloc()函数
:malloc 和 calloc 之间的不同点是,malloc 不会设置内存为零,而 calloc 会设置分配的内存为零。free()函数
:释放内存