问题求解

数组长度问题

问题1 数组必须是固定长度的,使用不方便,期望是动态长度的。
希望有数组的处理函数,以及字符串的处理函数,并且他们的长度是动态可控的。

  1. // 数组的处理函数
  2. // 字符串处理函数
  3. #include <iostream>
  4. #include <climits>
  5. #include <string.h>
  6. int main() {
  7. using namespace std;
  8. int a[10] = {1,2};
  9. char str[10] = "abcdef";
  10. char strA[] = "abcdef";
  11. cout << sizeof(a) << endl; // 40字节 1B = 1字节 = 8Bit
  12. cout << sizeof(a) / sizeof(int) << endl; // 10
  13. cout << sizeof(strA) << endl; // 7
  14. cout << sizeof(strA) / sizeof(char) << endl; // 7
  15. cout << strlen(str) << endl; // 6
  16. }

函数和变量的存储类别

  1. int main() {
  2. float add(float x, float y); // 对被调用变量的声明
  3. }
  4. float add(float x, float y);

变量的存储类别

从变量的作用域角度来分,可以分为全局变量和局部变量
从变量的生存周期来分,可以分为静态存储方式和动态存储方式

  • 静态存储区:全局变量存储在静态存储区中,在程序开始执行时给全局变量分配存储区,程序执行完毕就释放。
  • 动态存储区:
  1. 函数参数形式,函数中的局部变量如果不声明static都是动态地分配存储空间的
  2. 自动变量(未加static声明的局部变量)
  3. 函数调用时的现场保护和返回地址等
  • 存储类别指的是数据在内存中存储的方法

1.auto自动的(本函数有效)
2.static 静态的(静态局部变量只在函数内部有效并且离开函数值可以保留,静态全局变量只在本文件有效)
3.register寄存器(离开函数,值就消失)
4.extern 外部的(外部变量,其他文件可以引用)

  1. // 变量的存储类别
  2. // auto auto 可以被省略
  3. int f(int a) {
  4. auto int b, c = 3; // 声明b,c为自动变量
  5. //...
  6. auto int b, c = 3; // 与int b, c = 3;等价
  7. }
  8. // static 如果希望函数中的局部变量的值在函数调用以后不被销毁而保留原值,就可以用static声明
  9. f(int a) {
  10. auto b = 0;
  11. static c = 3;
  12. b += 1;
  13. c += 1;
  14. return (a + b + c);
  15. }
  16. int main() {
  17. int a = 2;
  18. int i;
  19. for (i = 0; i < 3; i += 1) {
  20. printf("%d\n", f(a)); // 输出结果7 8 9
  21. }
  22. }
  23. // register变量 寄存器变量,如果有一个变量要频繁被使用(例如在一个函数执行100000次,
  24. // 每次循环都要用到该变量),C语言允许将局部的值,放在寄存器中,以提供运算速度
  25. #include <stdio.h>
  26. int fac(int n) {
  27. register int i, f = 1;
  28. for (i = 1; i <= n; i += 1) {
  29. f = f * n;
  30. }
  31. return(f);
  32. }
  33. int main() {
  34. int i;
  35. for (i = 1; i <= 5; i += 1) {
  36. printf("%d! =%d\n",i, fac(i));
  37. }
  38. }
  39. // extern 外部的 如果一个程序包含多个文件,在多个文件中都要用到同一个外部变量Num,
  40. // 不能分别在两个文件中各自定义一个外部变量Num,否则程序会出现“重复定义”的错误,
  41. // 正确的做法是,在一个文件中定义外部变量Num,而在另一个文件中用extern对Num做外部变量声明
  42. #include <stdio.h>
  43. int max(int x, int y) {
  44. return x > y ? x : y;
  45. }
  46. int main() {
  47. extern int A;
  48. extern int B;
  49. printf("%d\n", max(A,B));
  50. }
  51. int A = 13;
  52. int B = -8;
  53. // 在程序设计中,希望某些变量只限于本文件引用,不能被其他文件引用,可以在定义外部变量上加上static;
  54. int A = 13;
  55. static int B = -8;
  56. int max(int x, int y) {
  57. return x > y ? x : y;
  58. }
  59. int main() {
  60. extern int A;
  61. printf("%d\n", max(A,B));
  62. }

预编译

宏定义

#define 标识符 字符串

#define 宏名(参数列表) 字符串

  • 可以设置有效范围 #define 标识符 字符串 … #undef 标识符 ```cpp

    define PI 3.1415926

    define S(a,b) a * b

define G 88

// … 有效范围

undef G

  1. <a name="b7wYI"></a>
  2. ## 文件包含
  3. #include <文件名> // 从标准目录开始查找<br />#include "文件名" // 从文件目录开始查找,没找到,在找标准目录
  4. - 文件包含是可以嵌套的
  5. <a name="L8isz"></a>
  6. ## 条件编译
  7. <a name="JGQiw"></a>
  8. ### #ifdef ... #else ... #endif
  9. 1. 方式一,标识符以及被定义过了,结果为true,未被定义过,结果为false
  10. ```cpp
  11. #ifdef 标识符
  12. 程序段1
  13. #else
  14. 程序段2
  15. #endif
  16. #ifdef 标识符
  17. 程序段1
  18. #endif

#ifndef … #else #endif

  1. 方式2,与方式一的区别是#ifndef多了一个n,并且表示符并定义过,结果为false,未被定义过,结果为true ```cpp

    ifndef 标识符

    程序段1

    else

    程序段2

    endif

ifdef 标识符

程序段1

endif

  1. <a name="SqQSd"></a>
  2. ### #if 标识符 #else ... #endif
  3. 3. 方式3,表达式值为真编译程序段1
  4. ```cpp
  5. #include <iostream>
  6. #define LETTER 1
  7. int main() {
  8. using namespace std;
  9. char str[20] = "lijunyang";
  10. int i;
  11. i = 0;
  12. char c;
  13. while((c = str[i]) != '\0') {
  14. i++;
  15. #if LETTER
  16. if (c >= 'a' && c <= 'z') {
  17. c = c - 32;
  18. }
  19. #else
  20. if (c >= 'A' && c <= 'Z') {
  21. c = c + 32;
  22. }
  23. #endif
  24. cout << c << endl;
  25. }
  26. }

使用typedef定义类型

typedef可以声明新的类型来代替原有类型

  1. typedef int INTEGER; // INTEGER 新类型 可以当int使用
  2. typedef float REAL;
  3. typedef int COUNT;
  4. COUNT i, j;
  5. typedef struct {
  6. int month;
  7. int day;
  8. int year;
  9. }DATE; // 新类型DATE
  10. typedef int NUM[100]; // 新类型NUM 他是一个长度为100的int数组
  11. NUM n;
  12. typedef char *STRING; // 定义字符串指针,相当于字符串数组
  13. STRING p,s[10];

指针

变量的指针和指向变量的指针变量

  • 基类型 指针变量名; ```cpp int pointer_1, pointer_2; float pointer_3; double *pointer_4;

int i,j; pointer_1 = &i; // 将i的地址存放在pointer_1中 pointer_2 = &j; // 将j的地址存放在pointer_2中

  1. - 指针变量的引用,指针变量只能存放指针,不能接受基本类型的值
  2. - &:取地址运算符<br />- *:间接访问运算符
  3. ```cpp
  4. #include <iostream>
  5. int main() {
  6. using namespace std;
  7. int *pointer_1;
  8. int *pointer_2;
  9. int i = 100;
  10. int j = 10;
  11. pointer_1 = &i; // 将i的地址存放在pointer_1中
  12. pointer_2 = &j; // 将j的地址存放在pointer_2中
  13. cout << "i:" << i << endl;
  14. cout << "j:" << j << endl;
  15. cout << "pointer_1:" << pointer_1 << endl;
  16. cout << "pointer_2:" << pointer_2 << endl;
  17. cout << "*pointer_1:" << *pointer_1 << endl;
  18. cout << "*pointer_2:" << *pointer_2 << endl;
  19. /*
  20. i:100
  21. j:10
  22. pointer_1:0x7fff59e348dc
  23. pointer_2:0x7fff59e348d8
  24. *pointer_1:100
  25. *pointer_2:10
  26. */
  27. &*pointer_1; // i 的地址
  28. pointer_2 = &*pointer_1; // 将i的地址赋值给pointer_2
  29. }
  • 指针作为函数的参数 注意值传递和引用传递的区别 ```cpp swap(int p1, int p2) { // 此方式,可以改变外部变量的内容 // C语言中实参变量和形参变量的数据传递是单向的“值传递”方式 // 但是此时修改的值,修改的是p1和p2指向的内存段的值,所以会影响外部的值 int temp; temp = p1; // 将p1指向的内存段的值,赋值给temp p1 = p2; // 将p1指向的内存段的值 设置为 p2指向内存段的值,引用修改 p2 = temp; // 将p2指向的内存段的值 设置为 temp }

swap (int x, int y) { // C语言中实参变量和形参变量的数据传递是单向的“值传递”方式 // 值传递,此时的x,y是属于该函数的,具有自己的内存段,值的变化不影响外部 int temp; temp = x; x = y; y = temp; }

swap (int p1, int p2) { // C语言中实参变量和形参变量的数据传递是单向的“值传递”方式,指针变量也遵循这一规则 // p1和p2都属于该函数内部的变量,这两个变量值的变化不影响外部 int *temp; temp = p1; p1 = p2; p2 = temp; }

swap(int p1, int p2) { int temp; // 声明一个指针 temp = p1; // 此语句有问题,因为temp所指向的内存单元是不可遇见的,所以此操作可能非常危险 p1 = p2; p2 = *temp; }


<a name="SjTVs"></a>
## 数组的指针和指向数组的指针变量

```cpp
int a[10];
int *p;

p = &a[0]; // p = a; 等价
p = a; // &a[0]; 等价

int *p1 = a; // int *p1 = &a[0]; int *p1 = a;

// p+1 = 数组下标+1
// a+1 = 数组下标+1
#include <iostream>

int main() {
    using namespace std;
    int a[10];
    int i;
    for (i = 0; i < 10; i++) {
        cin >> a[i];
    }
    for (i = 0; i < 10; i++) {
        cout << a[i];
    }
    cout << endl;
}

#include <iostream>

int main() {
    using namespace std;
    int a[10];
    int *p;
    int i;
    for (i = 0; i < 10; i++) {
        cin >> a[i];
    }
    for (p = a; p < (a + 10); p++) {
        cout << *p;
    }
    for (i = 0; i < 10; i++) {
        cout << *(a + i);
    }
    cout << endl;
}

数组作为函数参数

f(int arr[] , int n);
f(int *arr, int n);

arr[i] === *(arr+i); // 表达式 等价

max = min = *arr; // 等价与 max = min = arr[0]
max = min = arr[0]; // 等价与 max  = min = *arr;

多维数组的指针和指向多维数组的指针变量

int a[10][10];
a+1 = a[0][0]; 
a+1 = a[1][0];
a[0] + 1 = a[0][1];

*(*(a + 0) + 1) = a[0][1];
*(*(a + 1) + 1) = a[1][1];

#include <stdio.h>
#define FORMAT "%p,%p\n"

int main(){
  int a[3][4] = { 1, 3, 5, 7, 9, 11, 13, 15, 17, 19, 21, 23 };
  printf(FORMAT, a, a[0]);
  printf(FORMAT, a[0], *(a + 0));
  printf(FORMAT, &a[0], &a[0][0]);
  printf(FORMAT, a[1], a + 1);
  printf(FORMAT, &a[1][0], *(a + 1) + 0);
  printf(FORMAT, a[2], *(a + 2));
  printf(FORMAT, &a[2], a + 2);
  printf("%d,%d\n", a[1][0], *(*(a + 1) + 0)); // 9,9
  return 0;
}
/*
0x7fff5340d910,0x7fff5340d910
0x7fff5340d910,0x7fff5340d910
0x7fff5340d910,0x7fff5340d910
0x7fff5340d920,0x7fff5340d920
0x7fff5340d920,0x7fff5340d920
0x7fff5340d930,0x7fff5340d930
0x7fff5340d930,0x7fff5340d930
9,9
*/

字符串的指针和指向字符串的指针变量

main () {
  char string[] = "I love China!";
  char *strA = "I love China!";
  printf("%s\n", string);
}

// 将字符串A复制为字符串B
#include <stdio.h>

int main(){
  char a[] = "I am a boy";
  char b[20];
  int i;
  for (i = 0; *(a+i) != '\0'; i += 1) {
      *(b + i) = * (a + i);
  }
  *(b + i) = '\0';
  printf("string a is :%s\n", a);
  printf("string b is :");
  for (i = 0; b[i] != '\0'; i += 1) {
      printf("%c", *(b + i));
  } 
  printf("\n");
  return 0;
}

fn(char str[]); fn(char * str);

函数的指针与指向函数的指针变量

  • 每一个函数都占用一段内存单元,他们有一个起始地址,因此可以用指针变量指向一个函数

    数据类型 (* 指针变量名)(); // 声明指向函数的指针

    ```cpp

    include

int max(int x, int y) { int z; if (x > y) { z = x; } else { z = y; } return z; } / int main() { int max(int,int); int a,b,c; scanf(“%d,%d”, &a, &b); // 输入 11,22 c = max(a, b); printf(“a=%d,b=%b,max=%d\n”, a, b, c); return 0; } / int main() { int max(int,int); int (p)(); int a,b,c; p = max; scanf(“%d,%d”, &a, &b); c = (p)(a, b); printf(“a = %d, b = %d, max = %d\n”, a,b); }

<a name="tAXUB"></a>
#### 使用指向函数的指针作为参数
```cpp
sub(int (*x1)(int), int (*x2)(int, int)) {
    int a;
    int b;
    int i = 1;
    int j = 2;
    a = (*x1)(i);
    b = (*x2)(i, j);
}

例子

#include <stdio.h>
int main(){
  int max(int, int);
  int min(int, int);
  int add(int, int);
  void process(int, int, int (*fun)(int, int));
  int a;
  int b;
  printf("enter a and b\n");
  scanf("%d,%d", &a, &b);
  printf("min=");
  process(a, b, min);

  printf("max=");
  process(a, b, max);

  printf("sum=");
  process(a, b, add);
}

int max(int i, int j) {
    return i > j ? i : j;
}

int min (int i, int j) {
    return i > j ? j : i;
}

int add (int i, int j) {
    return i + j;
}

void process(int x, int y, int (*fun)(int, int)) {
    int result = (*fun)(x, y);
  printf("%d\n", result);
}

返回指针值的函数

类型名 *函数名(参数列表); // 通过这种方式可以获得一个指向特定类型的指针

int *a(int x, int y); // 该函数返回一个int类型的指针
#include <stdio.h>

int main() {
  float score[][4] = {
      { 12, 13, 14, 15 },
      { 100, 60, 30, 22 },
      { 73, 22, 32, 44 }
  };
  float * search(float (*pointer)[4], int n);
  float * p;
  int i;
  int m;
  printf("enter the number of student:");
  scanf("%d", &m);
  printf("The scores of No.%d are: \n", m);
  p = search(score, m);
  for (i = 0; i < 4; i += 1) {
      printf("%5.2f\t", *(p + i));
  }
  printf("\n");
}

float * search(float (*pointer)[4], int n) {
    float *pt;
  pt = *(pointer + n);
  return (pt);
}

指针数组 和 指向指针的指针

指针数组 : 类型名 *数组名[数组长度]

int *p[4];
// 由于[]比*优先级高,因此p先与[4]结合,形成p[4]的数组,有4个元素,然后在与*结合表示该数组是指针类型的。
// 每个数组元素是一个int类型的指针
#include <stdio.h>
#include <string.h>
int main() {
        void sort(const char *name[], int n);
    void print(const char *name[], int n);
    const char *name[] = { "wangdewei", "lijunyang", "wangbangming", "masai" };
    int n = 4;
    sort(name, n);
    print(name,n);
      /*
    lijunyang
    masai
    wangbangming
    wangdewei
    */
}

void sort(const char *name[], int n) {
  const char *temp;
  int i,j,k;
  for (i = 0; i < n-1; i += 1) {
    k = i;
    for (j = i + 1; j < n; j += 1) {
      // strcmp函数用于比较两个字符串并根据比较结果返回整数。 0 ,正数,负数
        if (strcmp(name[k], name[j]) > 0) {
          k = j;
      }
    }
    if (k != i) {
        temp = name[i];
      name[i] = name[k];
      name[k] = temp;
    }
  }
}

void print(const char *name[], int n) {
  int i;
  for (i = 0; i < n; i += 1) {
      printf("%s\n", name[i]);
  }
}

指向指针的指针

char **p; // 这个就是指向 指针的指针的声明方式

#include <stdio.h>
int main() {
  const char *name[] = { "wangdewei", "lijunyang", "wangbangming", "masai" };
  const char **p;
  int i;
  for (i = 0; i < 4; i += 1) {
    p = name + i;
      printf("%s\n", *p);
  }
}

#include <stdio.h>
int main() {
  static int a[5] = {1,3,5,7,9};
  int  *num[] = { &a[0], &a[1], &a[2], &a[3], &a[4] };
  int **p;
  int i;
  p = num;
  for (i = 0; i < 4; i += 1) {
    printf("%d\n", **p);
    p++;
  }
}

指向结构体的指针

  • (*p).属性
  • p -> 属性 ```cpp

    include

    include

int main(){ struct student { long num; char name[20]; char sex; float score; }; struct student stu_1; struct student *p; p = &stu_1; stu_1.num = 10000; strcpy(stu_1.name, “ljy”); stu_1.sex = ‘M’; stu_1.score = 77.5; printf(“No:%ld\nname:%s\nsex:%c\nscore=%f\n”,stu_1.num, stu_1.name, stu_1.sex, stu_1.score);

printf("No:%ld\nname:%s\nsex:%c\nscore=%f\n",(*p).num, (*p).name,
      (*p).sex, (*p).score);


printf("No:%ld\nname:%s\nsex:%c\nscore=%f\n",p -> num, p -> name,
      p -> sex, p -> score);
return 0;

}

指向结构体数组的指针

```cpp
#include <stdio.h>
struct student {
    int num;
    char name[20];
    char sex;
    int age;
};

struct student stu[3] = {
    {10001, "ABC", 'M', 1811},
    {10003, "DEF", 'F', 5},
    {10002, "GHI",   'M', 3811},
};

int main() {
    struct student *p;
    printf("No.    Name                  Sex  Age\n");
    for (p = stu; p < stu + 3; p++) {
        printf("%5d  %-20s   %-3c  %-4d\n", p -> num, 
        p -> name,
        p -> sex,
        p -> age
      );
    }
    return 0;
}