精华内容
下载资源
问答
  • C语言:比较两个字符串是否相等
    千次阅读
    2021-05-18 10:06:43

    1) 使用strcmp进行比较

    下面通过一个例子进行演示:

    #include

    #include

    int main(void)

    {

    char* str1 = "abc";

    char* str2 = "abc";

    if (strcmp(str1, str2) == 0) {

    printf("str1和str2相同!\n");

    }

    else {

    printf("str1和str2不相同!\n");

    }

    return 0;

    }

    讲解上面的程序:

    定义了一个char(字符型)的指针变量str1,并且初始化为 "abc"

    定义了一个char(字符型)的指针变量str2,并且初始化为 "abc"

    通过strcmp进行比较两个字符串是否相同,如果相同返回0(详细见strcmp百度百科)

    ?

    2) strcmp的实现

    int __cdecl strcmp (const char *src, const char *dst)

    {

    int ret = 0 ;

    while(!(ret = *(unsigned char *)src - *(unsigned char *)dst) && *dst)

    {

    ++src;

    ++dst;

    }

    if ( ret < 0 )

    ret = -1 ;

    else if ( ret > 0 )

    ret = 1 ;

    return( ret );

    }

    下面进行讲解:

    定义了一个int(整型)的变量ret,并且初始化为0

    (unsigned char*) src 表示将src强制转换为unsigned(无符号)的char(字符型)变量 (同理dst)

    *(unsigned char*) src 表示获取src中的数据(同理dst)

    *(unsigned char*) src - *(unsigned char*)dst,

    *(unsigned char*) src表示获取当前src的数据,(假设为"a")

    *(unsigned char*)dst表示获取当前dst的数据,(假设为"a")

    根据ASCII码表 "a"为65,(ASCII码表)

    所以src - dst,所表示的就是 65 - 65,返回结果为0

    (ret =*(unsigned char *)src - *(unsigned char *)dst),所以ret 为0

    !(ret = *(unsigned char *)src - *(unsigned char *)dst),取反ret

    *dst,*dst为获取dst的数据,因为每个字符串的结尾都有一个"\0"(ASCII码表中为0)

    判断true和false,其实就是0为false,非0为true,所以可以得出,

    如果dst到了字符串末尾,则退出循环

    ++src,表示将src的指针向后移动一位(同理dst)(如果这里不懂的可以看下面)

    下面的if...else if则是根据ret的返回值进行返回对应的数值(详细见strcmp百度百科)

    PS :(因为char、unsigned char 都只占一个字符,所以*src也就获取当前src所指向的字符)

    ?

    3)不懂++src的可以看下

    ++src,表示将src的指针向后移动一位

    ?

    好的,下面进行讲解:

    假设当前src的地址为(0x00898b3c),

    先说src的类型,当前src的类型为char(字符型),char所占内存大小为1字节,

    所以++src后src的地址就变成了(0x00898b3d),

    最后通过++src也就能遍历整个src所指向的内存地址中的数据,然后和dst比较

    你们是否不懂为什么要++呢?(不懂就继续往下看吧)

    首先假设src当前所指向的是 "abc" 的内存地址

    当前src为(0x00898b3c),所指向的是"a"

    所以*src也就是为"a",(可能你们会疑问为什么是"a")

    因为char所占内存大小为1字节,

    所以*src获取的数据也就只获取当前src当前所指向的内存地址的一位中的数据,

    可以这样理解:

    (0x00898b3c)中为"a"

    (0x00898b3d)中为"b"

    (0x00898b3e)中为"c"

    (0x00898b3f)中为"\0"

    所以++src就是不断向后移动指针进行遍历"abc"中的每个字符

    ?

    ?

    ?

    更多相关内容
  • C语言指针,便于理解

    千次阅读 2021-05-25 06:40:01
    一、指针变量定义C语言种变量:其中变量(普通变量)存储内容值;地址变量(指针变量)存储地址值。...(2)在定义指针变量时,指针变量名前的“*”表示现定义的是一个指针类型的变量。星号并不是指针变量名的...

    一、指针变量定义

    C语言有两种变量:

    其中变量(普通变量)存储内容值;地址变量(指针变量)存储地址值。

    1、定义的格式:

    类型名 *指针变量名;

    如:

    int a,b,*p1,*p2;

    float x,y,*p3,*p4;

    chars,*p5,*p6;

    注:

    (1)定义变量(普通变量、指针变量)都必须在前面有类型名。

    (2)在定义指针变量时,指针变量名前的“*”表示现定义的是一个指针类型的变量。星号并不是指针变量名的一部分,只有一个标志。

    (3)指针变景专口用来存地址,禁止将一个整型值直接t给一不着变量。

    int a,b,*p;

    a=1000;

    b=2000;

    p=4000;//错误只能存地址值

    2、指针变量的引用

    “&”取地址运算符,通过&运算符可以取出普通变量的地址。

    “”指针运算符,可以取出指针变量所指向的普通变量的值,(间接引用普通量)

    *指针变量名

    如:

    int a,b=20,c=30,d=40,*p;

    p=&d;

    a=*p;a=d;

    指针方法:

    口诀:内容变量画房子,指针变量画指向,定义也要初始化,

    口诀:地址变量得地址,得谁地址指向谁,有*为内容值,不是读就是写,=号左边是写操作

    画图:数组,static,指针,链表,文件

    注:

    (1)可以通过赋值使一个指针变量“指向”某一普通变量(指针变量=&普通变量)。

    (2)在C语言中正确的做法是先让指针变量指向一个确定的存储单元后,再通过该指针变量引用它所指向的存储单元,如:

    int *p;//p的"房子"是随机的,指针是任意指的,如果指针指向系统区,则代价极高

    *p=200;危险!//因此在C语言中指针必须定义且初始化

    (3)变量名(普通变量、指针变量)都表示其存储单元内的值。

    pl=p2;/*pl指向了p2所指向的单元*/

    读出p2的内容值写到p1的"房子"里

    (4)若指针变量p指向变量a,即将变量a的地址赋给了指针变量p。

    如:int a=20,*p=&a;则有下列结果(等价表):

    A、*p<=>a

    B、p<=>&a

    C、&*p<=>&a<=>p

    D、*&a<=>*p<=>a

    E、(*p)++ a++都是给变量a的值加1。

    (*p)-- a--

    ++(*p) ++a ++*p

    --(*p) --a --*p

    (5)所有的指针变量在内存中分配的字节数相同。sizcof()

    int *p1;

    float *p2;

    double *p3;

    指针变量永远占两个字节(地址),前面类型表示的是该指针指向的内容值的类型

    例1:

    请输出下列程序的结果

    void fun(int*x,int*y)

    {printf("%d %d",*x,*y);

    *x=3;

    *y=4;

    }

    main()

    {int x=1,y=2;

    fun(&y,&x);

    printf("d% d%",x,y);

    }

    输出结果:2 14 3

    例2:

    #include请输出下列程序的结果

    void swap(int*pl,int*p2)

    {int temp;

    temp=*p1;

    *p1=*p2;

    *p2=temp;}

    main()

    {

    int a,b;

    int *p1=&a,*p2=&b;

    scanf("%d%d",pl,p2);

    swap(pl,p2);

    printf("%d,%d",*pl,*p2);

    }

    键盘输入2 5

    输出结果:5,2

    改动后:

    #include请输出下列程序的结果

    void swap(int*pl,int*p2)

    {int *temp;

    temp=pl;

    p1=p2;

    p2=temp;

    }

    main()

    {int a,b;

    int*p1=&a,*p2=&b;

    scanf("%d%d",pl,p2);

    swap(p1,p2);

    printf("%d,%d",*p1,*p2);

    }

    键盘输入:2 5

    输出结果为: 2,5

    例3:

    #include请输出下列程序的结果

    void swap(int*pl,int*p2)

    {int *temp;

    *temp=*pl;

    *p1=*p2;

    *p2=*temp;}

    main()

    {int a,b;

    int *p1=&a,*p2=&b;

    scanf("%d%d",pl,p2);

    swap(pl,p2);

    printf(%d,%d",*p1,*p2);

    }

    键盘输入:2 5

    结果:是5,2吗?错误!会报错哦,指针变量不能任意指,必须初始化程序中temp没有初始化所以很危险哦

    二、一维数组与指针变量

    说明:(1)

    int fun(int a[10])<=>int fun(int*a)<=>int fun(int a[])

    若数组做为形参,则将数组名做指针变量来处理。

    指向数组的指针变量

    1、指向数组元素的指针变量

    由于数组元素与普通一样,所以定义指向数组元素的指针变量与定义指向普通变量的指针变量完全一样

    如:

    int s[10],a,b;

    int b[3][6];

    int*p;

    p=&a;

    p=&s[2];

    p=&b[2][4];

    2、指向一维数组的指针变量

    注:数组a[]

    (1)在C语言中规定:数组名a代表数组的首地址,而且是一个地址常量,且a<=>&a[0]

    如:

    int a[10];intp;P=a;<=>P=&a[0];

    (2)当指针变量指向数组中的某一个元素时,指针变量加1后指向数组的下一个元素,指针变量减1时指向数组中前一个元素。

    如:

    float a[10];floatp;p=&a[4];则p-3指向?---->a[1]

    (3)

    int a[N],*p=a;

    p+i a+i &a[i] 地址三者相互等价

    *(p+i) *(a+i) a[i] p[i] 元素四等价

    当指针变量指向数组时,下标运算符(一级) ([])用于数组也可用于指针变量后

    a)*(p+i)*(a+i)a[i] p[i]

    b)p++、++p、p+=1、p=p+1

    c)p--、--p、p-=1、p=p-1

    d)*p++*(p++) *p-- *(p--)

    e)*++p *(++p) *--p *(--p)

    f)(*p)++ ++(*p)++*p

    g)(*p)-- --(*p)--*p

    如:

    若有定义:

    int b[5]={10,30,20,15,40};

    int*q=b+2;

    则:

    ++二级从右向左运算

    q++表达式的值?,同时q指向了?----->(q++)--->20,b[3]

    ++q表达式的值?,同时q指向了?----->(++q)---->15,b[3]

    (q)++表达式的值?同时q指向了?21,b[2]

    ++(q)表达式的值?同时q指向了?21,b[2]

    例:

    举例指针在数组中的使用:

    main()

    {int*p,a[3],I;

    p=a;

    for(i=0:i<3;i++) //for(i=0;i<3;i++)

    scnaf("%d",p++); // scanf("%d",&a[i]);

    printf("\n\n");

    for(p=&a[0];p

    printf("%d",*p++); //printf("%d",a[i]);

    }

    (4)若两个指针变量指向同一个数组,则这两个指针变量可以进行大小比较如:

    char s[10];charpl=s+3,p2=&s[7];

    则:

    pl>p2=>0 pl1

    p1-p2=>-4 p2-p1=>4

    (5)在形参中的数组实际上是一个指针变量,并不是真正的数组,因为该“数组名”的值是可以改变的,而真正的数组名的值是不能改变的。

    (6)若形参是数组或指针变量,则在函数中可以通过该形参改变实参的值

    三、多维数组与指针变量

    如:int a[3][4];

    a+1是跳过一行。因为二维数组名是行指针,加1是跳过一行不是一个元素切记:

    ①只有列指针才是“真正”指向元素。即指向某一个元素的存储单元

    ②一维数组名表示的是列指针;二维数组名表示的是行指针。

    注:若a是一个二维数组,则有:

    (1)a+i是行指针,即指向的是一整行。若对它加1则指向下一行

    (2)*(a+i)和a[i]一样,都是一个列指针即指向的是一个元素,

    (3)*(a+i)+j和a[i]+j一样,都表示元素a[i][j]的地址。即与&a[i][j]等价

    *(a+i)+j a[i]+j &a[i][j]地址三等价

    (4)*(*(a+i)+j)、*(a[]j)、(*(a+i))[j]和a[i][j]一样,都表示(元素四等价)

    若有以下定义:

    int w[2][3];

    则对w数组元素非法引用是:E

    A、*(w[0]+2)B、*(w+1)[2]C、w[0][0]D、*(w[1]+2)E、w[l]+2

    1、指向多维数组元素的指针变量

    如:

    int a[31[4];

    int*p=&a[0][3];

    则:

    p+1指向元素a[1][0];

    p+4指向元素a[1][3]

    p-2指向元素a[0][1]

    常用于取二维数组a元素地址的方式:

    &a[i][j]、a[i]+j、*(a+i)+j

    例:

    main()

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

    for(p=a[0];p

    展开全文
  • C语言中指针和数组是否相等?简短的答案:不相等。详细的答案:这依赖于如何定义“相等”。指针运算和数组下标是相等的,其他方面指针和数组是不同的。一简单的例子展示相等性:#include int main(){char arr[] = ...

    这是一个简单的问题,但总是被忽略。特此翻译了一篇博客,讲的很清楚。这里是博客的原地址Are pointers and arrays equivalent in C?

    C语言中指针和数组是否相等?

    简短的答案:不相等。

    详细的答案:这依赖于如何定义“相等”。指针运算和数组下标是相等的,其他方面指针和数组是不同的。

    一个简单的例子展示相等性:

    #include

    int main()

    {

    char arr[] = "don't panic\n";

    char* ptr = arr;

    printf("%c %c\n", arr[4], ptr[4]);

    printf("%c %c\n", *(arr+2), *(ptr+2));

    return 0;

    }

    输出结果:

    t t

    n n

    注意到下标在数组和指针中都能工作,相似地,指针运算在数组和指针中都能用。

    他们如何是不同的?

    在一个很重要和基本的方式中,考虑如下代码:

    char array_place[100] = "dont't panic";

    char* ptr_place = "don't panic";

    int main()

    {

    char a = array_place[7];

    char b = ptr_place[7];

    return 0;

    }

    给a赋值时发生了什么?与给b赋值有什么不同?看一下编译器的分解是有用的:

    (Visual C++ 2005,x86,Windows XP)

    char a = array_place[7];

    0041137E mov al,byte ptr [_array_place+7 (417007h)]

    00411383 mov byte ptr [a],al

    char b = ptr_place[7];

    00411386 mov eax,dword ptr [_ptr_place (417064h)]

    0041138B mov cl,byte ptr [eax+7]

    0041138E mov byte ptr [b],cl

    C语言中数组的语义指示数组名作为数组第一个元素的地址。因此,在给a赋值的过程中,数组的第8个字符被偏移为array_place[7]的值,移动结果地址的内容到寄存器al,然后再赋给a。

    另一方面,指针的语义是十分不同的。指针仅仅是一个固定值,持有另一个内部变量的地址。因此,计算字符串第8个字符的偏移,CPU首先复制指针的值给一个寄存器,然后增加寄存器。这多出一个指令。

    一个图形化的解释

    c23060156383

    右边那一列是内存地址,每个格子是内存中存储的内容。如图展示的是array_place的第一个单词。

    注意到array_place是内存地址0x417000的一个简单标签,因此访问array_place[7]就是访问内存地址0x417007。如我们所看到的,编译器仅仅用0x417007代替array_place[7],不需要地址的计算。

    而指针的工作方式是不同的:

    c23060156383

    ptr_place仅仅是一个变量,变量的值是一个地址。这个地址是一个字符串所在内存位置的第一个字符的地址,比较访问pointer_place[7]的分解列表能够很清楚理解编译为何如此生成编码。

    C语言的变量名仅仅是一个标签

    没有黑过编译器的程序员经常忽视指针,C语言的变量仅仅是内存空间的一个方便的数字字母组成的笔名。如果我们正在写代码,我们应该仅仅创建内存空间的标签,然后访问这些标签,代替硬编码内存值,后者是由编译器来做的。

    实际上地址不是绝对的硬编码,因为存在载入和重分配。但这在我们的讨论之外,这里就不展开细节了。

    标签是编译器在编译时分配的,从这里我们可以看出指针和数组的巨大不同。

    在函数参数中数组被转换成指针

    先看一段代码:

    void foo(char arr_arg[], char* ptr_arg)

    {

    char a = arr_arg[7];

    char b = ptr_arg[7];

    }

    问题:在这里访问a和b有什么不同吗?

    回答:一点也没有!

    这是编译器的展开:

    char a = arr_arg[7];

    00412DCE mov eax,dword ptr [arr_arg]

    00412DD1 mov cl,byte ptr [eax+7]

    00412DD4 mov byte ptr [a],cl

    char b = ptr_arg[7];

    00412DD7 mov eax,dword ptr [ptr_arg]

    00412DDA mov cl,byte ptr [eax+7]

    00412DDD mov byte ptr [b],cl

    这是因为数组在函数的参数中总是倍转换成指针。

    char arr_place[]的参数声明仅仅是char* arr_place的语法糖。

    这里引用K&R2:

    当数组名作为函数参数时,仅仅是初始化元素的位置。在调用函数时,参数是一个局部变量,数组名就是一个指针,一个存储内容为内存地址的变量。

    如果这看起来很奇怪,再仔细想一想。回想一下前面的图。编译器在这里别无选择,数组名作为一个标签在编译时代替要表示的地址。但一个函数在编译时并没有调用,仅在运行时调用,此时在栈中倍看做是一个参数。编译器不能处理数组内部引用作为标签和把他们替换成地址,因为它不知道实际上数组在运行时传入什么。

    展开全文
  • 主要介绍了在C语言中比较两个字符串是否相等的方法,分别介绍了strcmp()函数和strcasecmp()函数,注意功能区分,需要的朋友可以参考下
  • 深入理解C语言指针

    万次阅读 多人点赞 2019-09-28 08:36:51
    一、指针的概念 要知道指针的概念,要先了解变量在内存如何存储的。在存储时,内存被分为一块一块的。...这段代码非常简单,就是两个变量的声明,分别赋值了 10、20。我们把内存当做一个酒店,而每个房间就...

    一、指针的概念

    要知道指针的概念,要先了解变量在内存中如何存储的。在存储时,内存被分为一块一块的。每一块都有一个特有的编号。而这个编号可以暂时理解为指针,就像酒店的门牌号一样。

    1.1、变量和地址

    先写一段简单的代码:

    void main(){
    	int x = 10, int y = 20;
    }
    

    这段代码非常简单,就是两个变量的声明,分别赋值了 10、20。我们把内存当做一个酒店,而每个房间就是一块内存。那么“int x = 10;”和“int y = 20;”的实际含义如下:

    1. 去酒店订了两个房间,门牌号暂时用 px、py 表示
    2. 让 10 住进 px,让 20 住进 py
    3. 其中门牌号就是 px、py 就是变量的地址
    4. x 和 y 在这里可以理解为具体的房间,房间 x 的门牌号(地址)是 px,房间 y 的门牌号(地址)是 py。而 10 和 20,通过 px、py 两个门牌,找到房间,住进 x、y。用户(变量的值)和房间(变量)以及房间号(指针、地址)的关系

    1.2、指针变量和指针的类型

    指针变量就是一个变量,它存储的内容是一个指针。如果用前面的例子,可以理解为指针变量就是一张房卡,房卡存储了房间号的信息。

    在我们定义一个变量的时候,要确定它的类型。int x、char ch、float、、、在定义指针变量时也是一样的,必须确定指针类型。int 变量的指针需要用 int 类型的指针存储,float 变量的指针需要用 float 类型的指针存储。就像你只能用酒店 A 的房卡存储酒店 A 中房间号的信息一样。

    二、变量的指针与指针变量

    变量的指针就是变量的存储地址,指针变量就是存储指针的变量。

    2.1、指针变量的定义及使用

    (1)指针变量的定义

    指针变量的定义形式如:数据类型 *指针名;例如:

    //分别定义了 int、float、char 类型的指针变量
    int *x;
    float *f;
    char *ch;
    

    如上面的定义,指针变量名为 x、f、ch。并不是*x、*f、*ch

    (2)指针变量的使用

    • 取地址运算符&:单目运算符&是用来取操作对象的地址。例:&i 为取变量 i 的地址。对于常量表达式、寄存器变量不能取地址(因为它们存储在存储器中,没有地址)。
    • 指针运算符*(间接寻址符):与&为逆运算,作用是通过操作对象的地址,获取存储的内容。例:x = &i,x 为 i 的地址,*x 则为通过 i 的地址,获取 i 的内容。

    代码示例:

    //声明了一个普通变量 a
    int a;
    //声明一个指针变量,指向变量 a 的地址
    int *pa;
    //通过取地址符&,获取 a 的地址,赋值给指针变量
    pa = &a;
    //通过间接寻址符,获取指针指向的内容
    printf("%d", *pa);
    

    (3)“&”和“*”的结合方向

    “&”和“*”都是右结合的。假设有变量 x = 10,则*&x 的含义是,先获取变量 x 的地址,再获取地址中的内容。因为“&”和“*”互为逆运算,所以 x = *&x。

    接下来做个小练习,输入 x、y 两个整数,然后将其中的值大的赋值给 x,小的赋值给 y。即:假设输入 x = 8,y = 9。就将 9 赋值给 x,8 赋值给 y。

    void main(){
    	//声明两个普通变量
    	int x, y;
    	//声明两个指针变量
    	int *px, *py;
    	//声明一个临时变量,用于交换
    	int t;
    	//输入两个值,赋值给 x、y
    	scanf("%d", &x);
    	scanf("%d", &y);
    	//给指针变量 px、py 赋初值(关联变量 x、y)
    	px = &x;
    	py = &y;
    	//利用指针来对比 x、y 的值,如果 x 的值比 y 的值小,就交换
    	if(*px < *py){
    		//交换步骤,其中*px == x、*py == y
    		t = *px;
    		*px = *py;
    		*py = t;
    	}
    	printf("x =  %d, y = %d", *px, *py);
    }
    
    输入:23 45
    输出结果为:x = 45, y = 23
    

    2.2、指针变量的初始化

    指针变量与其它变量一样,在定义时可以赋值,即初始化。也可以赋值“NULL”或“0”,如果赋值“0”,此时的“0”含义并不是数字“0”,而是 NULL 的字符码值。

    //利用取地址获取 x 的地址,在指针变量 px 定义时,赋值给 px
    int x;
    int *px = &x;
    //定义指针变量,分别赋值“NULL”和“0”
    int *p1= NULL, *p2 = 0;
    

    2.3、指针运算

    (1)赋值运算

    指针变量可以互相赋值,也可以赋值某个变量的地址,或者赋值一个具体的地址

    int *px, *py, *pz, x = 10;
    //赋予某个变量的地址
    px = &x;
    //相互赋值
    py = px;
    //赋值具体的地址
    pz = 4000;
    

    (2)指针与整数的加减运算

    1. 指针变量的自增自减运算。指针加 1 或减 1 运算,表示指针向前或向后移动一个单元(不同类型的指针,单元长度不同)。这个在数组中非常常用。
    2. 指针变量加上或减去一个整形数。和第一条类似,具体加几就是向前移动几个单元,减几就是向后移动几个单元。
    //定义三个变量,假设它们地址为连续的,分别为 4000、4004、4008
    int x, y, z;
    
    //定义一个指针,指向 x
    int *px = &x;
    
    //利用指针变量 px 加减整数,分别输出 x、y、z
    printf("x = %d", *px);		//因为 px 指向 x,所以*px = x
    
    //px + 1,表示,向前移动一个单元(从 4000 到 4004)
    //这里要先(px + 1),再*(px + 1)获取内容,因为单目运算符“*”优先级高于双目运算符“+”
    printf("y = %d", *(px + 1));		
    printf("z = %d", *(px + 2));
    

    (3)关系运算

    假设有指针变量 px、py。

    1. px > py 表示 px 指向的存储地址是否大于 py 指向的地址
    2. px == py 表示 px 和 py 是否指向同一个存储单元
    3. px == 0 和 px != 0 表示 px 是否为空指针
    //定义一个数组,数组中相邻元素地址间隔一个单元
    int num[2] = {1, 3};
    
    //将数组中第一个元素地址和第二个元素的地址赋值给 px、py
    int *px = &num[0], *py = &num[1];
    int *pz = &num[0];
    int *pn;
    
    //则 py > px
    if(py > px){
    	printf("py 指向的存储地址大于 px 所指向的存储地址");
    }
    
    //pz 和 px 都指向 num[0]
    if(pz == px){
    	printf("px 和 pz 指向同一个地址");
    }
    
    //pn 没有初始化
    if(pn == NULL || pn == 0){
    	printf("pn 是一个空指针");
    }
    

    三、指针与数组

    之前我们可以通过下标访问数组元素,学习了指针之后,我们可以通过指针访问数组的元素。在数组中,数组名即为该数组的首地址,结合上面指针和整数的加减,我们就可以实现指针访问数组元素。

    3.1、指向数组的指针

    如以下语句:

    int nums[10], *p;
    

    上面语句定义了一个数组 nums,在定义时分配了 10 个连续的int 内存空间。而一个数组的首地址即为数组名nums,或者第一个元素的首地址也是数组的首地址。那么有两种方式让指针变量 p 指向数组 nums:

    //数组名即为数组的首地址
    p = nums;
    //数组第一个元素的地址也是数组的首地址
    p = &nums[0];
    

    上面两句是等价的。
    如下几个操作,用指针操作数组:

    1. *p = 1,此操作为赋值操作,即将指针指向的存储空间赋值为 1。此时 p 指向数组 nums 的第一个元素,则此操作将 nums 第一个元素赋值为 0,即 nums[0] = 1。
    2. p + 1,此操作为指针加整数操作,即向前移动一个单元。此时 p + 1 指向 nums[0]的下一个元素,即 nums[1]。通过p + 整数可以移动到想要操作的元素(此整数可以为负数)。
    3. 如上面,p(p + 0)指向 nums[0]、p + 1 指向 nums[1]、、、类推可得,p+i 指向 nums[i],由此可以准确操作指定位置的元素。
    4. 在 p + 整数的操作要考虑边界的问题,如一个数组长度为 2,p+3 的意义对于数组操作来说没有意义。

    下面写一段代码,用指针访问数组的元素:

    //定义一个整形数组,并初始化
    int nums[5] = {4, 5, 3, 2, 7};
    
    //定义一个指针变量 p,将数组 nums 的首地址赋值给 p,也可以用p = &nums[0]赋值
    int *p = nums, i;			//i 作为循环变量
    
    //p 指向数组第一个元素(数组首地址),我们可以直接用间接寻址符,获取第一个元素的内容
    printf("nums[0] = %d\n", *p);			//输出结果为 nums[0] = 4
    
    //我们可以通过“p + 整数”来移动指针,要先移动地址,所以 p + 1 要扩起来
    printf("nums[1] = %d\n", *(p + 1));		//输出结果为 nums[1] = 5
    
    //由上面推导出*(p + i) = nums[i],所以我们可以通过 for 循环变量元素
    for(i = 0; i < 5; i++){
    	printf("nums[%d] = %d", i, *(p + i));
    }
    

    注:数组名不等价于指针变量,指针变量可以进行 p++和&操作,而这些操作对于数组名是非法的。数组名在编译时是确定的,在程序运行期间算一个常量。

    3.2、字符指针与字符数组

    在 C 语言中本身没有提供字符串数据类型,但是可以通过字符数组和字符指针的方式存储字符串。

    (1)字符数组方式

    这个在前面应该学习过,这里就不赘述了。

    char word[] = "zack";
    printf("%s", word);
    

    (2)字符指针方式

    指针方式操作字符串和数组操作字符串类似,可以把定义的指针看做是字符数组的数组名。在内存中存储大致如下,这里为了方便换了个字符串:在这里插入图片描述

    //除了定义一个字符数组外,还可以直接定义一个字符指针存储字符串
    char *sentence = "Do not go gentle into that good night!";
    
    //此时可以做字符串的操作
    //输出
    printf("%s", sentence);
    
    //通过下标取字符
    printf("%c", sentence[0]);
    
    //获取字符串长度,其中 strlen 是 string.h 库中的方法
    printf("%d", strlen(sentence));
    

    注:字符指针方式区别于字符数组方式,字符数组不能通过数组名自增操作,但是字符指针是指针,可以自增操作。自增自减少会实现什么效果大家可以自己尝试运行一下

    下面做个小练习,利用字符指针将字符数组 sentence 中的内容复制到字符数组 word 中:

    //定义字符数组 sentence 和 word,给 sentence 赋初值
    char sentence[] = "Do not go gentle into that good night!", word[100];
    
    //定义字符指针,指向 word
    char *ch = word;
    int i;
    
    //循环赋值
    for(i = 0; sentence[i] != '\0'; i++){
    	*(ch + i) = sentence[i];
    }
    
    //在当 i 等于 sentence 的长度(sentence 的长度不包含'\0')时,
    //i 继续自增,此时判断 sentence[0] != '\0'不符合,跳出循环,则 i 比 sentence 长度大 1
    *(ch + i) = '\0';
    
    //输出字符串,因为 ch 指向 word,所以输出结果是一样的
    printf("ch = %s, word = %s", ch, word);
    

    注:指针变量必须初始化一个有效值才能使用

    3.3、多级指针及指针数组

    (1)多级指针

    指针变量作为一个变量也有自己的存储地址,而指向指针变量的存储地址就被称为指针的指针,即二级指针。依次叠加,就形成了多级指针。我们先看看二级指针,它们关系如下:指针变量 p 指向变量 x,二级指针变量指向指针变量 p
    其中 p 为一级指针,pp 为二级指针。二级指针定义形式如下:

    数据类型 **二级指针名;
    

    和指针变量的定义类似,由于*是右结合的,所以*pp 相当于*(*p)。在本次定义中,二级指针的变量名为 pp,而不是**p。多级指针的定义就是定义时使用多个“*”号。下面用一个小程序给大家举例:

    //定义普通变量和指针变量
    int *pi, i = 10;
    //定义二级指针变量
    int **ppi;
    
    //给指针变量赋初值
    pi = &i;
    
    //给二级指针变量赋初值
    ppi = &pi;
    
    //我们可以直接用二级指针做普通指针的操作
    //获取 i 的内容
    printf("i = %d", **ppi);
    //获取 i 的地址
    printf("i 的地址为%d", *ppi);
    

    注:在初始化二级指针 ppi 时,不能直接 ppi = &&i,因为&i 获取的是一个具体的数值,而具体数字是没有指针的。

    (2)指针数组

    指针变量和普通变量一样,也能组成数组,指针数组的具体定义如下:

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

    下面举一个简单的例子熟悉指针数组:

    //定义一个数组
    int nums[5] = {2, 3, 4, 5, 2}, i;
    
    //定义一个指针数组
    int *p[5];
    
    //定义一个二级指针
    int **pp;
    
    //循环给指针数组赋值
    for(i = 0; i < 5; i++){
    	p[i] = &nums[i];
    }
    
    //将指针数组的首地址赋值给 pp,数组 p 的数组名作为 p 的首地址,也作为 p 中第一个元素的地址。
    //数组存放的内容为普通变量,则数组名为变量的指针;数组存放的内容为指针,则数组名为指针的指针。
    pp = p;
    
    //利用二级指针 pp 输出数组元素
    for(i = 0; i < 5; i++){
    	//pp == &p[0] == &&nums[0],nums[0] == *p[0] == **pp
    	printf("%d", **pp);
    	
    	//指针变量+整数的操作,即移动指针至下一个单元
    	pp++;
    }
    

    3.4、指针与多维数组

    讲多维数组是个麻烦的事,因为多维数组和二维数组没有本质的区别,但是复杂度倒是高了许多。这里我主要还是用二维数组来举例,但是还是会给大家分析多维数组和指针的关系。

    (1)多维数组的地址

    先用一个简单的数组来举例:

    int nums[2][2] = {
    	{1, 2},
    	{2, 3}
    };
    

    我们可以从两个维度来分析:

    1. 先是第一个维度,将数组当成一种数据类型 x,那么二维数组就可以当成一个元素为 x 的一维数组。
    2. 如上面的例子,将数组看成数据类型 x,那么 nums 就有两个元素。nums[0]和 nums[1]。
    3. 我们取 nums[0]分析。将 nums[0]看做一个整体,作为一个名称可以用 x1 替换。则 x1[0]就是 nums[0][0],其值为 1。
      在这里插入图片描述

    我们知道数组名即为数组首地址,上面的二维数组有两个维度。首先我们把按照上面 1 来理解,那么 nums 就是一个数组,则nums 就作为这个数组的首地址。第二个维度还是取 nums[0],我们把 nums[0]作为一个名称,其中有两个元素。我们可以尝试以下语句:

    printf("%d", nums[0]);
    

    此语句的输出结果为一个指针,在实验过后,发现就是 nums[0][0]的地址。即数组第一个元素的地址。

    如果再多一个维度,我们可以把二维数组看做一种数据类型 y,而三维数组就是一个变量为 y 的一维数组。而数组的地址我们要先确定是在哪个维度,再将数组某些维度看成一个整体,作为名称,此名称就是该维度的地址(这里有些绕)。

    例:

    //假设已初始化,二维数组数据类型设为 x,一维数组数据类型设为 y
    int nums[2][2][2];
    
    //此数组首地址为该数组名称
    printf("此数组首地址为%d", nums);
    
    //此数组可以看做存储了两个 x 类型元素的一维数组,则 nums[0] = x1 的地址为
    printf("第二个维度的首地址为%d", nums[0]);
    
    //而 x1 可以看做存储了两个 y 类型元素的一维数组,则 y1 = x1[0] = nums[0][0]
    printf("第三个维度的首地址为%d", nums[0][0]);
    
    

    三维数组实际存储形式如下:
    在这里插入图片描述
    实际存储内容的为最内层维度,且为连续的。对于 a 来说,其个跨度为 4 个单元;对 a[0]来说,其跨度为 2 个单元;对 a[0][0]来说,跨度为一个单元。有上面还可以得出:

    a == a[0] == a[0][0] == &a[0][0][0];
    

    上面的等式只是数值上相等,性质不同。

    (2)多维数组的指针

    在学习指针与数组的时候,我们可以如下表示一个数组:

    int nums[5] = {2, 4, 5, 6, 7};
    int *p = nums;
    

    在前面讲指针数组时,所有指针数组元素都指向一个数字,那么我们现在可以尝试用指针数组的每个元素指向一个数组:

    //定义一个二维数组
    int nums[2][2] = {
    	{1, 2},
    	{2, 3}
    };
    
    //此时 nums[0]、和 nums[1]各为一个数组
    int *p[2] = {nums[0], nums[1]};
    
    //我们可以用指针数组 p 操作一个二维数组
    
    //p 为数组 p 的首地址,p[0] = nums[0] = *p,**p = nums[0][0]
    printf("nums[0][0] = %d", **p);
    
    //指针 + 整数形式,p+1 移动到 nums 的地址,*(p +1) = nums[1],则**(p + 1) = nums[1][0]
    printf("nums[1][0] = %d", **(p + 1));
    
    //先*p = nums[0],再*p + 1 = &nums[0][1],最后获取内容*(*p + 1)即为 nums[0][1]
    printf("nums[0][1] = %d", *(*p + 1));
    

    这里可能不能理解为什么*p + 1 = &nums[0][1],而不是 nums[1]。*p 获得的是一个一维数组,而 int 数组 + 1 的跨度只有 4 个字节,也就是一个单元。前面 p 是一维数组的指针,其跨度为一个数组。所以*p + 1 = &nums[0][1],而 p + 1 = nums[1]。

    四、指针与函数

    前面学习函数学到,函数参数可以为 int、char、float 等,但是在操作时,这些参数只作为形参,所有操作都只在函数体内有效(除对指针的操作外),那么今天来学习一下指针作为函数参数。

    4.1、函数参数为指针

    我们直接做一个练习,定义一个函数,用来交换两个变量的内容。

    void swap(int *x, int *y);
    void main(){
    	int x = 20, y = 10;
    	swap(&x, &y);
    	printf("x = %d, y = %d", x ,y);
    }
    void swap(int *x, int *y){
    	int t;
    	t = *x;
    	*x = *y;
    	*y = t;
    }
    

    代码非常简单,我也就不细讲了。这里传入的参数为指针,所以调用 swap 方法后 x,y 的内容发生了交换。如果直接传入 x,y,那么交换只在 swap 中有效,在 main 中并没有交换。

    4.2、函数的返回值为指针

    返回值为指针的函数声明如下:

    数据类型 *函数名(参数列表){
    	函数体
    }
    //例如:
    int s;
    int *sum(int x, int y){
    	s = x + y;
    	return &s;
    }
    

    在函数调用前要声明需要对函数声明(有点编译器不需要)

    int s;
    void mian(){
    	int *r = sum(10, 9);
    	printf("10 + 9 + %d", *r);
    }
    int *sum(int x, int y){
    	s = x + y;
    	return &s;
    }
    

    除了上面的操作,更实用的是返回一个指向数组的指针,这样就实现了返回值为数组。

    4.3、指向函数的指针

    C 语言中,函数不能嵌套定义,也不能将函数作为参数传递。但是函数有个特性,即函数名为该函数的入口地址。我们可以定义一个指针指向该地址,将指针作为参数传递。

    函数指针定义如下:

    数据类型 (*函数指针名)();
    

    函数指针在进行“*”操作时,可以理解为执行该函数。函数指针不同与数据指针,不能进行+整数操作。

    下面举个例子,来使用函数指针:

    #include <string.h>
    /**
    *	定义一个方法,传入两个字符串和一个函数指针 p,用 p 对两个字符串进行操作
    */
    void check(char *x, char *y, int (*p)());
    void main(){
    	//string.h 库中的函数,使用之前需要声明该函数。字符串比较函数
    	int strcmp();
    	char x[] = "Zack";
    	char y[] = "Rudy";
    	
    	//定义一个函数指针
    	int (*p)() = strcmp;
    
    	check(x, y, p);
    }
    void check(char *x, char *y, int (*p)()){
    	if(!(*p)(x, y)){
    		printf("相等");
    	}else{
    		printf("不相等");
    	}
    }
    

    利用函数指针调用方法具体操作如下:

    (*p)(x, y);
    

    指针除了这些地方,还在结构体中用处巨大。今天就先讲到这里~·

    展开全文
  • 在一函数内部,声明指针变量 char *p1 = "abc"; char *p2 = "abc"; cout(p1 == p2); 输出结果是什么?求大神解释。谢谢
  • C语言中两个相同类型的结构体变量之间是可以相互直接赋值的 C语言中,在相同类型的变量间赋值时是直接内存复制的,即将他们的内存进行复制,而两个同类型的结构体变量属于同一种变量,所以赋值时是按照他们的内存分布来...
  • 运用指针,子函数,比较两个字符串是否相等相等返回1,否则返回0.求修改#include #include #include char bijiao(char a[21],char b[21]);//需要编写一个子函数可以用指针直接指向一个字符串吗?int n;main(){char...
  • 使用指针来判断两个字符串是否相等 cout请分别输入两个字符串str1和str2:"; cin.getline(str1,100); cin.getline(str2,100);
  • c语言指针比较辨析

    万次阅读 2020-04-13 09:29:13
    指针比较只对相同对象才有意义:如果两个指针指向同一个简单对象,则相等;如果指针指向同一个结构的不同成员,则指向结构后声明的成员的指针较大;如果指针指向同一个联合的不同成 员,则相等;如果指针指向一个...
  • C语言之数组指针指针数组

    千次阅读 2021-10-20 22:57:41
    为了说明这个概念,请考虑下面两个声明: int a[10]; int *b; 声明一个数组时,编译器根据声明所指定的元素数量为数组分配内存空间,然后再创建数组名,指向这段空间的起始位置。声明一个指针变量的时候,编译器只...
  • C语言中指针运算

    2021-05-21 01:48:00
    本文介绍了C语言中指针常量和指针变量的运算规则,以及对数组的访问。Abstract: The pointer is the essence, focus and difficult of C language which is also the basis of C language Series. This article ...
  • 指向同一数组的两个指针变量 相减 表示 相差元素个数,可以 比较 地址编号大小,两个指针变量不能相加 指针变量加一个数表示 跳过(指针变量类型的字节数)*(这个数)的字节数 数组名[ 不越界的情况下可以为复负数 ],...
  • 怎么避免两个指向同一个地址的多次释放问题本帖最后由 wallwind 于 2014-03-05 20:44:48 编辑比如以下代码#include#includeintmain(){int*ptr=malloc(10*sizeof(int));int*ptr2=ptr;if(ptr){free(ptr);ptr=NULL;...
  • C语言高级-指针

    千次阅读 2022-03-12 21:34:14
    第二步:给指针变量赋值,也就是让指针指向另一个变量,当我们没有指定指针变量之前,这个指针不能被解引用; p=&a //实现指针绑定,让p指向变量a p=(int *)4 //实现指针绑定,让p指向地址为4的哪个变量 第...
  • c语言中输出字符指针相关问题

    万次阅读 多人点赞 2017-05-01 01:41:21
    首先搞清楚在c语言中没有字符串的类型,所以对字符串操作,有种形式:可以用字符指针(为什么不叫字符串指针,我个人觉得,字符指针针对的是单个字符的操作,即指针操作,所以就叫它字符指针吧。。。),或者字符串...
  • 分析题目说到的数组一样大,那么也就是说数组元素的个数和类型相等,那么要达到交换这两个数组,仅需将其每一位对应的元素进行交换即可,这样也就达到了交换数组的效果。 第一步: 先构造一个能将两个数交换...
  • 在实际开发的时候有时需要比较文件是否相同,生成md5摘要比较固然是比较好的方法,有时只是需要写简单的测试程序,在c语言引入md5库就有点麻烦了,直接比对文件内容可能比较耗时但是准确性还是可以保证的。
  •   刚开始了解指针是从交换两个变量开始,但是总是断断续续地学,每次都在看交换两个变量的函数,上周在课上正式学了指针,看的时候感觉懂了,但是一上机就不知道指针怎么用、参数怎么传。于是想整理一下指针的学习...
  • 合并两个有序数组(Merge-Sorted-Array)题干:给你两个有序整数数组 nums1 和 nums2,请你将 nums2 合并到 nums1 ,使 nums1 成为一个有序数组。说明:初始化 nums1 和 nums2 的元素数量分别为 m 和 n 。你可以...
  • //方法三:利用位运算 (当*x和*y相等时,此方法不可用) void inplace_swap3(int *x, int *y) { *y = *x^*y; *x = *x^*y; *y = *x^*y; } int main() { int a = 6; int b = 9; printf("交换之前的a:%d,b:%d\n",...
  • C语言指针知识点小结

    万次阅读 多人点赞 2020-01-10 15:40:06
      C语言指针基础知识点(一)–指针指针变量   C语言指针基础知识点(二)–指针变量的引用   C语言指针基础知识点(三)–指针变量作为函数参数   C语言指针基础知识点(四)–通过指针引用数组   C语言指针...
  • 教你准确判断两个结构体是否相等

    多人点赞 热门讨论 2022-03-08 13:24:13
    文章目录系列文章目录前言一、判断两个结构体是否相等 前言 一、判断两个结构体是否相等 判断两个结构体是否相等:重载操作符"=="。 不能用函数memcpy来判断两个结构体是否相等:memcmp函数是逐个字节进行比较的...
  • 关于C语言中指针含义的详细解析

    千次阅读 2020-05-08 19:53:27
    C语言里,变量存放在内存,而内存其实就是一组有序字节组成的数组,每字节有唯一的内存地址。CPU 通过内存寻址对存储在内存的某个指定数据对象的地址进行定位。这里,数据对象是指存储在内存的一指定数据...
  • 来自公众号:strongerHuang素材来源:网络有很多工程师喜欢自己封装一些标准库已有的...下面就来分享一下C语言常见的一些标准库。标准头文件包括: 一、标准定义()文件里包含了标准库的一些常用定义,无论我们包含...
  • C语言结构体指针强转

    千次阅读 2022-02-07 14:25:05
    C语言中结构体无法进行强转,但是结构体指针是可以进行间接强转的 eg: 先定义4结构体 typedef struct { int array[4]; }Struct_A; typedef struct { int *ptr_b; } Struct_B; typedef struct { int int1; ...
  • 语言当比较两个对象时,必须要考虑“相等”的含义是什么,必须区分指针相等和相等性,指针相等很容易。如果现两个对象都指向相同的内存位置,则这个网对象的相等的。这里不难理解相等性,就是两个不同的对象,但是...
  • C语言指针值传递和地址传递

    千次阅读 2020-07-05 21:08:32
    C语言指针传参时,可以通过指针引用方式改变指针指向的值。改变变量,可以使用指针应用方式,改变地址,使用指针指针引用方式。 C语言值传递: 形参是实参的拷贝,改变形参的值并不会影响外部实参的值。从被调用...

空空如也

空空如也

1 2 3 4 5 ... 20
收藏数 37,054
精华内容 14,821
关键字:

c语言中两个指针相等