Skip to main content

moregeek program

指针详解(1)_wx6332fcf60e81c的博客-多极客编程

1.含义:变量的地址叫做指针,指针就是地址。

2.指针变量

1)。不管是个什么东西,首先它是1个变量.

指针变量就是专门用来存储地址的变量,专门用来存储另外1个变量的地址的。

那么我们就说这个指针变量指向了另外1个变量,

2)。这么做的好处

访问1个变量的方式主要分为两种,

a.直接访问。

int num = 10;

num =20;// 直接访问这个num变量

b.间接访问

可以通过指针变量找到这个指针变量指向的变量,通过指针变量就可以间接的访问这个指向的变量。

3).如何声明1个专门用来存储地址的指针变量

a,我们之前学习的普通变量是如何声明的?

数据类型变量名;int num;

b,声明指针变量的语法

数据类型*指针变量的名称; int* p1;

代表声明了1个指针变量。这个指针变量的名字叫做p1.这个指针变量的类型是int* 读作int指针。

这个*代表 这个变量不是1个普通变量,而是1个专门用来存储地址的指针变量。

c.声明的时候注意。

*的位置 可以与数据类型挨在一起,也可以和指针变量名挨在一起,也可以单独写中间,

int* p1; int *p1; int * p1;

d,指针变量是用来存储另外1个变量的地址。

但是1个指针变量并不是 可以存储 任意类型的变量的地址。而是有限定的。只能存储和这个指针类型相同的 普通变量的地址。

int* p1;p1变量中只能存储int变量的地址。

double* p2;p2变量中只能存储double类型的变量的地址。

float* p3;p3变量中只能存储float变量的地址。

char* p4;p4变量中只能存储char变量的地址。

否则会出现问题!!!

3.指针变量的初始化

1),指针变量是用来存储另外1个变量的地址的。

-> 所以,我们不能直接赋值1个非地址类型的常量数据。

所以,我们也不可以直接赋值1个变量给指针。

所以,指针变量是来存储地址的,不是来存储这些东西的。


2)。指针是用来存储另外1个变量的地址。并且指针可以存储的另外1个变量的地址 这个变量的类型是限定的。


3),正确的初始化步骤

a.先取出变量的地址。

好简单,使用&取地址运算符就可以取出变量的地址。要打印地址,使用格式控制符

b,将取出来的变量的地址赋值给指针变量,

int num = 10;

int* p1 = #

这个时候,p1指针变量的值就是num变量的地址。那么我们就说p1指针指向了num变量。

4),指针变量只能存储和指针变量类型相同的普通变量的地址,否则就会出问题,起码我们现在看到在编译的时候回报1个大警告。

指针详解(1)_赋值

5),如果直接写变量名.操作的就是这个变量,你可以为这个变量赋值或者取值。

&变量名;其实这个是1个表达式。

&是1个运算符 叫做取地址运算符。这个表达式的结果 是这个变量的地址。

6),指针变量在内存中也有1个地址,因为指针变量也是1个变量嘛。

所以,我们也可以使用&符号取出指针变量的地址。

int* p1;

p1 操作的是p1这个指针变量,可以取p1的值 也可以为p1赋值。&p1 拿到的是p1的地址。

4.指针变量的使用。

1),指针变量中存储的是另外1个普通变量的地址。

这么做的好处:在于可以使用指针间接的操作指针指向的变量。

2). Pointer.建议大家在声明指针变量的时候以p开头。

3).操作变量的方式

a. 直接访问。

int num =10; num = 20;

直接操作这个变量。

b.间接访问.

当1个指针指向了另外1个变量的时候那么就可以通过指针来间接的操作这个变量,操作1个变量就两种形式:赋值、取值。

4),使用指针间接的操作指针指向的变量。

格式:*指针变量名; 代表这个指针指向的变量。

int num = 10; int* p1 = #

*p1代表p1指针指向的变量,也就是num

*p1 完全等价于 num

*p1 = 100;

将100赋值给p1指针指向的变量,也就是num变量。

这个时候可以通过这种方式间接的去 为指针指向的变量赋值或者取值。

*指针变量名; 这个表达式的结果是指针指向的变量,拿到看指针指向的变量,

就可以为指针指向的变量赋值或者取值。

指针详解(1)_指针变量_02

5).注意.

*指针变量 就完全代表指针指向的变量。

所以通过这种方式为指针指向的变量赋值的时候 数据类型不同的时候

5.使用指针变量的时候注意的问题。

1),指针变量也是1个变量,所以可以批量声明指针变量。

int* p1,p2,p3;

这样声明的话,只有p1是int指针,p2 和 p3 是int类型的。

如果希望全部都是指针。

int* p1, *p2, *p3;

2).野指针。

我们声明1个指针变量,如果没有为其初始化。

那么这个时候这个指针变量中是有值的。垃圾值。随机数这个时候,这个指针变量就有可能指向了1块随机的空间。

这块空间: 有可能无人使用。有可能别的程序在用。有可能系统在用。

这个时候,去访问指针指向的变量的时候,就会报错。BAD ACCESS错误

像这样的指针我们就叫做野指针。

3),NULL值。

我们声明1个指针,如果不初始化这个指针,这个指针就是1个野指针就指向了1块随机的空间。那么这个时候 如果你通过这个指针访问指针指向的随机的空间的时候,是相当危险的,

如果是取值还罢了,如果赋值就相当危险,就可能会造成别的程序崩溃,

所以,我们建议大家。声明1个指针变量以后,最好为其初始化。如果你没有变量的地址初始化给这个指针变量,那你就初始化1个NULL值,

NULL值代表指针变量不指向内存中的任何地址。谁都不指,这个NULL完全等价于0.

所以,你也可以直接赋值给1个指针变量0

如果1个指针变量的值是NULL值。这个时候通过指针变量去访问指向的变量的时候100%报错。

4)。多个指针指向同一向量


#include<stdio.h>

int main()

{

int num = 10;

//先将num的地址赋给指针p1

int* p1 = &num;

//然后将p1值赋给p2

int* p2 = p1;//这时指针p1中的地址赋给了p2

//所以p1,p2都指向num变量

printf("%p\n", p1);
printf("%p\n", p2);
return 0;
}

指针详解(1)_数组_03

#include<stdio.h>

int main()

{

int num = 10;

//先将num的地址赋给指针p1

int* p1 = &num;

//然后将p1值赋给p2

int* p2 = p1;//这时指针p1中的地址赋给了p2

//所以p1,p2都指向num变量

//利用指针重新给num赋值

*p1 = 200;//然而这样p2的值也是200

printf("%d\n", *p1);

printf("%d\n", *p2);

return 0;

}

指针详解(1)_数组_04

6.指针作为函数的参数

1)。先回顾一下函数

当函数的参数的类型是int char double float的时候。

这个时候参数传递是值传递。在函数的内部去修改形参变量的值,对实参变量没有丝毫的影响。

当函数的参数的类型是数组的时候,这个时候参数传递是地址传递。

在函数内部修改参数数组的元素的时候,其实修改的就是实参数组的元素。

2)。.指针是一种新的数据类型。

a指针完全当然可以作为函数的参数,因为指针也是1个数据类型。

直接将指针的声明放在小括弧中,

b当我们调用1个函数的时候,如果这个函数的参数是1个指针。

那么我们就必须要为这个指针传递1个和指针类型相同的普通变量的地址。

c 这个时候,在函数的内部去访问参数指针指向的变量的时候,其实访问的就是实参变量。

3)。指针作为函数的参数,可以实现什么效果?

函数的内部可以修改实参变量的值。


4)。什么时候需要将指针作为函数的参数?

a遇到的问题。

函数只能返回1个数据。

如果函数需要返回多个数据怎么办?

b解决方案。

使用指针作为函数的参数,让调用者将自己的变量的地址传递到函数的内部函数的内部通过指针就可以修改实参变量的值。


c当函数需要返回多个数据的时候就可以使用指针作为函数的参数。

例子:

#include<stdio.h>

#include <cstdint>

//声明函数

void puanDuanZuiDaZhi(int arr[],int len,int* max,int* min);

//利用指针定义需要被返回的值

int main()

{

int max = 0, min = 0;

int arr[] = { 10,20,30,16,56,1651,213,1,3,543,1,34,321,321354,22203,98};

//调用函数将max,min的地址取出来

//所以现在指针指向的是max,min,将指针在void函数中赋值则main函数中的max,min会被重新赋值

puanDuanZuiDaZhi(arr, sizeof(arr) / sizeof(arr[0]), &max, &min);

printf("%d\n%d",max,min);

return 0;

}


//函数体

void puanDuanZuiDaZhi(int arr[], int len, int* Max, int* Min)

{

int max = INT32_MIN;

int min = INT32_MAX;

//在函数中定义最大和最小值

for (int i = 0; i < len; i++)

{

if (arr[i] > max)

{

max = arr[i];

}

if (arr[i] < min)

{

min = arr[i];

}

}

//然后将max和min的值赋给指针

* Max = max;

* Min = min;

}

7.指针要分类型

1).指针分好多类型.

int* double* float* char*

指针变量是1个变量,无论指针是什么类型,在内存中都是占据8个字节,

既然指针都是占据8个字节,为什么指针还要分类型呢?

2).通过指针间接的操作指针指向的变量的方式。

int num =10;

int* p1 = &num;

p1指针变量中存储的是num变量的地址 也就是num变量的低字节的地址。

通过这个p1指针其实只能找到这个地址的字节。

这个时候,通过p1指针找到这个字节 操作的时候,是操作多个字节空间呢?

操作多少个字节是根据指针的类型来决定的。

指针变量的类型决定了 通过这个指针找到字节以后连续操作多少个字节空间。

指针是int* 那么就连续操作4字节

指针是double* 那么就连续操作8字节

指针是float* 那么就连续操作4字节

指针是char* 那么就连续操作1字节

所以,指针的类型如果不和指向的变量的类型相同话。那么通过指针就无法正确的操作指向的变量

所以,指针变量一定要指向1个和自己类型相同的普通变量才可以。

举例说明

int num=10;//int型占4个字节
int char* p1=&num;//用char型指针,那接下来连续使用一个字节
* p1=300;//将300转换为二进制输送到那一个字节和剩下的三个字节组成一个新的int型数据

8.多级指针

A  有哪些级数的指针

一级指针

1个指针变量中存储的是1个普通变量的地址,像这样的指针,我们就叫做一级指针,

二级指针

1个指针变量中存储的是1个一级指针变量的地址,像这样的指针,我们就叫做二级指针。

三级指针

1个指针变量中存储的是1个二级指针变量的地址,像这样的指针,我们就叫做三级指针。

B  二级指针.

1)。只能存储一级指针变量的地址。这样的指针叫做二级指针。

2)。声明二级指针的语法:

a.声明一级指针:  数据类型*指针名;

b.声明二级指针:  数据类型** 指针名;

c.声明三级指针:  数据类型***指针名;

3)。一级指针只能存储普通变量的地址。

二级指针只能存储一级指针变量的地址三级指针只能存储二级指针变量的地址。

n级指针只能存储n-1级指针变量的地址。

否则就会出问题。

5).初始化.

使用取地址运算符。拿到对应的指针变量的地址赋值给指针变量就可以了。

int num = 10;

int* p1 =&num;//p1是1个一级指针,存储的是num变量的地址。

int** p2 =&p1;//p2是1个二级指针,存储的是一级指针变量p1的地址。

int*** p3 =&p2;//p3是1个三级指针,存储的是二级指针变量p2的地址。

举例说明

#include<stdio.h>

int main()

{

int num = 10;
int* p1 = &num;
int** p2 = &p1;
//1.打印num变量的地址。
printf("num变量的地址:%p\n", &num);//num变量的地址。
//2.打印p1变量的值。
printf("p1指针变量的值是:%p\n", p1);//和上面的输出一样。
//3.打印p1指针变量的地址。
printf("p1指针变量的地址是:%p\n", & p1);//输出p1指针变量的地址
//4.打印p2变量的值。
printf("p2指针变量的值是:%p\n", p2);//和上面一样。
//5.打印p2的地址。
printf("p2指针变量的地址是:%p\n", &p2);//p2的地址,

}

C二级指针的使用

3. 二级指针的使用。

1),使用指针的时候,有几颗星就拐几个弯,

*指针变量名,代表这个指针指向的变量。

**指针变量名。这个指针至少要是1个二级指针,代表这个指针指向的指针指向的变量。

*p1 代表p1指针指向的变量.

**p1代表p1指针指向的指针指向的变量。

***p1代表p1指针指向的指针指向指针指向的变量。

#include<stdio.h>

int main()

{

int num = 20;

int* p1 = &num;

int** p2 = &p1;

int*** p3 = &p2;

printf("%d\n", *p1);//指向num的值

printf("%d\n", **p2);//先指向p1再指向num

printf("%d\n", ***p3);//先指向p2然后指向p1最后指向num

printf("%p\n", p1); //取p1的地址

printf("%p\n", *p2);//取p2的地址

printf("%p\n", **p3);//取p3的地址

//但最后都指向num的地址

return 0;

}

指针详解(1)_数组_05

9.指针与整数的加减法

指针与整数进行加减运算。

比如指针 +1;

并不是在指针地址的基础之上加1个字节的地址。而是在这个指针地址的基础之上加1个单位变量占用的字节数。

如果指针的类型是int* 那么这个时候1代表4个字节地址。

如果指针的类型是double* 那么这个时候1代表8个字节地址。

如果指针的类型是float* 那么这个时候1代表4个字节地址。

如果指针的类型是char* 那么这个时候1代表1个字节地址。

指针详解(1)_赋值_06

10.指针和数组

A.数组中的元素的地址也可以用指针表示

int arr[] = {10,20,30,40,50,60,70};

int *p1 = &arr[0];表示p1指针指向了数组中的第0个元素。

数组的第0个元素的地址就是数组的地址。数组名就代表数组的地址。

B.运用指针遍历数组中的元素(利用指针与整数加减)

1)。普通遍历

#include<stdio.h>

int main()

{

int arr[] = { 12,212,151,215,12121,231,313,132,31,1223 };

int len = sizeof(arr) / sizeof(arr[0]);

for (int i = 0; i < len; i++)

{

printf("%d\n",arr[i]);

}

return 0;

}

2).运用指针遍历

a.

#include<stdio.h>//使用指针遍历数组中的元素
int main()
{ int arr[] = { 12,212,151,215,12121,231,313,132,31,1223 };
int len = sizeof(arr) / sizeof(arr[0]);
int* p1 = arr;//将arr用指针表示
for (int i = 0; i < len; i++)
{
printf("%d\n", *(p1 + i));//利用指针加法将其的地址每次加四个字节
}
return 0;
}

b.

#include<stdio.h>

int main()

{

int arr[] = { 12,212,151,215,12121,231,313,132,31,1223 };

int len = sizeof(arr) / sizeof(arr[0]);

for (int i = 0; i < len; i++)

{

printf("%d\n", * (arr+i));//数组本身就是一个指针

}

return 0;

}

c.

#include<stdio.h>

int main()

{

int arr[] = { 12,212,151,215,12121,231,313,132,31,1223 };

int len = sizeof(arr) / sizeof(arr[0]);

int* p1 = arr;//将arr用指针表示

for (int i = 0; i < len; i++)

{

printf("%d\n", *(p1++));//利用指针加法将其的地址每次加四个字节

//使用这种方法指针p1的地址会改变不在跟原来一样。

}

return 0;

}
//注意注意的地方,每次循环.p1的值都会变化。
最后1次执行完毕之后,p1指针指向外面去了。 p1就不再执行数组中的任何元素了。

d.注意:数组名代表数组的地址。而数组一旦创建,数组的地址就确定了,不能改变所以。我们不能为数组名赋值。不能修改数组名的值。但是可以使用数组名的值。

结论:无法修改数组名的值。不能为数组名赋值。任何值都不可以。

因为数组名代表数组的地址,而数组一旦创建数组的地址是无法改变的。所以你不能给他赋值,数组名是1个常量.1个地址常量

11.当数组作为函数的参数时

在声明这个参数数组的时候。它并不是去创建1个数组而是去创建1个用来存储地址的指针变量,

如果我们为函数写了1个数组作为参数。其实啊,编译器在编译的时候,已经把这个数组换成了指针。

所以。以后,我们的函数如果带了1个参数 这个参数是1个数组。

建议,不要写数组了,直接写1个指向数组的第0个元素的指针,再传入长度

12.索引的本质。

1),指针变量后面可以使用中括弧的在中括弧中写上下标来访问数据。

2),p1[n];前提是p1是1个指针变量。

完全等价于 *(p1+n);

3),只要是指针都可以使用中括弧下标,就相当于是去访问指针指向的变量。

操作数组我们虽然使用的中括弧下标来操作,实际上内部仍然使用的指针来操作

#include<stdio.h>

int main()

{

int arr[4] = { 1,15,121,51};

//为数组中的元素赋值

arr[0] = 12;//* (arr+0)

arr[1] = 56;//* (arr+1)

printf("%d\n", arr[0]);

printf("%d\n", arr[1]);

return 0;

}

13.指针数组

如果1个数组是用来存储指针类型的数据的话。那么这个数组就叫做存储指针的数组。

格式:

元素类型数组名[数组长度];

int* arr[3];

这个arr数组的元素的类型是int*,是int指针,所以这个数组可以存储int指针数据。最多存储3个

#include<stdio.h>

int main()

{

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

//arr数组中的第零个元素指针parr[0]中储存的是arr[0]的地址。

int* parr[] = { arr,&arr[1],&arr[2] };

*(parr[0]) = 250;//将其赋值,则会改变原来数组中的值。

printf("%d", arr[0]);
return0;
}

14.指针与指针之间的减法

a.指针与指针之间可以做减法运算。

结果是1个long类型的数据。

结果的意义:代表两个指针指向的变量之间相差多少个单位变量。

绝大多数情况下,我们用在判断数组的两个元素之间相差多少个元素,


b.如果参与减法运算的两个指针不指向同1个数组,结果就有问题。

 唯一的意义:就是用在数组中,判断两个元素之间相差多少个元素。

d.指针与指针之间只能做减法运算。

15.指针与指针之间可以做比较运算。

a.

>

>=

<

<=

==

!=

都可以作用于两个指针之间。

b.为变量分配字节空间的时候,

从高地址向低地址分配的嘛。

>= 它可以判断两个指针指向的变量的地址 谁在高字节 谁在低字节。

c,也可以使用==、!= 来判断两个指针指向的地址是不是为同1个地址,

©著作权归作者所有:来自51CTO博客作者Woking77的原创作品,如需转载,请与作者联系,否则将追究法律责任

数据结构【c语言版】五千字长文手把手带你手撕快速排序,归并排序!_mb634f511ccb70e的博客-多极客编程

数据结构之八大算法详解(2)——快速排序,归并排序 快速排序 快速排序是Hoare于1962年提出的一种二叉树结构的交换排序方法,其基本思想为:任取待排序元素序列中 的某元素作为基准值,按照该排序码将待排序集合分割成两子序列,左子序列中所有元素均小于基准值,右子序列中所有元素均大于基准值,然后最左右子序列重复该过程,直到所有元素都排列在相应位置上为止。 hoare版本 单趟排序: 选择一个k

驱动开发:内核层inlinehook挂钩函数_lyshark的博客-多极客编程

在上一章《驱动开发:内核LDE64引擎计算汇编长度》中,LyShark教大家如何通过LDE64引擎实现计算反汇编指令长度,本章将在此基础之上实现内联函数挂钩,内核中的InlineHook函数挂钩其实与应用层一致,都是使用劫持执行流并跳转到我们自己的函数上来做处理,唯一的不同的是内核Hook只针对内核API函数,但由于其身处在最底层所以一旦被挂钩其整个应用层都将会受到影响,这就直接决定了在内核层挂钩

驱动开发:内核lde64引擎计算汇编长度_lyshark的博客-多极客编程

本章开始LyShark将介绍如何在内核中实现InlineHook挂钩这门技术,内核挂钩的第一步需要实现一个动态计算汇编指令长度的功能,该功能可以使用LDE64这个反汇编引擎,该引擎小巧简单可以直接在驱动中使用,LDE引擎是BeaEngine引擎的一部分,后来让BeatriX打包成了一个ShellCode代码,并可以通过typedef动态指针的方式直接调用功能,本章内容作为后期Hook挂钩的铺垫部分

数据结构中的七大排序算法—2_qq60a4bb138dd7e的博客-多极客编程

       今天为大家带来的是数据结构中的七大排序算法的其中两种:希尔排序和堆排序。本次的代码实现还是使用的C语言,编译器还是vs2013版本,希望接下来的内容可以帮助大家理解这两种排序。希尔排序       首先,对于一组待排数据,无论是什么方法,最重要的就是排序的速度,占用空间和准确性。所以,前人一直在寻找可以提升排序速度的算法。现在,我就为大家带来排序算法里程碑的算法:希尔排序算法。   

【c语言数据结构】ep1顺序表_wx624057a7edb56的博客-多极客编程

1.什么是顺序表 顺序表是用一段物理地址连续的存储单元依次存储数据元素的线性结构,一般情况下采用数组存储。在数组 上完成数据的增删查改。 顺序表一般可以分为静态表与动态表 1.静态顺序表 #define S 100 typedef int Sqlinstdate; typedef struct Sqlist { Sqlinstdate con[S]; int sz; }Sqlist; 静态顺

驱动开发:内核封装tdi网络通信接口_lyshark的博客-多极客编程

在上一篇文章《驱动开发:内核封装WSK网络通信接口》中,LyShark已经带大家看过了如何通过WSK接口实现套接字通信,但WSK实现的通信是内核与内核模块之间的,而如果需要内核与应用层之间通信则使用TDK会更好一些因为它更接近应用层,本章将使用TDK实现,TDI全称传输驱动接口,其主要负责连接Socket和协议驱动,用于实现访问传输层的功能,该接口比NDIS更接近于应用层,在早期Win系统中常用于

springboot+vue+token实现(表单+图片)上传、图片地址保存到数据库。上传图片保存位置自己定义、图片可以在前端回显(一))_记笔记/程序bug的博客-多极客编程

1、大致思路 以下是基于先处理图片、后端返回图片地址进行的 ==存数据== 1、将图片信息提交到后端 2、后端处理 3、后端返回前端图片的访问地址 4、前端将图片地址存入要提交的表单中 5、将整个表单提交到后端、将数据存入数据库 ==取数据== 1、前端获取后端返回的信息(包含图片的访问路径) 2、将访问图片的资源放到对应的标签或者组件中、按照自己的方式进行展示。(如果后端没有做图片资源的地址映射

#打卡不停更#openharmony数据转码应用开发实战(上)_鸿蒙社区的博客-多极客编程

背景 OpenHarmony的应用开发支持C++、JS、eTS,从已有版本的演进路线来看,eTS是未来重点的技术路线。 对于刚入门OpenHarmony应用开发的小伙伴来说,eTS可能比较陌生,如果有一个合适的实战项目来练手,那么对技术能力提升是非常有帮助的,本文将以一个小项目——数据转码应用,来讲解应用开发全流程。 需求 开发一个字符串转码应用,应用提供待转码字符串输入框,用户输入字符串后可方便

小白如何用java编写爬虫程序_13478918的博客-多极客编程

初入爬虫行业的程序员,往往会因为爬虫代码一个字符错误导致程序不能正常运行而且检查起来繁琐,耗费大量的精力,前期学习可以借鉴同行的代码加以完善,后期等技术能力达到一定的标准再去自己优化编写代码。下文就是通过Java语言编程的一个爬虫程序,希望对小白用户有一些帮助。 下面就上核心代码: public void crawling(String[] seeds) { //使用种子初始化 U

文盘rust -- 把程序作为守护进程启动_京东云官方的博客-多极客编程

当我们写完一个服务端程序,需要上线部署的时候,或多或少都会和操作系统的守护进程打交道,毕竟谁也不希望shell关闭既停服。今天我们就来聊聊这个事儿。最早大家部署应用的通常操作是 “nohup xxxx &”,别说像weblogic 或者其他java 容器有启动脚本,里面其实也差不多;很喜欢 nginx的 -d 参数,或者像redis 配置文件里可以指定是否以守护进程启动。看起来很优雅。那么

【算法】二叉搜索树的最近公共祖先_小冷的博客-多极客编程

题目要求 给定一个二叉搜索树, 找到该树中两个指定节点的最近公共祖先。 什么是最近公共祖先呢?百度百科解释 中将最近公共祖先的定义为:“对于有根树 T 的两个结点 p、q,最近公共祖先表示为一个结点 x,满足 x 是 p、q 的祖先且 x 的深度尽可能大(一个节点也可以是它自己的祖先)。” 例如,给定如下二叉搜索树: root = [6,2,8,0,4,7,9,null,null,3,5] 示

solr服务器_mb62c3ac8538829的博客-多极客编程

目标:solr的概念solr服务器的搭建和使用solr中导入数据库数据项目中怎么使用solr实现商品搜索功能一.solr相关概念1.1 什么是Solr?solr是一个独立的企业级搜索应用服务器,它是对外提供类似于web-service的api接口,用户可以通过http请求,发送一定格式的xml数据到solr,生成索引,也可以发送http get请求,请求solr服务器查询数据,将查询出的数据也是以