C 指针

理解指针定义 --存放地址

内存区的每一个字节有一个编号, 这就是“地址”。 如果在程序中定义了一个变量, 在对程序进行编译

时, 系统就会给这个变量分配内存单元。 

在c程序里面有两种访问方式: 1. 是直接访问, 2是间接访问(a的箱子要是在b抽屉里)。

直接访问: a=5;, 系统在编译是,已经对变量分配了地址 如果变量的a的地址是2000, 那么这个语句的作用就是

把常数5保存到地址为2000的单元。
间接访问如:scanf(“%d”, &a);
调用函数时, 把变量a的地址传递给函数scanf, 函数首先把该地址保存到一个单元中, 然后把键盘接受的数据通过所存储的地址保存到a的变量中。

 

定义指针

int i=5;
int
* i_abc; 定义指针变量 i_abc = & i; 存放整型变量i的地址

 

 

深入理解:

将i 的内存地址2000存放到i_abc,这时, i_abc的值就是(2000, i的内存地址),即变量i所占用单元

的起始地址。要存取变量i的值,可以采取间接方式:先找到存放“i的地址”的变量i_abc, 然后从中取出i的地址(2000)

然后取出i的值3.

代码讲解

*  : 叫取值操作符

&: 叫取址操作符

int i = 5;
int *abc;  // 这个*不是取值操作符,而是声明他是指针变量, 也就是定义指针变量
abc = &i;  // 存放指针,也就是内存地址  &i 的地址是2000
printf("%d\n", *abc);//这个才是取值操作符, 加上*系统知道他是指针的值

 

注意:

定义的时候:

float a;

int   *abc;

abc = &a;

这样是错误的,关系到取址, 比如有浮点是8位,而整型是4位,那就会少4位

说明: 

如果已执行了语句 abc = &a;

1) . &*abc的含义是什么?

"&"和 "*" 两个运算符的优先级相同, 但按照自右而左方向结合, 因此先进行*abc 的运算, 他就是变量a,

例如: printf("%d\n", *abc);

再执行&运算。

2)。 * & a的含义是蛇年意思?

先&a运算,然后在×运算, 最后还是指向a  

 

针对数组的指针 ---------------------------

p= &a【0】  // 把a【0】元素的地址赋给指针变量p

注意一个小地方:

引用一个数组元素, 可以用:

).下标法, 如a[i]形式;

).指针法, 如*(a+i) 或(p+)

其中的a是数组名, p是指向数组元素的指针变量, 其初值p=a。也就是

a指向的数组第一个值

数组名即“翻译成数组的第一个元素地址”

 

简单易懂的例子

#include <stdio.h>

#define N 10

int main(void) {

    int a[N] = {1, 2, 3, 4, 5, 6, 7, 8, 9, 10};
    int *p, sum = 0;

    //方法1:
    //用索引的方式, 这里需要注意的是p是指针,a[0]是实际的值,需要用&取址
    for (p = &a[0]; p < &a[N]; p++) {
        sum += *p;
    }
    printf("sum value is:%d \n", sum); /* sum value is:55 */

    //方法2:
    //用指针的方式
    sum = 0;
    for (p = a; p < a + N; p++) {
        sum += *p;
    }
    printf("sum value is:%d \n", sum); /*sum value is:55*/
    return 0;
}

 

 

要输出数组中的全部元素的三种方法-------一维数组

方法1:下标法

#include <stdio.h>

int main(int argc, char const *argv[]) {
  /* code */
  int a[10];
  int i;
  for(i = 0; i < 10; i++)
  {
      scanf("%d", &a[i] );
  }
  for(i=0;i<10;i++)
  {
      printf("%d\n", a[i]);
  }
  return 0;
}

方法2: 通过数组名计算数组元素的地址, 找出元素值

#include <stdio.h>

int main(int argc, char const *argv[]) {
  /* code */
  int a[10];
  int i;
  for(i = 0; i < 10; i++)
  {
      scanf("%d", &a[i] );
  }
  for(i=0;i<10;i++)
  {
      printf("%d\n", *(a+i));
  }
  return 0;
}

方法3:用指针变量指向数组元素

#include <stdio.h>

int main(int argc, char const *argv[]) {
  int a[10];
  int i;
  int *p;

  for (i=0;i<10;i++)
  {
      scanf("%d", &a[i]);
  }

  for (p = a; p < (a+10); p++)
  {
    /* code */
    printf("%d", *p);
  }
  return 0;
}

 

用数组名作为函数参数--------------------------------------------

f(int a[], int n)  但在编译时是将arr按指针变量处理的, 相当于将函数f的首部写成f(int *arr, int n)  等价的

看试题:

要求将数组a中n个整数按相反顺序存放

#include <stdio.h>

int main(int argc, char const *argv[]) {
  void reverse(int *x, int);
  int i, a[10] = {3, 7, 9, 11, 0, 6, 7, 5, 4, 2};
  for (i = 0; i < 10; i++)
  {
      printf("%d", a[i]);
  }
  printf("\n");
  reverse(a, 10);
  for (i = 0; i < 10; i++) {
    printf("%d", a[i]);
  }
  printf("\n");
  return 0;
}

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;
   }
}
View Code

 

 指针写法

#include <stdio.h>

int main(int argc, char const *argv[]) {
  void reverse(int *x, int);
  int i, a[10] = {3, 7, 9, 11, 0, 6, 7, 5, 4, 2};
  for (i = 0; i < 10; i++)
  {
      printf("%d", a[i]);
  }
  printf("\n");
  reverse(a, 10);
  for (i = 0; i < 10; i++) {
    printf("%d", a[i]);
  }
  printf("\n");
  return 0;
}

void reverse(int *x, int n)
{
    int *p, temp, *i, *j, m;

    m = (n - 1)/2;
    i = x;
    j = x + n -1;
    p = x + m;
    for (;i <= p;i++, j--)
    {
      temp = *i;
      *i = *j;
      *j = temp;
    }
}
View Code

 二维数组

内存地址

 

 怎么用指针寻找的规律

 

  

从前面的图可以分析得出结论 *(p+i) + j 是二维数组i行j列的元素地址
而*(*(p+i) +j) 则是i行j列的值

定义多维数组元素的指针变量

把二维数组a分解为一维数组a[0], a[1], a[2]之后, 设p为指向二维数组的指针变量

可定义为:

int (*p)[4]

 

 表示p是一个指针变量, 他指向包含4个元素的一维数组。 若指向第一个一维数组a[0], 其值等于a,

a【0】, 或&a【0】【0】等。 

 

#include <stdio.h>

int main(int argc, char const *argv[])
{
  int a[3][4] = {0,1,2,3,4,5,6,7,8,9,10,11};
  int (*p)[4];
  int i, j;
  p = a;

  for (i=0; i < 3; i++)
  {
    /* code */
    for (j = 0;j<4;j++)
    {
        // printf("%2d", *(*p+i)+j);   //注意这个错误,是我当初犯下的错误
        printf("%2d", *(*(p+i)+j));
    }
    printf("\n");
  }

  return 0;
}

 

字符串与指针  --------------------------------------

用数组的形式来表示字符串

#include <stdio.h>

int main(int argc, char const *argv[])
{
  char string[] = "I love you , Future girl"  ;
  printf("%s\n", string);

  return 0;
}

 

用指针的形式

#include <stdio.h>

int main(int argc, char const *argv[])
{
  char *string = "I love you , Future girl"  ;
  printf("%s\n", string);

  return 0;
}

 

对字符串中的字符的存取方法有两种

1. 是下标法:

#include <stdio.h>

int main(int argc, char const *argv[])
{
  char a[] = "hahhahahaha, future girl", b[40];
  int i;

  for (i = 0; *(a + i) != '\0'; i++)
 {
    *(b + i) = a[i];
  }
  *(b + i) = '\0';
  printf("%s\n", a);
  printf("%c\n", *a);
  for (i = 0; b[i] != '\0'; i++)
  {
    printf("%c", b[i]);
  }
  printf("\n");
  return 0;
}
View Code

 

2.是指针方法:

#include <stdio.h>

int main(int argc, char const *argv[]) {
  char a[] = "hahhahahaha, future girl", b[40], *p1, *p2;
  int i;

  p1 = a;
  p2 = b;

  for (; *p1 != '\0'; p1++, p2++)
 {
    *p2 = *p1;
  }
  *p2 = '\0';
  printf("wo shi a:%s\n", a);
  for (i = 0; b[i] != '\0'; i++)
  {
    printf("%c", b[i]);
  }
  return 0;
}
View Code

 

字符指针作函数参数以及指针a【】和*a 的区别 -----------------------------

*a 是不可写的,a【】是可写的

为什么:  char *a = "i am a;";  是放常量的,常量是不可写的。

在c/c++中,内存分为5个区, 堆,栈, 自由存储区, 全局/静态存储区和常亮存储区。

 

方法一:用字符串数组作参数

#include <stdio.h>

int main(int argc, char const *argv[])
{
    int copy_str(char from[], char to[]);

    char a[] = "i am a;";
    char b[] = "i am b;";

    printf("%s\n%s\n----------------\n", a, b);

    copy_str(a, b);
    printf("%s\n%s\n", a, b);

  return 0;
}


int copy_str(char from[], char to[])
{
  int i = 0;
  while (from[i] != '\0') {
    to[i] = from[i];
    i++;
  }
  to[i] = '\0';
  return 0;
}
View Code

 

方法二: 形参用字符指针变量

#include <stdio.h>

int main(int argc, char const *argv[])
{
    int copy_str(char *from, char *to);

    char *a = "i am a;";
    char b[] = "i am b;";  //注意这是b是不是为×b,否则报错不能写入

    printf("%s\n%s\n----------------\n", a, b);

    copy_str(a, b);
    printf("%s\n%s\n", a, b);

  return 0;
}


int copy_str(char *from, char *to)
{
  for (; *from != '\0'; from++, to++)
  {
      *to = *from ;
  }
  return 0;
}
View Code

 

还有一种巧妙方法

#include <stdio.h>

int main(int argc, char const *argv[])
{
    int max(int, int);
    int (*p)();
    int a, b, c;

    p = max;
    scanf("%d %d", &a, &b );

    c = (*p)(a, b);  //关键是这句
    printf("%d, %d\n", a, b);
    printf("%d\n", c);
  return 0;
}
int max(int x, int y)
{
    int z;

    if (x > y)
      {
         z = x;
      }
    else
      {
        z = y;
      }
    return z;
}
View Code

 

小需求及测试题

注意,指针函数 的写法

int *test(int a[]);

返回指针的数组元素的写法

int *test(int a[]){
    return &a[3];
}

用&符号

 

 参考代码:

只写了一部分

#include <stdio.h>

#define N 5

int *test(int a[]);

int main(void) {
    int b[N] = {1, 2, 3, 4, 5};
    int *a=NULL;
    a = test(b);
    printf("%d\n", *a);
    return 0;
}

int *test(int a[]){
    return &a[3];
}
View Code

 

 

 

#include <stdio.h>

#define N 5

void find_two_largest(int a[], int n, int *largest, int *second_largest);

int main(void) {
    int b[N] = {1, 2, 3, 4, 5,};
    int largest = 0, second_largest = 0;

    find_two_largest(b, N, &largest, &second_largest);
    printf("largest value is: %d \n", largest);
    printf("second_largest value is: %d \n", second_largest);
    return 0;
}

void find_two_largest(int a[], int n, int *largest, int *second_largest) {

    *largest = *second_largest = a[0];

    for (int i = 0; i < n; ++i) {
        if (a[i] > *largest)
            *largest = a[i];
    }
    for (int i = 0; i < n; ++i) {
        if (a[i] == *largest) {
            continue;
        } else if (a[i] > *second_largest) {
            *second_largest = a[i];
        }
    }
}

 

posted @ 2017-05-08 21:47  我当道士那儿些年  阅读(260)  评论(0编辑  收藏  举报