C语言指针的使用、字符串和指针详解(详细、易懂)

C语言指针笔记

刚开始了解指针是从交换两个变量开始,但是总是断断续续地学,每次都在看交换两个变量的函数,上周在课上正式学了指针,看的时候感觉懂了,但是一上机就不知道指针怎么用、参数怎么传。于是想整理一下指针的学习笔记,再去做实验。

文中有错别字或其他错误的话记得给我留言哦~

什么是指针?怎么定义?

指针是一个变量,其值为另一个变量的地址,内存位置的直接地址。就像其他变量或常量一样,您必须在使用指针存储其他变量地址之前,对其进行声明。定义指针的一般类型为:

  <类型> *<变量标识符>,*<变量标识符>,...;

指针变量声明的例子:

int *px;
float *q;

其中,定义变量px是一个指针,且是指向整型变量的指针变量;q是指向单精度型变量的指针变量。

怎么使用指针变量?

指针变量跟其他变量一样,若要引用,则先要初始化或赋值。与指针有关的运算符有两个:

  1. &—取地址运算符
  2. *指针运算符

刚学指针的时候对这两个运算符很蒙,不知道该用哪个,怎么用。刚开始学不用搞那么复杂,举个简单的例子:

int a=10;
int *p;
p=&a;
printf("%d %d %p %p",a,*p,&a,p);

结果是:
10 10 000000CB5D3FF654 000000CB5D3FF654
因为变量的地址是系统随机分配的,故每次运行地址都不一样,但是输出&a和p是一个效果。a是一个普通变量,应该在前面加个"&“才能取到a的地址,而p是一个指针变量,它存的就是a的地址,故前面不用取地址符”&"。

对于取值还是取地址,为了方便记忆与理解,我是这样记的:
仅仅一个p的话,它的值就是a的地址,*p的话就是取到a的值10。

指针和数组的关系是什么?

假设程序中有以下语句:

int a[20],*p;
p=&a[2];

假设程序中有以下语句:

int a[20],*p;
p=&a[2];

这里先把a[2]看成一个普通变量而不是数组,由上面的讲解假设程序中有以下语句:

int a[20],*p;
p=&a[2];

这里先把a[2]看成一个普通变量而不是数组就好理解了。

C语言规定数组名代表数组首地址,即数组第一个元素的地址,一下两个语句是等价的:

int a[20],*p;
p=a;
p=&a[0];

注意:在程序运行过程中,一个数组所占用的存储区是不变的,因此数组名是一个常量,故只能引用数组名,而不能对其进行赋值。a=&x;是非法的。通过数组名取地址前面不用"&",因为数组名本身就是一个地址,而通过元素取地址的话前面就要加"&"。
a是常量,a++是非法的,但p是指针变量,p++是合法的。

int *p1,*p2;
int a[20],k=5;
p1=&a[k];
p2=&a[1];

p1+i ——表示&a[k+i],即a[k+i]的地址
p1-i ——表示&a[k-i],即a[k-i]的地址
p1-p2 ——表示k-1,即a[k]与a[1]之间相隔的元素个数

如何通过指针存取数组元素?

已知数组名就是数组中第一个元素的地址,以下两个语句是等价的:

*a=65;
a[0]=65;

那么如何通过指针存取数组中其他元素呢?
C语言约定如果一个指针p指向a[i],则p+1指向a[i+1],因此以下两个语句是等价的:

*(a+1=80;
a[1]=80;

注意:"*“的优先级比”+“高,”*(a+1)"中的括号是不可省略的*a+1表示先取第一个元素的值,再加1。

字符串和指针

我们先来看一段代码:

#include<stdio.h>
int main()
{
	char *s1="abcde";
	char s2[]={"abcde"};
	printf("%s,%c%s,%c\n",s1,*s1,s1+1,s1[1]);
	printf("%s,%c,%s,%c\n",s2,*s2,s2+1,s2[1]);
	return 0;
}

运行结果为:
abcde,a,bcde,b
abcde,a,bcde,b
注意输出一个字符和输出字符串的区别。
当用指针时,如s1,s1+1,s2等表示一个字符串,该字符串从指针所指字符开始直至字符串结束标志’\0’;而当用*s1,s1[1],*(s1+1),s2[0]等时,表示的是一个字符,即指针所指的字符或位于该下标的字符元素。由此可见,字符数组和字符指针在使用上是相似的。但是两者又是有区别的:

字符指针

字符串指针变量本身是一个变量,用于存放字符串的首地址。而字符串本身是存放在以该首地址为首的一块连续的内存空间中并以 \0 作为串的结束。
char *ps="C Language";
顺序是:
1.分配内存给字符指针;
2.分配内存给字符串;
3.将字符串首地址赋值给字符指针;

char *ps;  // ps 字符串指针,是指针,是一个变量
ps="C Language"; /* ps 为字符串的首地址,利用 ps++ 可遍历字符串,字符串存储
在以 ps 为开始地址的地段连续的内存空间中,并以 \0 作为字符串的结束。*/

这里有两点需要考虑清楚的地方:
1.*a只是指向一个字符

#include <stdio.h>
#include <stdlib.h>
int main(void){  
    char *a= "bcd" ;  
    printf("输出字符:%c \n", *a);  /*输出字符,使用"%c"*/
    printf("输出字符:%c \n", *(a+1) );  /*输出字符,使用"%c"*/
    printf("输出字符串:%s \n", a); /*输出字符串,使用"%s";而且a之前不能有星号"*"  */
    system("pause");  /*为了能看到输出结果*/
}

运行结果:
b c bcd
2.若字符串常量出现在表达式中,代表的值为该字符串常量的第一个字符的地址。所以"hello"仅仅代表的是其地址。原声明方式相当于一下声明方式:

char *a;
a="hello";/"hello"仅代表第一个字符的地址 

字符数组

字符数组是由若干个数组元素组成的,它可用来存放整个字符串(即用字符数组来存放字符串)。在C语言中,将字符串作为字符数组来处理(c++中不是)。
(1)可以用字符串常量来初始化字符数组:

char str[]={"hello"};

也可以省略花括号:

char str[]="hello";/系统自动加入\0

注意:上述这种字符数组的整体赋值只能出现在字符数组初始化时使用,不能用于字符数组的赋值,字符数组的赋值只能对其元素一一赋值。
下面的赋值方法是错误的:

char str[20];
str="hello";

在C语言中,可以用两种方法表示和存放字符串:

char a[]="hello";/用字符数组存放一个字符串
char *a="hello";/用字符指针指向一个字符串 

两种表示方式的字符串输出都用:printf("%s",a);
%s表示输出一个字符串,给出字符指针变量a(对于第一种表示方法,字符数组名即是字符数组的首地址,与第二种中的指针意义是一致的),则系统先输出它所指向的一个字符,然后使a自动加1,使之指向下一个字符,纸到遇到字符串结束标志符\0。

字符串指针

string* str可以赋值:

string* str = {"hello", "world"}; 
//  对比与 char *name = "wang" = {'w','a','n','g'}
//  *(str) = "hello", *(str+1) = "world"
//  *(*(str)+1) = 'e'

也就是说每个元素都是string类型的,跟char是不一样的,不过string可以用char**来代替:

string=char*;
string*=char**;

(字符串)指针数组

实例:

#include <stdio.h>
void main()
{
    char *str[] = {"Hello", "C++", "World"}; //char (*str)[] = ...
    int i;
    for(i=0; i<3; i++)
        printf("%s\n", str[i]);
} 
// str[0]字符串"hello"的首地址,str[0]+1:字符串"hello"第二个字符'e'的地址,str[2]=str+2:第三个字符串"world"的首地址
// str[1]字符串"C++"的首地址
// str[2]字符串"world"的首地址

或者:

#include<stdio.h>
#include<stdlib.h>
int main()
{
    char *str[3]={"Hello","C++","World"};
    printf("%s,%s,%c",str[0],str[0]+1,*(*(str+2)+1));
}

结果:
Hello ello o
char *a[]:表示哦a是数组,数组中的元素是指针,指向char类型,(数组里面所有的元素是连续的内存存放的),数组名是数组第一个字节的内存地址,并且数组名a也表示指针。所以a并不表示a地址存储的内容,而是a地址本身。
a+1:表示a的第二个元素的内存地址,所以是加8字节。(因为a的元素是char指针,所需要的空间为8字节(64位))
*(a+1):表示a这个数组的第二个元素的内容(是个char类型的指针,本例表示world字符串的地址)
*(*(a+1)):表示a这个数组的第二个元素的内容(char指针)所指向的内容(w字符)
char * a[10]:表示限定这个数组最多可存放10个元素(char指针),也就是说这个数组占用10*8=80个字节

a+1=>*(a+1)=>*(a+1)[0]
指针(地址)指针内容(字符串)字符
char *argv:理解为字符串
char **argv:理解为字符串指针
char *argv[]:字符串指针数组

C语言有两种表示字符串的方法,一种是字符数组,另一种是字符串常量,它们在内存中的存储位置不同,使得字符数组可以读取和修改,而字符串常量只能读取不能修改。

参考:[1]C++ 字符、字符串、字符数组、字符串指针、指针数组
   [2]C语言中文网-C语言指针

  • 154
    点赞
  • 575
    收藏
    觉得还不错? 一键收藏
  • 11
    评论

“相关推荐”对你有帮助么?

  • 非常没帮助
  • 没帮助
  • 一般
  • 有帮助
  • 非常有帮助
提交
评论 11
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值