一些指针相关的问题解析

其实很久之前我就想总结一下指针相关的东西,比如指针与数组的关系,函数的指针与函数名的关系,还有一些指针传参之类的,有很多的细节是值得去推敲的,我在这里想对这些地方使用时要注意的问题做一些总结。


一、数组与指针
我们都知道数组名其实就是一个地址,也是数组第一个元素的地址,数组名可以直接赋值给一个指针。我前面遇到的一个问题是字符串指针与数组的问题。比如:

int main(void)
{
  char *str="abcde";
  int i=strlen(str);

  printf("%s\n,str");

  //使用*(str+i)
  for(int j=0;j<i;j++)
  {
    printf("%c\n",*(str+i));
  }

  //使用数组str[i]
    for(int j=0;j<i;j++)
  {
    printf("%c\n",str[i]);
  }

}

以上三种方法都能打印出字符串“abcde”,但是需要注意的是,使用指针打印的字符串是保存在 READ ONLY DATA 段的,即常量区的,只能读而不能写。而通过数组打印的字符串是保存在全局数据区或者是保存在栈区的,这里的数据是能够进行写入操作的。事实上在程序执行之前字符“abcde”存储在静态存储区的常量区,若是使用指针,这个指针指向的就是这个常量区的地址,而若是使用数组,在执行程序时会将这个字符串复制到数组中。所以归根结底来说,这两种方法事实上操作的并不是同一段内存,因此可以进行的操作也是不一样的。

其实上面所说的,用数组来改变字符串的值也是不对的,他不会导致上面所说的错误,但是可能会导致内存访问的错误。具体的情况大家可以去看看c primer plus这本书的字符串与字符串函数这一章。

另外我看书发现了一些字符串函数的定义方法,顺便在这里贴出来:
1. char m3[40] = “abcdef”;

  1. char *m3[2] = {“abcdef”,”ghijk”};//字符串数组

  2. char *m3 = “abcdef”

  3. char *m3[] = “abcdef”;

  4. char m3[] = “abcdef”;

说实话这里的理解起来有点晦涩,其中2是字符串数组,其他的四种都是可以用于定义字符串的。在5中,计算机内存中被分配了一个有7个元素的数组(包括\0),每个元素都被初始化为相应的字符,当程序加载到内存中的时候,字符串也被加载到内存中。但是程序运行的时候才为数组分配储存空间,这时候会把引用的字符串复制到数组中。m3也就是这个数组的首地址,这里最重要的是m3是一个常量,可以使用m3+1来标识下一个元素,却不能用++m3,增量运算符只能用在变量前面。 在4中,*(m3)也在静态存储区为字符串留了7个元素空间。而一旦程序开始,还会在内存中给指针变量m3预留存储位置,用来存储该字符串的地址。在这里m3是可以改变的。


二、函数与指针
我在这里想说说是函数名与指针的一些关系。函数名经过编译器编译过后,等效为地址,也就是函数的入口。例如void (q)(int a,char b);这个函数的意思是指针q指向了 一个返回值是void类型,参数是int类型和char类型的函数,需要与void *q(int a,char b);做出区别,后者是一个返回值是void 的函数。
比如一个函数

int (*pfun)(int) ;//定义函数指针
int fun(int a)
{
  printf("%d\n",a);

  return 0;
}

int main (int argc,char** argv)
{
  fun(9);
  pfun=&fun;              //将fun的地址赋值给pfun
  (*pfun)(10);           //用 (*pfun)调用
  return 0;
}

int main (int argc,char** argv)
{
  fun(9);
  pfun=fun;               //将fun的值赋值给pfun
  pfun(10);              //用 pfun调用
  return 0;
}

int main (int argc,char** argv)
{
  fun(9);
  pfun=fun;                    //将fun的值赋值给pfun
  (*pfun)(10);                //用 (*pfun)调用
  return 0;
}

int main (int argc,char** argv)
{
  fun(9); 
  pfun=&fun;                     //将fun的地址赋值给pfun
  pfun(10);                       //用 pfun调用
  return 0;
}

int main (int argc,char** argv)
{
  (*fun)(9);             //用(*fun)调用
  return 0;
}

为了简便我就在同一代码块写了几个main函数,事实上以上这些调用都是合理的,有没有感觉很糊涂。
1.事实上,函数名前面已经解释过了,他其实是一个指针,是一个但是是一个指针常量,而我们申请的函数指针是一个变量。准确的说调用上面的fun()函数是应该(*fun)(9);
2.但函数名调用如果都得如(*fun)(9);这样,那书写与读起来都是不方便和不习惯的。所以C语言的设计者们才会设计成又可允许Fun(9);这种形式地调用。这样方便多了。
3.为统一起见,pfun函数指针变量也可以pfun(9)的形式来调用。
4.赋值时,即可pfun=&fun形式,也可pfun=Fun。
至于要怎么使用,这就看你自己的喜好咯,但是千万要注意以下的注意事项哦!
函数声明时,可不能搞得花里胡哨的
void fun(int ); //不能写成void (*fun)(int )。
void (*pun)(int ); //不能写成void pun(int )。

总结了一下我之前遇到的一些关于指针的一些细节问题,在此记录一下,也不知到是否完全正确,如果大家觉得有问题欢迎提出来讨论。但是我觉得大部分应该如此吧,也希望能给大家一些小小的帮助。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值