C语言基础

2018-03-03  本文已影响0人  恒筠

第一章

1.C语言学习中的重难点

第二章

prinf函数


prinf函数的域宽问题

    // 如果m为负数,则右对齐(右侧补空白)
    printf("|%-5d|",88);
输出结果:|88   |

转义字符问题

printf("%f%%", 1.0/3);
输出结果: 0.333333%。
\n 换行,相当于敲一下回车。
\t 跳到下一个tab位置,相当于按一下键盘上的tab键。 \b 退格,相当于按一下backspace。
\r 使光标回到本行开头。
\f 换页,光标移到到下页开头。
\\ 输出\字符,也就是在屏幕上显示一个\字符。
\' 输出'字符,也就是在屏幕上显示一个'字符。
\" 输出"字符,也就是在屏幕上显示一个"字符。

第三章

1.类型转换

2.sizeof 运算符

    >   - 注意: sizeof不是一个函数, 是一个运算符. (面试题)
    > 

3.自增自剪

自增的两种写法

 int result = 10;
 result++;
 ++result;
 

自剪的两种写法

   result--;
    --result;
**总结一句话: ++在前, 先自增再运算, ++在后, 先运算再自增**

4.逻辑运算符的短路问题

 int a = 10;
  int b = 20;
  int result = (a > 19) && (b++ > 6);
  printf("a = %d,b = %d, result = %d\n", a, b, result);
输出结果:a = 10,b = 20, result = 0
 int a = 10;
  int b = 20;
  int result = (a > 19) || (b++ > 6);
  printf("a = %d,b = %d, result = %d\n", a, b, result);
输出结果:a = 10,b = 21, result = 1

第四章

1.whie循环的注意点

  int num = 3;
  while (3 == num) {
      printf("num = %d\n",num);
      num++;
  }

2.break关键字

```
if(1)
{
break; // 没有意义
}
```

- 在多层循环中,一个break语句只向外跳一层


```
while(1)
{
while(2)
{
  break;// 只对while2有效, 不会影响while1
}
}
```

3.continue关键字

for(int i = 100; i<= 200; i++)
{
  if(i %3 == 0) continue;
  printf("i = %d", i);
}

4.for循环的其他形式

```
for(sum=0,i=1;i<=100;i++) sum=sum+i;
或
for(i=0,j=100;i<=j;i++,j--) k=i+j;

// 表达式1和表达式3都是逗号表达式,各包含两个赋值表达式,即同时设两个初值,使两个变量增值.
```

5.for嵌套实现

1.
*
**
***
****
*****

2.
*****
****
***
**
*
for(int i = 0; i< 5; i++){
        for(int j = 0; j <= i; j++){
            printf("*\t");
        }
        printf("\n");
    }
    for(int i = 0; i< 5; i++){
        for(int j = i; j < 5; j++){
            printf("*\t");
        }
        printf("\n");
    }

第五章

1.递归函数

void getNumber2()
{
    int number = -1;
    printf("请输入一个正数abc\n");
    scanf("%d", &number);
    if (number < 0) {
//        负数
        getNumber2();
    }else{
//        正数
       printf("number = %d\n", number);
    }
}

2.用递归法求n的阶乘

4!=4*3*2*1
      =4*3!
      =4*3*2!
      =4*3*2*1!

    n!=(n-1)!*n;
    (n-1)!=(n-2)!*(n-1);
    ... ...

    1!=1; 作为递归的结束条件

3.Xcode运行原理

4.常见的UNIX命令

ls :列出当前目录下的所有内容(文件\文件夹) pwd :显示出当前目录的名称
cd :改变当前操作的目录
who :显示当前用户名
clear :清除所有内容
mkdir : 创建一个新目录
rm: 删除文件
rm -r: 删除文件夹 -f 强制删除
touch: 创建文件
vi /open:打开、创建文件
  -q 退出
  -wq 保存并退出
  -q!强制退出
  i 进入编辑模式
  esc 退出编辑模式
  :wq!
cat/more 都可以查看文件内容

5.手动编译的步骤

第六章

1.进制

***口诀:不看你怎么存,只看你怎去取***

2.原码反码补码

3.位运算

* 2.| 按位或
* 特点:只要对应的两位其中一位是1就返回1
* 口诀:一真则真


*  3.^ **按位异或**
*  特点:对应的两位不相同返回1 相同返回0


```
1001
 ^ 0101
 _______
 1100
 
 //     **多个整数按位异或的结果和顺序无关**
 1001
 ^ 0101
 _______
 1100
 
 1100
 ^ 0110
 _______
 1010
 
 1001
 ^ 0110
 _______
 1111
 
 1111
 ^ 0101
 _______
 1010
 
 
 //     **相同整数按位异或结果是0**
 1001
 ^ 1001
 _______
 0000
 
 //     **任何整数按位异或上0结果不变**
 1001
 ^ 0000
 _______
 1001
 
 //     **任何整数按位异或上另一个整数两次结果还是那个数**
 1001
 ^ 1001
 ____________
 0000
 
 0000
 ^0101
 ______
 0101
     
```    

<< 左移

 a << n 把整数a的二进制位往左边移n位
 移出的位砍掉,低位补0, 发现左移会把原有的数值变大
 9 << 1 = 18  9 * 2(1) = 18
 9 << 2 = 36  9 * 2(2) = 26
 9 << n =  9 * 2(n)
 左移的应用场景:当要计算某个数乘以2的n次方的时候就用左移,效率最高
 
 0000 0000 0000 0000 0000 0000 0000 0000
 100 0000 0000 0000 0000 0000 0000 10010
 
 注意点:左移有可能改变数值的正负性

>> 右移

 a >> n 把整数a的二进制位往右边移n位
 移出的位砍掉, 缺少的以为最高位是0就补0是1就补1(是在当前操作系统下)
 9 >> 1 = 4  9 / 2(1) = 4
 9 >> 2 = 2  9 / 2(2) = 2
 右移的应用场景:当要计算某个数除以2的N次方的时候就用右移,效率最高
 0000 0000 0000 0000 0000 0000 0000 0000
 000000 0000 0000 0000 0000 0000 0000 10

4.数组

1.数组内部存储细节

2.数组的地址

   // 注意: 由于内存寻址是从大到小, 所以存储数据也是从大到小的存储(先存储二进制的高位, 再存储低位)
    //  高位   -->                    低位
    // 00000000 00000000 00000000 00001001

第七章

1.数组练习

(填坑法)

 // 1.定义数组保存用户输入的数据
    int nums[10] = {0};
    // 2.接收用户的数据
    int value = -1;
    for (int i = 0; i < 6; i++) {
        printf("请输入第%i个数据\n", i + 1);
        scanf("%i", &value); // 2, 2, 1, 2
        // 7, 3, 6, 1
//        nums[value] = 1;
        nums[value] = nums[value] + 1;
    }
    
    for (int i = 0; i < 10; i++) { // i == 7
//        printf("nums[%i] = %i\n", i , nums[i]);
        /*
        if (nums[i] != 0) {
            printf("%i\n", i); // 1, 2, 2, 2
        }
         */
        for (int j = 0; j < nums[i]; j++) { // j == 1
            printf("%i\n", i); // 1, 1, 2, 3, 3, 6
        }
    }



int nums[8] = {99, 12, 88, 34, 5, 44, 12, 100}
int length = sizeof(nums) / sizeof(nums[0]);
    printf("length = %i\n", length);
    for (int i = 0; i < length; i++) {
        printf("nums[%i] = %i\n", i, nums[i]);
    }
    
    // length - 1是为了防止角标越界
    // length - 1因为最后一个元素已经没有可以比较的了
    // 0, 1, 2, 3, 4
    for (int i = 0; i < length - 1; i++) {
        for (int j = i+1; j < length; j++) {
//            printf("*");
//            printf("i = %i, j = %i\n", i, j);
            if (nums[i] > nums[j]) {
                int temp = nums[i];
                nums[i] = nums[j];
                nums[j] = temp;
            }
        }
//        printf("\n");
    }
    
    printf("--------------\n");
    for (int i = 0; i < length; i++) {
        printf("nums[%i] = %i\n", i, nums[i]);
    }

/*
     思路: 
     1.先分析如何比较
     2.找出比较的规律比较完一次之后第二次比较会少一次
     3.打印倒三角
     4.打印需要比较的角标
     5.比较并交换位置
     6.将常量替换为变量(length)
     */
    // 已知一个无序的数组, 里面有5个元素, 要求对数组进行排序
    int nums[6] = {99, 12, 88, 34, 5, 7};
    int length = sizeof(nums) / sizeof(nums[0]);
    for (int i = 0; i < length; i++) {
        printf("nums[%i] = %i\n", i, nums[i]);
    }
    for (int i = 0; i < length - 1; i++) {
        for (int j = 0; j < length - 1 - i; j++) {
//            printf("*");
//            printf("%i == %i\n", j, j+1);
            if (nums[j] > nums[j + 1]) {
                int temp = nums[j];
                nums[j] = nums[j + 1];
                nums[j + 1] = temp;
            }
        }
//        printf("\n");
    }
    printf("----------\n");
    for (int i = 0; i < length; i++) {
        printf("nums[%i] = %i\n", i, nums[i]);
    }

```
nt min, max, mid;
    min = 0;
    max = length - 1;
    
    // 只要还在我们的范围内就需要查找
    while (min <= max) {
        // 计算中间值
        mid = (min  + max) / 2;
        if (key > nums[mid]) {
            min = mid + 1;
        }else if (key < nums[mid])
        {
            max = mid - 1;
        }else
        {
            return mid;
        }
        
    }
    return -1;
```

* 方法2

    
```

int min, max, mid;
min = 0;
max = length - 1;
mid = (min + max) / 2;

while (key != nums[mid]) {
    // 判断如果要找的值, 大于了取出的值, 那么min要改变
    if (key > nums[mid]) {
        min = mid + 1;
    // 判断如果要找的值, 小雨了取出的值, 那么max要改变
    }else if (key < nums[mid])
    {
        max = mid - 1;
    }
    
    // 超出范围, 数组中没有需要查找的值
    if (min > max) {
        return -1;
    }
    // 每次改变完min和max都需要重新计算mid
    mid = (min + max) / 2;
}

// printf("aaaaaa\n");

return mid;

```

    // 转换所有的进制
    // value就是需要转换的数值
    // base就是需要&上的数
    // offset就是需要右移的位数  
    // 1.定义一个数组, 用于保存十六进制中所有的取值
    char charValues[] = {'0', '1', '2', '3', '4', '5', '6', '7', '8', '9', 'a', 'b', 'c', 'd', 'e', 'f'};
    // 2.定义一个数组, 用于保存查询后的结果
    char results[32] = {'0'};
    // 3.定义一个变量, 用于记录当前需要存储到查询结果数组的索引
    int pos = sizeof(results)/ sizeof(results[0]);
    
    while (value != 0) {
        // 1.取出1位的值
        int res = value & base;// 1 7 15
        // 2.利用取出来得值到表中查询对应的结果
        char c = charValues[res];
        // 3.存储查询的结果
        results[--pos] = c;
        // 4.移除二进制被取过的1位
        value = value >> offset;// 1 3 4
    }
    
    // 4.打印结果
    for (int i = pos; i < 32; i++) {
        printf("%c", results[i]);
    }
    printf("\n");

第八章

1.字符串

char ch[] = "lnj";
printf("%s\n", ch);

\0引发的脏读

char name[] = {'c', 'o', 'o', 'l' , '\0'};
char name2[] = {'l', 'n', 'j'};
printf("name2 = %s\n", name2);
输出结果: lnjcool

2.指针与数组

3.字符串指针

char *str;
scanf("%s", str);

错误的原因是:str是一个野指针,他并没有指向某一块内 存空间,所以不允许这样写如果给str分配内存空间是可以这样用 的

4.指向函数的指针


int sum(int v1, int v2)
{
    return v1 + v2;
}

int minus(int v1, int v2)
{
    return v1 - v2;
}

// 让demo接受一个指向函数的指针
// 以后我们只需要给demo函数传递对应的指针, 那么函数内部就可以调用不同的函数


int demo3(int v1, int v2, int (*p)(int, int))
{
    return p(v1, v2);
}
int main(int argc, const char * argv[]) {
    // 定义一个方法, 给你两个数, 用户要求你做加法你就做加法, 用户要求你做减法, 那你就做减法
    
    printf("mins = %i\n", demo3(20, 10, minus));
    printf("sum = %i\n", demo3(20, 10, sum));
    
    return 0;
}

第九章

1.构造类型

2.结构体

* 指定将数据赋值给指定的属性
    * struct Dog sd3 = {.height = 1.77, .name = "ww", .age = 33};

3.结构体指针

struct 结构名 *结构指针变量名
```
// 定义一个结构体类型
      struct Student {
          char *name;
          int age;
      };

     // 定义一个结构体变量
     struct Student stu = {“NJ", 27};

     // 定义一个指向结构体的指针变量
     struct Student *p;

    // 指向结构体变量stu
    p = &stu;

     /*
      这时候可以用3种方式访问结构体的成员
      */
     // 方式1:结构体变量名.成员名
     printf("name=%s, age = %d \n", stu.name, stu.age);

     // 方式2:(*指针变量名).成员名
     printf("name=%s, age = %d \n", (*p).name, (*p).age);

     // 方式3:指针变量名->成员名
     printf("name=%s, age = %d \n", p->name, p->age);

     return 0; }
```

4.枚举类型

枚举类型是一种基本数据类型,而不是一种构造类型,因为它不能再分解为任何 基本类型。


要求定义一个枚举来保持一年四季
    // 1.定义枚举类型
    // 定义枚举类型的规范
    // 枚举类型的取值一般以k开头 后面跟上枚举类型的名称  跟上当前取值的含义
    // 和结构体一样, 枚举类型的名称首字母大写
    enum Season
    {
        kSeasonSpring,
        kSeasonSummer,
        kSeasonAutumn,
        kSeasonWinter
    };
    
    enum Gender
    {
        kGenderMale,
        kGenderFemale
    };
    
    enum Season es;
    es = kSeasonAutumn;
    
    enum Gender eg;
    eg = kGenderFemale;

第十章

1.static和extern关键字-对变量的作用

* 声明一个内部变量 static int a;
* 定义一个内部变量 static int a = 10;
* 由于静态全局变量的作用域局限于一个源文件内,只能为该源文件内的函数公用,因此可以 避免在其它源文件中引起错误。

2.宏定义

            不能有空格
#define average (a, b) ((a+b)/2)

提前结束宏定义的作用域
//#undef COUNT

3.条件编译

#define DEBUG 1 // 0是调试阶段 1是发布阶段

#if DEBUG == 0
// 调试阶段
#define NJLog(format, ...) printf(format,## __VA_ARGS__)
#else
// 发布阶段
#define NJLog(format, ...)
#endif
#ifdef SCORE // 判断是否定义了后面的宏
    printf("score\n");
#elif COUNT
    printf("count\n");
#else
    printf("OTHER\n");
#endif
     
#ifndef SCORE // 是不是没有定义名称叫做SCORE的宏
    printf("no score\n");
#else
    printf("score\n");
#endif
     */
    
    /*
#if defined(SCORE) // 判断是否定义了SCORE这个宏
    printf("score\n");
#else
    printf("no score\n");
#endif
    
#if !defined(SCORE) // 判断是否没有定义SCORE这个宏
    printf("no score\n");
#else
    printf("score\n");
#endif


4.typedef


注意: 如果是给指向函数的指针起别名, 那么指向函数的指针的指针名称就是它的别名

functionPotinter == int(*functionPotinter)(int , int)
typedef int(*functionPotinter)(int , int);

5.const

上一篇 下一篇

猜你喜欢

热点阅读