C语言学习

2 篇文章 0 订阅
1 篇文章 0 订阅

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=1F2=2Fn=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和自身大小,相比较较小的对齐。

n是编译器的一个对齐参数,n = 1,2,4,8。

Mac下得gcc中n默认值为8。

用#pragma pack(n)修改对齐参数。











学习C语言已经有些时间了,对于面向过程的这门基础语言,还是需要时时回看,研究算法,只有基础打好,才是通向成功坚实的阶梯。

 

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值