学习来源 b站--作者:小甲鱼--【C语言】C语言视频教程(孤独自学 - up主)
变量的存储类别
包括自动变量(auto)、静态变量(static)、外部变量(extern)、寄存器变量(register)。
预处理命令
凡是以“#”开头的均为预处理命令。宏定义
无参宏定义
一般形式:#define 标识符 字符串
注:
1.define 为宏定义命令。“标识符”为所定义的宏名。“字符串”可以是常数、表达式、格式串等。
2.宏定义不是说明或语句,在行末不必加分号,如加上分号则连分号也一起置换。
3.宏定义必须写在函数之外,其作用域为宏定义命令起到源程序结束。如要终止其作用域可使用# undef命令。
4.可用宏定义表示数据类型,使书写方便。与typedef的区别:宏定义只是简单的字符串代换,是在预处理完成的,而typedef是在编译时处理的,它不是作简单的代换,而是对类型说明符重新命名。被命名的标识符具有类型定义说明的功能。
5.对“输出格式”也可以作宏定义,可以减少书写麻烦。
带参宏定义
一般形式为:宏名(实参表) 字符串
注:
1.带参宏定义中,宏名和形参表之间不能有空格出现,若出现空格则会被认为是无参宏定义,就会出错。
2在宏定义中的形参是标识符,而宏调用中的实参可以是表达式。
3.在宏定义中,字符串内的形参通常要用括号括起来以避免出错。
文件包含
包含命令中的文件名可以用双引号括起来,也可以用尖括号括起来。
#include"stdio.h"
#include<math.h>
区别:使用尖括号表示在包含文件目录中去查找(包含目录是由用户在设置环境时设置的),而不在源文件目录去查找;使用双引号则表示首先在当前的源文件目录中查找,若未找到才到包含目录中去查找。用户编程时可根据自己文件所在的目录来选择某一种命令形式。
指针
取值操作符:* ;取址操作符:&。“&”和“*”两个运算符的优先级别相同,但按自右而左方向结合
一般形式:类型说明符 *变量名;
知道了一个变量的地址,就可以通过这个地址来访问这个变量,因此,又把变量的地址称为该变量的“指针”
C语言中可以定义一类特殊的变量,这些变量专门用来存放变量的地址,称为指针变量。注:只有整型变量的地址才能放到指向整型变量的指针变量中。
指针变量中只能存放地址(指针),不要将一个整数(或任何其他非地址类型的数据)赋给一个指针变量,否则编译器也会把该值当成一个地址来处理。
练习:
#include <stdio.h>
void main()
{
int a, b;
int *pointer_1, *pointer_2;
a = 100;
b = 10;
pointer_1 = &a;
pointer_2 = &b;
printf("%d,%d\n", a, b);
printf("%d,%d\n", *pointer_1, *pointer_2);
}
结果:,在这里就可以看到*pointer_1和*pointer_2可以输出a,b的值。
题目:pointer_1 = &a
&* pointer_1的含义是什么?
&*pointer_1 == &a(“&”和“*”两个运算符的优先级别相同,但按自右而左方向结合,因此先进行* pointer_1的运算,它就是变量a,再执行&运算。)
*&a的含义是什么?
*&a == a;(先进行&a运算,得a的地址,再进行*运算。即&a所指向的变量,也就是变量a。)
(*pointer_1)++相当于a++
不能去掉括号。因为由于++在pointer_1的右侧,是“后加”,因此先对pointer_1的原值进行*运算,得到a的值,然后使pointer_1的值改变,这样pointer_1不再指向a了。
题目:输入a和b两个整数,按先大后小的顺序输出a和b。
#include <stdio.h>
void main()
{
int *p1, *p2, *p, a, b;
scanf("%d %d", &a, &b);
p1 = &a;
p2 = &b;
if( a < b)
{
p = p1;
p1 = p2;
p2 = p;
}
printf("a = %d, b = %d\n", a, b);
printf("max = %d, min = %d\n", *p1, *p2);
}
输入:2 6
结果:
题目:对输入的两个整数按大小顺序输出!这次用函数实现交换功能!
#include <stdio.h>
void swap(int *p1, int *p2);
void main()
{
int a, b;
int *pointer_1, *pointer_2;
scanf("%d %d", &a, &b);
pointer_1 = &a;
pointer_2 = &b;
if(a < b)
{
swap(pointer_1, pointer_2);
}
printf("\n%d > %d\n", a, b);
}
void swap(int *p1, int *p2)
{
int temp;
temp = *p1; //temp = a;
*p1 = *p2; //a = b;
*p2 = temp; //b = temp;
}
输入:3 5
结果:,在这里改变了a和b的地址里面的值,让a拥有最大的值,让b
拥有最小的值。
题目:输入a、b、c 3个整数,按大小顺序输出
#include <stdio.h>
void main()
{
void exchange(int *q1, int *q2, int *q3);
int a, b, c, *p1, *p2, *p3;
scanf("%d %d %d", &a, &b, &c);
p1 = &a;
p2 = &b;
p3 = &c;
exchange(p1, p2, p3);
printf("%d %d %d\n", a, b, c);
}
void exchange(int *q1, int *q2, int *q3) //int *q1 = p1;
{
void swap(int *pt1, int *pt2);
if( *q1 < *q2 )
{
swap(q1, q2);
}
if( *q1 < *q3 )
{
swap(q1, q3);
}
if( *q2 < *q3 )
{
swap(q2, q3);
}
}
void swap(int *pt1, int *pt2)
{
int temp;
temp = *pt1;
*pt1 = *pt2;
*pt2 = temp;
}
输入:5 9 6
结果:
通过指针引用数组元素
引用一个数组元素,可以使用两种方法:(1)下标法,如a[i];(2)指针法,如*(a+i)。
题目:假设有一个a数组,整型,有10个元素。
void main()
{
int *p, i, a[10];
p = a;
for( i=0; i < 10; i++ )
{
scanf("%d", p++);
}
p = p-10;
printf("\n");
for( i=0; i < 10; i++, p++ )
{
printf("%d ", *p);
}
}
输入:5 1 2 3 4 5 6 7 8 9
结果:
函数参数
f (int arr[ ], int n) 等价于f (int *arr, int n)
题目:将数组a中n个整数按相反顺序存放
解法1,用数组名做参数
#include <stdio.h>
void reverse(int x[],int n);
void main()
{
int i, a[10] = {3, 7, 9, 11, 0, 6, 7, 5, 4, 2};
printf("start:\n");
for( i=0; i < 10; i++)
{
printf("%d ", a[i]);
}
printf("\n");
reverse(a, 10);
printf("end:\n");
for( i=0; i < 10; i++)
{
printf("%d ", a[i]);
}
printf("\n");
}
void reverse(int x[], int n)
{
int temp, i, j, m;
m = (n-1)/2;
for( i=0; i <= m; i++)
{
j = n-1-i;
temp = x[i];
x[i] = x[j];
x[j] = temp;
}
}
结果:
解法2,利用指针做参数
#include <stdio.h>
void reserve(int *x, int n);
void main()
{
int i, a[10] = {3, 7, 9, 11, 0, 6, 7, 5, 4, 2};
printf("start:\n");
for( i=0; i < 10; i++)
{
printf("%d ", a[i]);
}
printf("\n");
reserve(a, 10);
printf("end:\n");
for( i=0; i < 10; i++)
{
printf("%d ", a[i]);
}
printf("\n");
}
void reserve(int *x, int n)
{
int *p, temp, *i, *j, m;
m = (n-1)/2;
i = x;
j = x-1+n;
p = x+m;
for( ; i <= p; i++, j--)
{
temp = *i;
*i = *j;
*j = temp;
}
}
结果:
今日总结:指针的知识确实很多也比较重要,明天可能还要继续复习指针内容,冲冲冲!