12.3
1. VIM 新建.c后缀名文件
强制退出后, 按D解决
2. 标示符 变量名、函数名、类型名···
只能是 数字+字母+下划线,首字母不能是数字
C语言定义标示符的规范:尽量让它有含义,多个单词用_连接
//%d 按照十进制的格式输出
//%o 按照八进制的格式输出
//%x 按照十六进制的格式输出 //%X 大写
//%ld 长整形十进制
//%u 无符号
//%lu 无符号长整形
//%lld 长长整形
//%llu 无符号长长整形
3. 常量:不可变的量
123 十进制常量
0123 八进制常量
0x123十六进制常量
123L十进制长整形
123UL 十进制无符号长整形
123U 十进制无符号
‘a’ 字符常量 ‘\n’ ‘\t’
“abc” 字符串常量
变量:值可变的量
sizeof()运算符 计算占用的字节数
字节:8位二进制 0~255 有符号:-128~127
int 4字节
short 短整型 2字节
long 8字节 longlong 8字节
浮点类型(实型) float(4) double(8)
ANSI C99标准 :short为2字节
long 为4字节 int为机器字长
64位 机器 int 为8字节
4.运算符:
算数:+ - * / %(只支持整形)
关系:> < >= <= == !=
逻辑: && || !
0为假 1为真
expr1&&expr2
同为真时才为真,一个为假就是假
如果expr1为真,则判断expr2,如果为真则为真,否则为假
如果expr1为假,则直接返回假
exper1||expr2
同位假时才为假,一个为真就是真
如果expr1为假,则判断expr2,如果为真则为真,否则为假
如果expr1为真,则直接返回真
闰年
if((year%4==0&&year%100!=0)||year%400==0)
优先级一样的从左到右
a++ a=a+1 a++// a先参与运算再自加
++a// a先自加再参与运算
a-- a=a-1
赋值运算符:= += -= *= /= %=
a=b;
a+=b; ==> a=a+b;
逗号运算符:用于将若干个表达式组合成一个表达式。
逗号表达式:
形式: 表达式1,表达式2,表达式3,
要领:
1)逗号表达式的运算过程为为:从左往右逐个计算表达式
2)逗号表达式作为一个整体,他的值为最后一个表达式(也即表达式n)的值。
3)逗号表达式的优先级别在所有运算符中最低。
EQ1:int main(){
int a=1,b=2,c=3;
int d;
d=(++a,b+a,c++);
printf(“%d,%d,%d\n”,a,b,d);
}
结果:2,4,4,3
EQ2:int main(){
int a=1,b=2,c=3;
int d;
d=++a,b+a,c++;
printf(“%d,%d,%d\n”,a,b,d);
}
结果:2,4,4,2
用于连接多个表达式,整个表达式的值为最后一个表达式的值
逗号表达式的优先级最低
条件运算符
a> b?a:b
单目、三目运算符的优先级大于双目运算符。
4. 字符类型:char
5. 对字符进行编码,实际上就是整形 0~255
字母o (octal)开头的是8进制
字母h (hexadecimal)开头的是16进制
字母d(decimal)开头的是10进制
ASCII 查看
终端下 man ascii
‘0’-48 ‘a’-97 ‘A’-65
‘\0’-0 ‘\n’-10 ‘sp(空格)’-32
6. 分支语句
if语句
swith语句
goto语句 ..
循环语句
for循环 while循环 do-while循环
for(e1;e2;e3){
}
e1:循环的初值(循环前的准备操作)
e2:循环继续条件(如果为真则继续循环)
e3:循环增量(每一次循环后,都会执行)
课堂练习:
1 分数 计算
判断输入0~100的数,超出即判断错误。
90~100 A
80~89 B
70~79 C
60~69 D
0~59 E
int score=0;
while(1){
score=0;
scanf("%d",&score);
if(score<0||2score>100)
printf("输入错误,请重新输入\n");
else
break;
}
score=(int)score/10;
switch(score){
case 10:
case 9:
printf("A\n");
break;
case 8:
printf("B\n");
break;
case 7:
printf("C\n");
break;
case 6:
printf("D\n");
break;
default:
printf("E\n");
break;
}
return 0;
}
2 100~999 的水仙花数
int sum=0;
for(sum=100;sum<1000;sum++){
if(sum==(sum/100)*(sum/100)*(sum/100)+(sum%100/10)*(sum%100/10)*(sum%100/10)+(sum%10)*(sum%10)*(sum%10))
printf("%d ",sum);
}
return 0;
}
3 一元钱可以拆成 多少1分钱,2分钱 5分钱
int money=100,a1=0,b2=0,c5=0,k=0;
for(a1=0;a1<=100;a1++)
for(b2=0;b2<=50;b2++)
for(c5=0;c5<=20;c5++)
{
if(money==a1+b2*2+c5*5)
{ printf("一分钱个数=%d,二分钱个数=%d,5分钱个数=%d\n",a1,b2,c5);
k++;
}
}
printf("次数=%d\n",k);
return 0;
}
作业:
20151203
1. 求fibonacii(斐波那契)数列的前40个数。F1=1,F2=2,Fn=Fn-1+Fn-2(n>=3)
2. ABCDE五个人去打鱼,经过一天疲惫不堪,各自找地方睡觉。第二天A第一个醒来,将鱼分成5份,丢掉多余的一条,拿走自己的一份。B第二个醒来,也将鱼分成5份,丢掉多余的一条,拿走自己的一份CDE都做了同样的事情。问他们最少打了多少鱼?
4 求fibonacii(斐波那契)数列的前40个数。
F1=1,F2=2,Fn=Fn-1+Fn-2(n>=3)
int i=0,k=0;
int F[50]={0};
F[1]=1;
F[2]=2;
for(i=3;i<=40;i++)
{
F[i]=F[i-1]+F[i-2];
k++;
printf("%d ",F[i]);
}
printf("次数为%d",k);
return 0;
}
12.4
1. do-while 最少执行一次,先执行后判断
do
{
}while(expr1);
输入一个数字或字母,打印,否则重新输入
#include <stdio.h>
int main()
{
char ch;
char tmp;
do{
printf ("input a character\n");
scanf("%c",&i);
whilr(1){
scanf("%c",&tmp);
if( tmp == '\n')
{
break;
}
}
}while(!((ch >=’0’&&ch<=’9’)||(ch>=’A’&&ch<=’Z’)||(ch>=’a’&&ch<=’z’)));
printf("ch=%c\n",ch);
return 0; }
for(),while();先判断后执行,可能一次也不执行。
%c可以接收 \n space 等字符
2.数组:一组相同类型元素的有序集合。
#include <stdio.h>
int main()
{
// 数组定义
// type array_name[array_length] ={value1 ,valuew,...};
int arr[10]; //={1,2,3,4,5,6,7,8,9,10};
int i;
// 访问数组中的元素
// 通过数组下标 0~n-1
// printf("%d\n",arr[4]);
for(i = 0;i <10;i++)
{
scanf("%d",&arr[i]);
}
for( i = 0;i <10;i++)
{
printf("arr[%d]=%d\n",i,arr[i]);
}
int max;
for(i=1;i<10;i++)
{
if (max<arr[i])
{
max = arr[i];
}
}
}
练习:输入10个整形数
将最小值和第一个数交换
将最大值和最后一个数交换
输出
自做:
#include <stdio.h>
int main()
{
int arr[10];int i;
for(i = 0;i <10;i++)
{
scanf("%d",&arr[i]);
}
int max = arr[0];
int min = arr[0];
int maxnum = 0;
int minnum = 0;
int a;int b;
for(i=1;i<10;i++)
{
if (max<arr[i])
{
max = arr[i];
maxnum = i;
}
if (min>arr[i])
{
min = arr[i];
minnum = i;
}
}
a = arr[0];
arr[0] = min;
arr[minnum] = a;
b = arr[9];
arr[9] = max;
arr[maxnum] = b;
for( i = 0;i <10;i++)
{
printf("arr[%d]=%d\n",i,arr[i]);
}
return 0;
}
老师做:
#include <stdio.h>
int main()
{
//1.定义一个数组
int arr[10];
int i;
//2.输入十个数
for(i = 0;i <10;i++)
{
scanf("%d",&arr[i]);
}
int max = 0;
int min = 0;
int tmp;
//3.找最大最小值的下标
for(i=1;i<10;i++)
{
if (arr[max]<arr[i])
{
max = i;
}
if (arr[min]>arr[i])
{
min = i;
}
}
//4.交换
tmp = arr[0];
arr[0] = arr[min];
arr[min] = tmp;
if(max == 0)
{
max = min;
}
tmp = arr[9];
arr[9] = arr[max];
arr[max] = tmp;
//5.输出十个数
for( i = 0;i <10;i++)
{
printf("arr[%d]=%d\n",i,arr[i]);
}
return 0;
}
数组越界,如果越界胶原程序会崩溃,数组越界是一个错误。
&表示取地址。%p专门用于表示地址。
数组名是一个地址常量,表示数组中第一个元素的首地址。
定义数时,初始化列表中值得个数徐爱玉数组长度,缺少的全部为0,定义数组时,如果有初始化列表,可省略数组长度,其长度为初始化列表中元素的个数。
sizeof(数组名)计算的是整个数组所占用的字节数。
局部变量 (函数内的)未初始化,值为随机数。
作用域:函数内
全局变量 (函数外的)未初始化,值为0。
作用域:整个程序
当不同的作用域中的变量名重复时,访问的是作用域内小的。
3.字符数组与字符串
‘\0’:表示字符串的结束。
字符串输出方法:
方法一:循环 + %c
不同于整形数组的遍历,字符串的遍历一般需要两个条件:不越界和结束符判断
方法二:%s 有可能越界(只判断结束符,不判断数组长度)。
需要包含#include<string.h>头文件,表示一些字符串操作的函数
方法三:puts();//和printf的问题一样,puts会自动在最后输出一个\n。
方法四;putchar();//和printf(“%c”,arr[]);一样。
字符串输入不需要取地址符(&)。
字符串输入方法:
方法一:
使用%s输入时,以空格、回车等字符作为结束符,也不能保证不会越界。
方法二:
gets(),和scanf()相类似,可以接受空格,以回车作为结束输入,也不能保证不会越界。
方法三:
循环 + %c,需要使用&,需要自己判断回车结束。需要使用if来防止越界。
方法四:
getchar();
练习:输入一个字符串,将所有的法学字母转换为小写字母后输出。
#include <stdio.h>
int main()
{
char str[10];
int i ;
for(i = 0;i < 10; i++)
{
scanf("%c",&str[i]);
if(str[i] == '\n')
{
str[i] = '\0';
break;
}
}
if( i == 10)
{
str[i-1]='\0';
}
for(i = 0;i <10 &&str[i]!='\0'; i++)
{
if(str[i]>='A'&&str[i]<='Z')
{
str[i] +=32;
}
}
for(i = 0 ; i < 10&&str[i]!='\0'; i++)
{
printf("%c",str[i]);
}
printf("\n");
return 0;
}
输入两个字符串,比较两个字符串是否相等,输出结果。
老师做:
#include <stdio.h>
#include <string.h>
int main()
{
char str1[128], str2[128];
int i;
for ( i=0; i<10; i++) {
scanf("%c", &str1[i]);
if ( str1[i] == '\n' ) {
str1[i] = '\0';
break;
}
}
if ( i == 10 ) {
str1[i-1] = '\0';
}
for ( i=0; i<10; i++) {
scanf("%c", &str2[i]);
if ( str2[i] == '\n' ) {
str2[i] = '\0';
break;
}
}
if ( i == 10 ) {
str2[i-1] = '\0';
}
for( i=0;i<10&&str1[i]!='\0'&&str2[i]!='\0'; i++) {
if ( str1[i] != str2[i] ) {
break;
}
}
if ( str1[i] == str2[i] ) {
printf("相等!\n");
}
else {
printf("不相等\n");
}
return 0;
}
自己做:
#include <stdio.h>
int main()
{
char str1[10];
char str2[10];
int i,j=0 ;
for(i = 0;i < 10; i++)
{
scanf("%c",&str1[i]);
if(str1[i] == '\n')
{
str1[i] = '\0';
break;
}
}
if( i == 10)
{
str1[i-1]='\0';
}
for(i = 0;i < 10; i++)
{
scanf("%c",&str2[i]);
if(str2[i] == '\n')
{
str2[i] = '\0';
break;
}
}
if( i == 10)
{
str2[i-1]='\0';
} for(i=0;i<10&&str1[i]!='\0'&&str2[i]!='\0'; i++)
{
if(str1[i]!=str2[i])
{
j = 1;
break;
}
}
if( j == 0 &&str1[i]=='\0'&&str2[i]=='\0')
{
printf("相同\n");
}
else
{
printf("不相同\n");
}
return 0;
}
12.7
练习
实现长度为10的整型有序数组的操作(>0)的操作
包括:插入、删除、查找、打印。
#include <stdio.h>
int main()
{
int arr[10] = {0};
int choose;
while (1) {
printf("1.Insert 2.Delete 3.Search 4.Print 5.Quit:");
scanf("%d", &choose);
if ( choose == 5 ) {
break;
}
switch (choose) {
case 1:
{
int data;
if ( arr[9] != 0 ) {
printf("can not insert!\n");
break;
}
printf("input a insert data:");
scanf("%d", &data);
if ( data <= 0 ) {
printf("input error!\n");
break;
}
//1.确定插入的位置
int i;
for ( i=0; i<10&&arr[i]>0; i++) {
if ( data < arr[i] ) {
break;
}
}
//3.插入数据
int tmp;
for ( ; i<10&&data>0; i++) {
tmp = data;
data = arr[i];
arr[i] = tmp;
}
break;
}
case 2:
{
int data;
int i;
if ( arr[0] == 0 ) {
printf("can not delete!\n");
break;
}
printf("input delete data:");
scanf("%d", &data);
if ( data <= 0 ) {
printf("delete failed.\n");
break;
}
//找删除的元素位置
int flag = 0;//0表示没找到 1表示找到了
for ( i=0; i<10&&arr[i]>0; i++) {
if ( data == arr[i] ) {
flag = 1;
break;
}
else if ( data < arr[i] ) {
break;
}
}
if ( flag == 0 ) {
printf("delete failed.\n");
break;
}
//删除
for ( ; i<9; i++) {
arr[i] = arr[i+1];
}
if ( arr[9] != 0) {
arr[9] = 0;
}
break;
}
case 3:
{
int data;
int i;
if ( arr[0] == 0 ) {
printf("can not search!\n");
break;
}
printf("input search data:");
scanf("%d", &data);
if ( data <= 0 ) {
printf("search failed.\n");
break;
}
//找删除的元素位置
int flag = 0;//0表示没找到 1表示找到了
for ( i=0; i<10&&arr[i]>0; i++) {
if ( data == arr[i] ) {
flag = 1;
break;
}
else if ( data < arr[i] ) {
break;
}
}
if ( flag == 0 ) {
printf("search failed.\n");
}
else {
printf("search success %d.\n", i);
}
break;
}
case 4:
{
int i;
for ( i=0; i<10&&arr[i]>0; i++) {
printf("%d ", arr[i]);
}
printf("\n");
break;
}
default:
break;
}
}
return 0;
}
1. 二维数组
定义多维数组时,只有和数组名最近的长度可以省略。
练习:
定义多维数组,打印每一行的最大值,打印所有值的最小值。
自做:存在bug,输入每一维度数据不能全为负数,若全为负数,输出结果有误。
#include <stdio.h>
int main()
{
int arr1[3][4] = {{0}};
int i, j;
int max = 0,min = 0;
for ( i=0; i<3; i++)
{
for ( j=0; j<4; j++)
{
scanf("%d", &arr1[i][j]);
}
}
for ( i=0; i<3; i++)
{
for ( j=0; j<4; j++)
{
if(arr1[i][j]>max)
{
max = arr1[i][j];
}
}
printf("%d ", max);
printf("\n");
if(min == 0)
{
min = max;
}
else if(min > max)
{
min = max;
}
}
printf("%d ", min);
printf("\n");
return 0;
}
老师做;
#include <stdio.h>
int main()
{
int arr1[3][4] = {{0}};
int i, j;
for ( i=0; i<3; i++) {
for ( j=0; j<4; j++) {
scanf("%d", &arr1[i][j]);
}
}
for ( i=0; i<3; i++) {
for ( j=0; j<4; j++) {
printf("%d ", arr1[i][j]);
}
printf("\n");
}
int max[3],min;
for ( i=0; i<3; i++) {
max[i] = arr1[i][0];
for ( j=1; j<4; j++) {
if ( max < arr1[i][j] ) {
max = arr1[i][j];
}
}
printf("the max of %d line is %d\n", i, max);
}
min = max[0];
for ( i=1; i<3; i++) {
if ( min > max[i] ) {
min = max[i];
}
}
printf("min:%d\n", min);
return 0;
}
2. 数组中的地址
地址与整型数进行+-运算
数组名+n:arr+n*sizeof(数组的元素类型)
arr+n == &arr[n]
取地址中的数据 *
*(arr+n) == arr[n]
&*(arr+n) == &arr[n]
3. 指针变量:存储地址的变量
p是a的地址,*p就是a。
int *p //野指针,随机地址
int *p = NULL //0x0地址处不能访问 Null就是空值。
12.8
重构
整个程序的运行,是由若干个函数串联起来的。
main()函数是程序的入口。
1. 函数
函数三要素:函数的声明(可缺省)
用于告诉编译器,有这么个函数。
函数声明,形参名可省略。
函数的定义
函数具体做了什么。
函数的调用
除了主函数外,其他函数的调用必须在函数中。
执行一遍函数中的代码。
函数应当先声明后调用。
函数的定义也当做声明来用。
函数形式参数:在函数的定义中相当于内部的局部变量。
函数实际参数:在函数调用中,实参将值传递给形参,即形参的处置是实参的值。
返回值类型为void,表示无返回值
变量赋值为一个函数的调用:变量赋值为函数的返回值。
有返回值的函数,在函数内部的每一个分支执行到最后都要有return。
一个函数,可以接收多个参数,但只能有一个返回值。
形参不能改变实参,如果实参传地址,形参用指针接收这个地址,可以改变。
函数如果想要改变实参的值,实参传地址(形参使用指针接收),这种参数被称作出参(具有返回值的功能)。
函数不改变实参的值,直接传实参就可以,这种参数被称作入参。
一个函数被调用两次,这两次之间一点关系都没有。
练习:
用函数,求阶乘
自做:
#include <stdio.h>
int factorial(int n);
int main()
{
int a,b;
scanf("%d",&a);
b = factorial(a);
printf("%d\n",b);
return 0;
}
int factorial(int n)
{
int i;
for(i = n;n > 1;n--)
{
i *= (n-1);
}
return i;
}
老师做:
#include <stdio.h>
int factorial(int num);
int main()
{
int a;
scanf("%d", &a);
int b = factorial(a);
printf("%d!=%d\n", a, b);
return 0;
}
int factorial(int num)
{
int a = 1, i;
for ( i=1; i<=num; i++) {
a = a*i; //a = 1*2*3*4*...*num
}
return a;
}
用函数进行简单计算。(加减乘除)
#include <stdio.h>
int my_add(int, int);
int my_sub(int, int);
int my_mul(int, int);
int my_div(int, int);
int main()
{
int x1, x2, ret;
char ch;
scanf("%d%c%d", &x1, &ch, &x2);
switch (ch) {
case '+':
ret = my_add(x1, x2);
break;
case '-':
ret = my_sub(x1, x2);
break;
case '*':
ret = my_mul(x1, x2);
break;
case '/':
ret = my_div(x1, x2);
break;
default:
break;
}
printf("%d%c%d=%d\n", x1, ch, x2, ret);
return 0;
}
int my_add(int a, int b)
{
int ret;
ret = a + b;
return ret;
}
int my_sub(int a, int b)
{
int ret;
ret = a - b;
return ret;
}
int my_mul(int a, int b)
{
int ret;
ret = a * b;
return ret;
}
int my_div(int a, int b)
{
int ret;
ret = a / b;
return ret;
}
指针变量的长度:机器字长。(MAC下是8字节),与指针指向的具体类型无关。
函数的参数不能是数组,如果写成数组的形式,实际上是指针变量。
函数的使用,使得程序模块化,能够实现代码复用。
2.位运算:二进制的运算 & | ~ >> <<
按位运算,并且没有进位和借位
& :对应位 都是1才是1 清零
| :对应位 都是0才是0 置位
~ :对应位 按位取反
最大整型:~0
异或运算:^相同为0,不同为1。
位移运算
左移运算 << 高位丢弃,低位补0。
右移运算 >> 低位丢弃,高位补0。
12.9
1.函数递归:自己调用自己,尽量不使用。
2.程序中的内存空间
局部变量:
栈
全局变量:全局静态区
常量:静态全局区
静态变量:静态全局区
动态申请的空间:堆
3.常量:const 关键字用于声明一个变量为只读,即常量。
const char * p1; // p1指向的区域是只读的 --- *p1只读
char const * p2; // p1 == p2
char * const p3; // p2本身是只读的 -- p3只读
字符串常量:
char *p = "hello world"; //字符串常量
字符串常量前最好加上const。
4.string.h库中的常用函数
strlen()与sizeof()区别:
strlen()只能用于字符串
strlen()计算时不考虑结束符,sizeof()计算的是数组的实际空间
size_t strlen(const char *str)
strcpy(str1, str2); //copy
char * strcpy(char * str1, const char * str2)
返回值是str1
strcat(str1, str2);//连接
char * strcat (char * str1, const char * str2)
strcmp(str1, str2); //compare 比较两个字符串是否相等
char * strcmp (char * str1, const char * str2)
5.静态变量:sratic
静态函数:该函数不能被其他源文件调用。
静态函数;静态的含义是:将一个全局的变量/函数 作用域缩小。
静态局部变量:作用域为函数内。
该变量不会随着函数调用的结果而销毁。
改变量只会在函数第一次被调用时初始化。
静态全局变量:作用域为当前文件。
6.extern外部声明:
声明一个全局变量以及函数,到其他源文件去寻找,所有的函数声明前都有一个缺省的extern
7. auto:声明 局部变量、自动变量,可缺省。
8. 预处理命令:
宏定义;
#define N 10
在编译过程中,将N替换为10,仅仅是简单替换。
9. 堆空间:malloc 和 free
头文件#include <stdlib.h>
malloc函数用于内存分配(堆空间)。
堆空间通过指针来访问。
void* malloc(size_t size);
参数size:要分配空间的字节数。
返回值:分配的内存空间的首地址。
void* 任意类型地址。
malloc函数如果失败,返回NULL。
堆空间的使用:想要用得申请,不再使用要释放。
free函数用于释放不再使用的堆空间。
void free(void *ptr);
如果未及时释放,造成的情况:内存泄露。
如果重复释放,程序会崩溃。
使用下面代码可防止重复释放:
if ( p != NULL )
{
free(p);
p = NULL;
}
如果一段内存释放了,就不要再访问了。
练习:
输入两个数组,合并成一个数组后输出。
#include <stdio.h>
#include <stdlib.h>
int main()
{
int num1,num2,i;
int *parr1;
int *parr2;
int *parr3;
scanf("%d", &num1);
parr1 = (int*)malloc(num1*sizeof(int));
for ( i=0; i<num1; i++)
{
scanf("%d", parr1+i);
}
scanf("%d", &num2);
parr2 = (int*)malloc(num2*sizeof(int));
for ( i=0; i<num2; i++)
{
scanf("%d", parr2+i);
}
parr3 = (int*)malloc(num1*sizeof(int)+num2*sizeof(int));
for ( i=0; i< (num1+num2); i++)
{
if(i < num1)
{
parr3[i] = parr1[i];
}
else
{
parr3[i] = parr2[i-num1];
}
}
for ( i=0; i < (num1+num2); i++)
{
printf("%d ", parr3[i]);
}
printf("\n");
if ( parr1 != NULL ) {
free(parr1);
parr1 = NULL;
}
if ( parr2 != NULL ) {
free(parr2);
parr2 = NULL;
}
if ( parr3 != NULL ) {
free(parr3);
parr3 = NULL;
}
return 0;
}
12.10
1.地址常量(数组名)的步长:数组中元素的类型。
地址变量 (指针)的步长:去掉名和*。
数组的元素类型:去掉数组名以及最近的[]。
地址的步长: +1的长度 sizeof(数组的元素类型)。
指针所指向元素的类型:去掉指针名和最近的*。
指针的步长: +1的长度 sizeof(指针所指向元素的类型)。
不同的地址之间可以进行类型强转,强转后值不变。
不同的地址之间的区别:
1、步长不同。
2、*运算取出数据的长度不同。
void * p1 没有步长:不能出现以下要操作
p5+1 *p5
仅用于传递地址数据
2. 二级指针:存储一级指针变量的地址,二级指针存储的地址被称作耳机地址,通常用于函数的形参(实参传指针)。
3. 指针数组 *parr[10];指针数组,存储多个字符串。存储二维数组中的每一行的地址。
4. 数组指针:作为形参时,接收为二维数组的实参。
5. 指针数组的步长是数组的长度。
6. 枚举类型
数值类型:int float char 布尔类型 枚举类型(无符号整型)
集合类型:数组 结构体 字典 元组
枚举类型是一个无符号的整型数,取值范围是有穷的,定义枚举类型时,需要将该枚举类型可以赋值的值列举出来。关键字enum。提高代码可读性。列举的值,如果第一个未指定赋值,则为0,其他值如果未指定赋值,为前一个+1。列举值可以重复,但名不可以重复。
typedef为类型那个取别名。
7. 条件编译
#include <stdio.h>
#include <stdint.h>
//#define INT32
#ifdef INT32
typedef int32_t int_t;
#else
typedef int64_t int_t;
#endif
#include <stdio.h>
#include <stdint.h>
//#define INT32
#ifndef INT32
typedef int32_t int_t;
#else
typedef int64_t int_t;
#endif
#if
#endif
8. 多文件开发
头文件:函数的声明、全局变量的声明、宏定义、类型的定义。头文件声明
#ifndef HEAD_H
#define HEAD_H //防止头文件被重复包含
结尾处
#endif
包含头文件时<>与“”的区别
<>用于自带的头文件,| 用于包含在系统指定的头文件目录中的文件。
“”用于自定义的头文件 | 用于包含指定目录中的头文件。编译时不用编译头文件。
9. 函数指针
函数名代表函数的首地址(在代码段中的地址)。
函数指针是存储函数地址的
#include <stdio.h>
void my_swap(int *x, int *y)
{
int tmp;
tmp = *x;
*x = *y;
*y = tmp;
}
int main()
{
int a = 10, b = 20;
// my_swap(&a, &b);
void (*p)(int *, int*); //1.定义函数指针变量
p = my_swap; //2.为函数指针变量赋值
p(&a, &b); //3.通过函数指针调用函数
//(*p)(&a, &b);
printf("a=%d b=%d\n", a, b);
return 0;
}
#include <stdio.h>
void my_swap(int *x, int *y)
{
int tmp;
tmp = *x;
*x = *y;
*y = tmp;
}
void my_swap2(int *x, int *y)
{
int a, b;
a = *x;
b = *y;
*x = a+b;
*y = a-b;
}
int main()
{
int a = 10, b = 20;
void (*p)(int*, int*);
// p = my_swap;
p = my_swap2;
p(&a, &b);
printf("a=%d b=%d\n", a, b);
return 0;
}
使用的三步:
1.定义函数指针变量
2.为函数指针变量赋值(存储一个函数地址)
3.通过函数指针调用函数
函数指针没有步长。
用途:
1.放在结构体中,作为结构体的成员。
2.函数指针作为函数的参数。
12.11
1.结构体:一组可以具有不同类型元素的集合。
结构体类型的定义:
struct 名字{
//所有成员变量,用;分割
};
//struct A {
// int a;
// char b;
// int *c;
// char d[10];
//};
//typedef struct A A;
typedef struct A {
int a;
char b;
int *c;
char d[10];
}sA, *pA; //类型别名
//sA ---> struct A
//pA ---> struct A * --> sA *
//struct A {
// int a;
// char b;
// int *c;
// char d[10];
//}sA, *pA; //全局变量
//struct { //没有类型名
// int a;
// char b;
// int *c;
// char d[10];
//}sA, *pA;
结构体变量初始化,和数组类似。
结构体变量成员访问:变量名.成员名。
练习:设计一个结构体,学生结构体
成员包括:学号id,姓名name,且判断score
输入一个学生的信息,并输出,且判断这个学生是否及格。
自做:
#include <stdio.h>
typedef struct A {
int id;
char name;
int score;
}student;
int main()
{
student a1 ;
scanf("%d", &a1.id);
scanf("%c", &a1.name);
scanf("%d", &a1.score);
if ( a1.score >= 60 )
{
printf("学生学号:%d 学生姓名:%c 学生分数:%d 学生及格\n",a1.id, a1.name, a1.score);
}
else
{
printf("学生学号:%d 学生姓名:%c 学生分数:%d 学生不及格\n",a1.id, a1.name, a1.score);
}
return 0;
}
老师做:
#include <stdio.h>
#define NAME_LENGTH 128
typedef enum {
Male, Female
}sex_t;
typedef struct student {
unsigned int id;
char name[NAME_LENGTH];
sex_t sex;
unsigned short score;
}sStu_t;
int main()
{
sStu_t s;
char *pstr_sex[2] = {"male", "female"};
printf("input the student identifier:");
scanf("%u", &s.id);
printf("input the student name:");
scanf("%s", s.name);
printf("input the student sex(0:male 1:female):");
scanf("%u", &s.sex);
printf("input the student score:");
scanf("%hu", &s.score);
printf("id:%u name:%s sex:%s score:%hu ", s.id, s.name, pstr_sex[s.sex], s.score);
if ( s.score >= 60 ) {
printf("pass.\n");
}
else {
printf("not pass.\n");
}
return 0;
}
练习:设计一个结构体,学生结构体
成员包括:学号id,姓名name,性别,且判断chinese、english、math的score
输入一个学生的信息,并输出,且判断这个学生每门学科是否及格。
自做:
#include <stdio.h>
#define NAME_LENGTH 128
typedef enum {
Male, Female
}sex_t;
typedef struct {
unsigned short chinese;
unsigned short english;
unsigned short math;
}score_t;
typedef struct student {
unsigned int id;
char name[NAME_LENGTH];
sex_t sex;
score_t score;
}sStu_t;
int main()
{
sStu_t s;
char *pstr_sex[2] = {"male", "female"};
printf("input the student identifier:");
scanf("%u", &s.id);
printf("input the student name:");
scanf("%s", s.name);
printf("input the student sex(0:male 1:female):");
scanf("%u", &s.sex);
printf("input the student chinese score:");
scanf("%hu", &s.score.chinese);
printf("input the student english score:");
scanf("%hu", &s.score.english);
printf("input the student math score:");
scanf("%hu", &s.score.math);
printf("id:%u name:%s sex:%s chinese score:%hu englishscore:%hu math score:%hu \n", s.id, s.name, pstr_sex[s.sex], s.score.chinese,s.score.english,s.score.math);
if (s.score.chinese >= 60 )
{
printf("chinese pass.\n");
}
else {
printf("chinese not pass.\n");
}
if (s.score.english >= 60 )
{
printf("english pass.\n");
}
else {
printf("english not pass.\n");
}
if (s.score.math >= 60)
{
printf("math pass.\n");
}
else {
printf("math not pass.\n");
}
return 0;
}
老师做:
#include <stdio.h>
#define NAME_LENGTH 128
typedef enum {
Male, Female
}sex_t;
typedef struct {
unsigned short chinese;
unsigned short english;
unsigned short math;
}score_t;
typedef struct student {
unsigned int id;
char name[NAME_LENGTH];
sex_t sex;
score_t score;
}sStu_t;
int main()
{
sStu_t s;
char *pstr_sex[2] = {"male", "female"};
printf("input the student identifier:");
scanf("%u", &s.id);
printf("input the student name:");
scanf("%s", s.name);
printf("input the student sex(0:male 1:female):");
scanf("%u", &s.sex);
printf("input the student score:");
scanf("%hu %hu %hu", &s.score.chinese, &s.score.english, &s.score.math);
printf("id:%u name:%s sex:%s\n", s.id, s.name, pstr_sex[s.sex]);
if ( s.score.chinese >= 60 ) {
printf("\t\tchinese:%hu pass.\n", s.score.chinese);
}
else {
printf("\t\tchinese:%hu not pass.\n", s.score.chinese);
}
if ( s.score.english >= 60 ) {
printf("\t\tenglish:%hu pass.\n", s.score.english);
}
else {
printf("\t\tenglish:%hu not pass.\n", s.score.english);
}
if ( s.score.math >= 60 ) {
printf("\t\tmath:%hu pass.\n", s.score.math);
}
else {
printf("\t\tmath:%hu not pass.\n", s.score.math);
}
return 0;
}
编译器的对齐规则:
整个结构体按照n和最大成员的大小,相比较较小的对齐,每一个成员按照n和自身大小,相比较较小的对齐。
Mac下得gcc中n默认值为8。
用#pragma pack(n)修改对齐参数。
学习C语言已经有些时间了,对于面向过程的这门基础语言,还是需要时时回看,研究算法,只有基础打好,才是通向成功坚实的阶梯。