review c/c++ question

1、i+++j的结合

问题:输出k的值

 int i=1,j=2,k=0;

 k=i+++j;

答案:k=3;

解析:i+++j的结合方式为 (i++)+j。还有一个就是i+++++j这个表达式,它按照词法"贪心法“来解释。也只能这样解释成 (i++)++ +j
但这样的话 i++它就不是左值了。所以后面的++操作会报错。如果你写成i++ + ++j这样就没问题了。

原因:

词法分析里面有一个所谓的“贪心法”或者说叫“大嘴法”:每一个符号应该包含尽可能多的字符。 也就是说,编译器将程序分解为符号的办法是从左到右一个字符一个字符的读入。如果该字符可能组成一个符号,那么再读入下一个字符。判断已经读入的字符组成的字符串是否可能是一个符号的组成符号。如果可能再继续读入下一个字符。重复上面的过程。直到读入的字符组成的字符串不再可能组成一个有意义的符号。
这个方法的表述是:
如果(编译器的)输入流截止至某个字符之前都已经被分解为一个个符号,那么下一个符号将包括从该字符之后可能组成一个符号的最长字符串。
注意:除了字符串和字符常量,符号的中间不能嵌有空白。
如a---b和a-- -b的含义相同。但和a- --b的含义不同。

2、类型强制转换

char foo(void)
{
 unsigned int a=6;
 int b=-20;
 char c;
 (a+b>6)?(c=1):(c=0);

 printf("a+b=%u,c=%u\n",a+b,c);


 return c;
}

答案:a+b=4294967282,c=1
解析: unsigned int 类型的数据与int类型的数据相运算后,自动转换为unsigned int 类型。

计算机中是用补码来表示和存储数据,有符号数(如int)在计算机中用一个数的最高位存放符号, 正数为0, 负数为1。

[-20]=(10000000 00000000 00000000 00010100)原码=(11111111 11111111 11111111 11101011)反码=(11111111 11111111 11111111 11101100)补码,在强制类型转换后,最高位不再认为是符号位,作为变量的值,所以类型强转后,a的值为4294967276,因此a+b的值不是-14,而是一个unsigned int类型的数4294967382。
//因此返回值是1,与实际我们想要得到的结果不符。可以定义一个int类型的数接受a+b的值,如int c=a+b。或者是对相加结果进行强制类型转换,如int(a+b)。//这个问题测试你是否懂得C语言中的整数自动转化规则。-20变成了一个非常大的正整数,所以表达式的结果大于6。这一点对于频繁用到无符号数据类型的嵌入式系统来说是非常重要的。

扩展:隐式类型转换

A、在混合类型的算术表达式中,最宽的数据类型数据类型成为目标转换类型

B、一种类型的表达式赋值给两一种类型的对象,目标转换类型为被赋值对象的类型。

C、把一个表达式传递给一个函数,调用表达式的类型与形式参数的类型不相同,目标转换类型是形式参数的类型。

D、从一个函数返回一个表达式的类型与函数返回类型不相同,返回的表达式类型自动转换为函数返回类型。


3、螺旋队列


1> 规律:

A、螺旋规律

B、奇数(圈数,或X轴正坐标)平方规律(紫线)

2> 问题描述:

设1的坐标是(0,0),x方向向右为正,y方向向下为正,例如,7的坐标为(-1,-1),2的坐标为(1,0)。编程实现输入任意一点坐标(x,y),输出所对应的数字!

3> 问题解决:

从紫线突破,从图中不难发现,每圈最大值max=(2*c+1)(2*c+1),c为由内往外的圈数,c>=0。如图每圈最大值分别是1、9、25、49、81........,算出每圈的max后,就分4条边分别计算每圈的其他值。通过坐标落在该圈4条边的哪条边上,按照不同的公式计算出具体坐标点的值。

以第3圈(max=49)为例,4条边划分如下图(以颜色区分):

这里先给出4条边上各坐标上的值与max的对应关系为:

上边:Utop = max+(x+y);

左边: Uleft= max+(3*x-y);

下边:Ubottom = max + (-x - 5*y);

右边:Uright = max+(-7*x+y);

 

那么这些关系是怎么得出来的呢?再看图中画上圈的数字(将其值表示为topBase,xxBase),我们称其为每条边的基准值:

观察这些基准值与max值之间关系,不难发现,这些基准值与max之间的差分别是1C(上边),3C(左边),5C(下边),7C(右边)(C表示当前圈数),在上边和下边,y坐标表示(或等于)圈数(即C=y),而在左边和右边,x坐标表示(或等于)圈数(即C=x)。因此前面提到的差值又可用坐标表示成1y,3x,5y,7x。因此就产生了各边基准值的计算公式:

topBase=max+y

leftBase=max+3x

bottomBase=max-5y

rightBase=max-7x

(注意坐标的符号,负数加,正数减,因为基准值肯定都比max要小)

下面得出每条边的值,首先考虑上边和下边,这2条边,在基准值的基础上,由x坐标控制增减,因此:

topValue=topBase+x=max+y+x(上边,随x赠而赠,因此是加x)

bottomValue=bottomBase-x=max-5y-x(下边,随x赠而减,因此是减x)

同理,左边和右边,则在基准值的基础上,由y坐标控制增减,因此:

leftValue=leftBase-y=max+3x-y(左边,随y赠而减,因此是减y)

rightValue=rightBase+y=max-7x+y(右边,随y赠而赠,因此是加y)

4> 程序实现
#define max(x,y) ((x)>(y)?(x):(y))
#define abs(x)  (x>0)?(x):(-x)

int spiral(int x,int y)
{

    int c = max(abs(x), abs(y));// 当前坐标所在圈  
    int max = (c * 2 + 1) * (c * 2 + 1);// 当前圈上最大值  

    if (y == -c) // 上边
    {  
        return max + (x + y);  
    }
    else if (x == -c) // 左边
    {
        return max + (3 * x - y);  
    }
    else if (y == c) // 下边
    {
        return max + (-x - 5 * y);  
    }
    else // 右边
    {  
        return max + (-7 * x + y);  
    }  
}
void printQueue()
{  
    int x=0;
    int y=0;
    for (y = -5; y <= 5; ++y)
    {  
        for (x = -5; x <= 5; ++x)
        {  
            printf("%5d ", spiral(x, y));  
        }
        printf("\n");  
    }  
}
int main()
{
    printQueue();
}

output:

  111   112   113   114   115   116   117   118   119   120   121
  110    73    74    75    76    77    78    79    80    81    82
  109    72    43    44    45    46    47    48    49    50    83
  108    71    42    21    22    23    24    25    26    51    84
  107    70    41    20     7     8     9    10    27    52    85
  106    69    40    19     6     1     2    11    28    53    86
  105    68    39    18     5     4     3    12    29    54    87
  104    67    38    17    16    15    14    13    30    55    88
  103    66    37    36    35    34    33    32    31    56    89
  102    65    64    63    62    61    60    59    58    57    90
  101   100    99    98    97    96    95    94    93    92    91 


4、不使用判断语句,求两个数的最大值

问题:两个int类型的数据,不用任何的判断语句如if、switch、?:等,找出其中的大值

代码:

int getMax(int a,int b)
{
    int c=0;
    int x;
    int y;
    int val[2]={a,b};

    c=a-b;
    c=(unsigned)c>>(sizeof(int) *8 -1);
    printf("a=%d,b=%d,max[%d]=%d\n",a,b,c,val[c]);
    
    return val[c];
}
int main()
{
    getMax(-1,9);
    getMax(-6,-2);
    getMax(127,-128);
    return 0;

}

output:

a=-1,b=9,max[1]=9
a=-6,b=-2,max[1]=-2
a=127,b=-128,max[0]=127
方式2:max=a+b+abs(a,b);

5、不使用中间变量,把a、b值进行交换

方式1:

a=a+b;

b=a-b;

a=a-b;

方式2:

a=a^b;

b=a^b;

a=a^b;

6、C 和C++间的关系

1 >在C++ 程序中调用被 C 编译器编译后的函数,为什么要加 extern “C”声明?

之所以采用这种方式,是因为两种语言之间的一些差异所导致的。函数被C++编译后在库中的名字与C 语言的不同。C++语言支持函数重载,C 语言不支持函数重载。由于C++支持多态性,也就是具有相同函数名的函数可以完成不同的功能,C++通常是通过参数区分具体调用的是哪一个函数。在编译的时候,C++编译器会将参数类型和函数名连接在一起,于是在程序编译成为目标文件以后,C++编译器可以直接根据目标文件中的符号名将多个目标文件连接成一个目标文件或者可执行文件。但是在C语言中,由于完全没有多态性的概念,C编译器在编译时除了会在函数名前面添加一个下划线之外,什么也不会做(至少很多编译器都是这样干的)。由于这种的原因,当采用CPP与C混合编程的时候,就可能会出问题。假设某个函数的原型为: void foo(int x, int y);该函数被C 编译器编译后在库中的名字为_foo , 而C++ 编译器则会产生像_foo_int_int 之类的名字。
C++提供了C 连接交换指定符号extern“C”来解决名字匹配问题。

2>ifndef/define/endif的作用

ifndef/define/endif的作用是防止该头文件被重复引用。

一般格式是这样的:   
#ifndef   <标识>   
#define   <标识>   
......   
......   
#endif   <标识> 
在理论上来说可以是自由命名的,但每个头文件的这个“标识”都应该是唯一的。标识的命名规则一般是头文件名全大写,前后加下划线,并把文件名中的“.”也变成下划线,如:stdio.h  
#ifndef  _STDIO_H_  
#define  _STDIO_H_  
......   
#endif 

3>、#include"filename"与#include<filename>的区别

< >引用的是编译器的类库路径里面的头文件
" "引用的是你程序目录的相对路径中的头文件,在程序目录的相对路径中找不到该头文件时会继续在类库路径里搜寻该头文件。

7、十进制转换为二进制、八进制、十六进制

#include <stdio.h>

/*十进制转换成二进制*/
void decToBin(int a, char* str)
{  
    unsigned int c;
    int i=0;
    
    c=a;   
    for(i=0;i<32;i++)
    {  
        str[31-i]=(char)(c&1)+'0';  
        c>>=1;  
    }  
    str[32] = '\0';
    for(i=0;i<32;i++)
    {
        printf("%c",str[i]);
    }
}  

/*十进制转换为二进制、八进制、十六机制*/
int decTransform(int dnum,int *bin,int type)
{
    int i,j=0;
    for(i=0;dnum>0;i++)
    {
        *(bin+i)=dnum%type;
        dnum/=type;
        j++;
    }
    return j;
}
main()
{
    int n,s,j,a[100];
    int type=0;
    
    printf("input value:");
    scanf("%d",&n);
    printf("input type of transfer:");
    scanf("%d",&type);
    s=transformToBin(n,a,type);
    if(2==type)
    {
        printf("Decimalist to Binary:");
    }
    else if(8==type)
    {
        printf("Decimalist to Octonary:0x");
    }
    else if(16== type)
    {
        printf("Decimalist to Hex:");
    }
        
    for(j=s-1;j>=0;j--)
    printf("%d",a[j]);
    
    return 1;
}

8、打印控制台输入的参数个数及携带的参数

使用的main函数的入参来获取参数个数及命令携带的参数值。

C语言规定main函数的参数只能有两个,习惯上这两个参数写为argc和argv。因此,main函数的函数头可写为: main(argc,argv)C语言还规定argc(第一个形参)必须是整型变量,argv(第二个形参)必须是指向字符串的指针数组。加上形参说明后,main函数的函数头应写为:
main (argc,argv)
int argv;
char *argv[];或写成:
main (int argc,char *argv[])
由于main函数不能被其它函数调用, 因此不可能在程序内部取得实际值。那么,在何处把实参值赋予main函数的形参呢?实际上,main函数的参数值是从操作系统命令行上获得的。当我们要运行一个可执行文件时,在DOS提示符下键入文件名,再输入实际参数即可把这些实参传送到main的形参中去。

9、不重复随机数列生成算法

首先我们来看命题:

给定一个正整数n,需要输出一个长度为n的数组,数组元素是随机数,范围为0 – n-1,且元素不能重复。比如 n = 3 时,需要获取一个长度为3的数组,元素范围为0-2,

比如 0,2,1。

这个问题的通常解决方案就是设计一个 hashtable ,然后循环获取随机数,再到 hashtable 中找,如果hashtable 中没有这个数,则输出。下面给出这种算法的代码

        public static int[] GetRandomSequence0(int total)
        {
            int[] hashtable = new int[total];
            int[] output = new int[total];
 
            Random random = new Random();
            for (int i = 0; i < total; i++)
            {
                int num = random.Next(0, total);
                while (hashtable[num] > 0)
                {
                    num = random.Next(0, total);
                }
 
                output[i] = num;
                hashtable[num] = 1;
            }
 
            return output;
        }

代码很简单,从 0 到 total - 1 循环获取随机数,再去hashtable 中尝试匹配,如果这个数在hashtable中不存在,则输出,并把这个数在hashtable 中置1,否则循环尝试获取随机数,直到找到一个不在hashtable 中的数为止。这个算法的问题在于需要不断尝试获取随机数,在hashtable 接近满时,这个尝试失败的概率会越来越高。

 方法二:

image

如上图所示,我们设计一个顺序的数组,假设n = 4

第一轮,我们取 0 – 3 之间的随机数,假设为2,这时,我们把数组位置为2的数取出来输出,并把这个数从数组中删除,这时这个数组变成了

image

第二轮,我们再取 0-2 之间的随机数,假设为1,并把这个位置的数输出,同时把这个数从数组删除,以此类推,直到这个数组的长度为0。这时我们就可以得到一个随机的不重复的序列。

这个算法的好处是不需要用一个hashtable 来存储已获取的数字,不需要反复尝试。算法代码如下:

        public static int[] GetRandomSequence1(int total)
        {
            List<int> input = new List<int>();
            for (int i = 0; i < total; i++)
            {
                input.Add(i);
            }
 
            List<int> output = new List<int>();
 
            Random random = new Random();
            int end = total;
            for (int i = 0; i < total; i++)
            {
                int num = random.Next(0, end);
                output.Add(input[num]);
                input.RemoveAt(num);
                end--;
            }
 
            return output.ToArray();
        }

 

这个算法把两个循环改成了一个循环,算法复杂度大大降低了,按说速度应该比第一个算法要快才对,然而现实往往超出我们的想象,当total = 100000 时,测试下来,第一个算法用时 44ms, 第二个用时 1038 ms ,慢了很多!这是为什么呢?问题的关键就在这个 input.RemoveAt 上了,我们知道如果要删除一个数组元素,我们需要把这个数组元素后面的所有元素都向前移动1,这个移动操作是非常耗时的,这个算法慢就慢在这里。到这里,可能有人要说了,那我们不用数组,用链表,那删除不就很快了吗?没错,链表是能解决删除元素的效率问题,但查找的速度又大大降低了,无法像数组那样根据数组元素下标直接定位到元素。所以用链表也是不行的。

方法三:

还是上面那个例子,假设 n = 4

image

 

第一轮,我们随机获得2时,我们不将 2 从数组中移除,而是将数组的最后一个元素移动到2的位置

image

这时数组变成了

image

第二轮我们对 0-2 取随机数,这时数组可用的最后一个元素位置已经变成了2,而不是3。假设这时取到随机数为1

我们再把下标为2 的元素移动到下标1,这时数组变成了

image

以此类推,直到取出n个元素为止。

这个算法的优点是不需要用一个hashtable 来存储已获取的数字,不需要反复尝试,也不用像上一个算法那样删除数组元素,要做的只是每次把数组有效位置的最后一个元素移动到当前位置就可以了,这样算法的复杂度就降低为 O(n) ,速度大大提高。

经测试,在 n= 100000 时,这个算法的用时仅为7ms。

下面给出这个算法的实现代码

        /// <summary>
        /// Designed by eaglet
        /// </summary>
        /// <param name="total"></param>
        /// <returns></returns>
        public static int[] GetRandomSequence2(int total)
        {
 
            int[] sequence = new int[total];
            int[] output = new int[total];
 
            for (int i = 0; i < total; i++)
            {
                sequence[i] = i;
            }
 
            Random random = new Random();
 
            int end = total - 1;
 
            for (int i = 0; i < total; i++)
            {
                int num = random.Next(0, end + 1);
                output[i] = sequence[num];
                sequence[num] = sequence[end];
                end--;
            }
 
            return output;
        }

 

下面是n 等于1万,10万和100万时的测试数据,时间单位为毫秒。从测试数据看GetRandomSequence2的用时和n基本成正比,线性增长的,这个和理论上的算法复杂度O(n)也是一致的,另外两个算法则随着n的增大,用时超过了线性增长。在1百万时,我的算法比用hashtable的算法要快10倍以上。

 

 100001000001000000
GetRandomSequence05441075
GetRandomSequence1111038124205
GetRandomSequence21782

10、在C++中重写和重载的区别

1>、重写(override)

override是重写(覆盖)了一个方法,以实现不同的功能。一般是用于子类在继承父类时,重写(重新实现)父类中的方法。

重写(覆盖)的规则:

   1、重写方法的参数列表必须完全与被重写的方法的相同,否则不能称其为重写而是重载.

   2、重写方法的访问修饰符一定要大于被重写方法的访问修饰符(public>protected>default>private)。

   3、重写的方法的返回值必须和被重写的方法的返回一致;

   4、重写的方法所抛出的异常必须和被重写方法的所抛出的异常一致,或者是其子类;

   5、被重写的方法不能为private,否则在其子类中只是新定义了一个方法,并没s有对其进行重写。

   6、静态方法不能被重写为非静态的方法(会编译出错)。

View Code

 2>、overload是重载,一般是用于在一个类内实现若干重载的方法,这些方法的名称相同而参数形式不同。

重载的规则

   1、在使用重载时只能通过相同的方法名、不同的参数形式实现。不同的参数类型可以是不同的参数类型,不同的参数个数,不同的参数顺序(参数类型必须不一样);

   2、不能通过访问权限、返回类型、抛出的异常进行重载;

   3、方法的异常类型和数目不会对重载造成影响;

多态的概念比较复杂,有多种意义的多态,一个有趣但不严谨的说法是:继承是子类使用父类的方法,而多态则是父类使用子类的方法。

一般,我们使用多态是为了避免在父类里大量重载引起代码臃肿且难于维护。

11、指针和引用的区别

   ★ 相同点:

    1. 都是地址的概念;
       指针指向一块内存,它的内容是所指内存的地址;
       引用是某块内存的别名。
    ★ 区别:
    1. 指针是一个实体,而引用仅是个别名;
    2. 引用使用时无需解引用(*),指针需要解引用;
    3. 引用只能在定义时被初始化一次,之后不可变;指针可变;
    4. 引用没有 const,指针有 const,const 的指针不可变;
    5. 引用不能为空,指针可以为空;
    6. “sizeof 引用”得到的是所指向的变量(对象)的大小,而“sizeof 指针”得到的是指针本身(所指向的变量或对象的地址)的大小;
    typeid(T) == typeid(T&) 恒为真,sizeof(T) == sizeof(T&) 恒为真,但是当引用作为类成员名称时,其占用空间与指针相同4个字节(没找到标准的规定)。
    7. 指针和引用的自增(++)运算意义不一样;
    ★ 联系
    1. 引用在语言内部用指针实现。
    2. 对一般应用而言,把引用理解为指针,不会犯严重语义错误。引用是操作受限了的指针(仅容许取内容操作)。
    引用的一些规则如下:
    (1)引用被创建的同时必须被初始化(指针则可以在任何时候被初始化)。
    (2)不能有NULL 引用,引用必须与合法的存储单元关联(指针则可以是NULL)。
    (3)一旦引用被初始化,就不能改变引用的关系(指针则可以随时改变所指的对象)。

12、struct和class的区别

在c++中:

关于使用大括号初始化 
class和struct如果定义了构造函数的话,都不能用大括号进行初始化 
如果没有定义构造函数,struct可以用大括号初始化。 
如果没有定义构造函数,且所有成员变量全是public的话,可以用大括号初始化。

关于默认访问权限 
class中默认的成员访问权限是private的,而struct中则是public的。 
关于继承方式 
class继承默认是private继承,而struct继承默认是public继承。

C中,结构不允许含有成员函数,在c++中则允许含有成员函数

比较一下   C   语言的   struct   和   C++   的   struct   好了 
访问权限: 
C:public   (没有   private   访问权限) 
C++:默认   public,可以用   protected/private   限制 
内容: 
C:只有数据 
C++:可以有数据、成员函数、构造析构函数,与   class   相同 
其它: 
C:除了存放数据,没有其它功能 
C++:可以与   class   参与继承,可以重载操作符,可以有模板结构。。。 
使用: 
C:需要   struct   s  作为名称声明变量 
C++:struct   关键字在声明变量的时候可选

C++中struct已经被扩展,已经不再是C时代的struct

那么C#中的struct 和C++里的区别在哪呢?

(*) struct的内存分配不同 
C#: 在栈上分配 
c++: 在哪分配由程序员说了算,只有用new的时候才在堆上分配

说实话我对堆栈的区别也有些不清楚可以参考http://baike.baidu.com/view/93201.htm

stack:

由系统自动分配。 例如,声明在函数中一个局部变量 int b; 系统自动在栈中为b开辟空间

heap:

需要程序员自己申请,并指明大小,在c中malloc函数

如p1 = (char *)malloc(10);

在C++中用new运算符

如p2 = new char[20];//(char *)malloc(10);

在C#中class是引用类型分配在堆中 struct是值类型分配在栈中。


13、遍历输出指定目录下的所以文件

在Linux下opendir()、readdir()和closedir()这三个函数主要用来遍历目录。在使用这三个函数前必须先包括以下两个头文件:#include <sys/types.h>#include <dirent.h>

opendir函数的原型为:
DIR *opendir(const char *name);它返回一个DIR*类型,这就是一个句柄啦,你不用管它的内部结构是什么样的,只要知道这个句柄就是等一下要传给readdir()函数的参数就行了。

readdir函数的原型为:struct dirent *readdir(DIR *dir);看它的参数就知道该参数是opendir函数返回的句柄,而该函数的返回值是struct dirent* 类型,这里我们必须了解一下这个结构体:struct dirent {               ino_t          d_ino;       /* inode number */
               off_t          d_off;       /* offset to the next dirent */
               unsigned short d_reclen;    /* length of this record */
               unsigned char  d_type;      /* type of file */
               char           d_name[256]; /* filename */
};这个结构体的d_name存放的就是文件的名字,这里的文件包括普通文件,目录文件等等,在linux的思想中,所有的东西都是文件。
closedir函数的原型为:int closedir(DIR *dir);这个函数就不用多说了,一般有开(open),就有关(close),这样的结构经常可出看到,如fopen,fclose等等。

三个函数介绍完了,直接来一个例子吧:
******************************SearchDir.c******************************
#include <stdio.h>
#include <string.h>
#include <sys/types.h>
#include <dirent.h>
#include <sys/stat.h>
char filename[256][256];
int len = 0;
int trave_dir(char* path, int depth)
{
    DIR *d;//声明一个句柄
    struct dirent *file;//readdir函数的返回值就存放在这个结构体中
    struct stat sb;   
   
    if(!(d = opendir(path)))
    {
        printf("error opendir %s!!!\n",path);
        return -1;
    }
    while((file = readdir(d)) != NULL)
    {
       //把当前目录.,上一级目录..及隐藏文件都去掉,避免死循环遍历目录
        if(strncmp(file->d_name, ".", 1) == 0)
            continue;
        strcpy(filename[len++], file->d_name);//保存遍历到的文件名
       //判断该文件是否是目录,及是否已搜索了三层,这里我定义只搜索了三层目录,太深就不搜了,省得搜出太多文件
        if(stat(file->d_name, &sb) >= 0 && S_ISDIR(sb.st_mode) && depth <= 3)
        {
            trave_dir(file->d_name, depth + 1);
        }
    }
    closedir(d);
    return 0;
}

14、 Linux下如何根据进程名查端口号(或根据端口号查进程名)

1>、根据进程名查对应的端口号

如果你在网上搜索一下,发现有不少这方面的资料,仔细尝试,却发现多半是不正确的(吐槽一下:文抄公真是多如牛毛,以讹传讹太可恶)。其实这个很容易做到:

#netstat -tlnp | grep /processname

注意:processname前面最好加上/,这样便于缩小查询范围。

2>、根据端口号查对应的进程名

网上推荐使用两种方法,分别用到lsof和netstat命令,在这里根据我的使用经验总结一下:

1)使用lsof命令

#lsof -Pnl -i :portnumber

lsof(list open files)是一个列出当前系统中打开文件的工具。在linux环境下,everything is file,通过文件不仅仅可以访问常规数据,还可以访问网络连接和硬件。

上述lsof命令参数解释:
-P :该选项禁止端口号到端口名的转换,这样可以加快lsof运行速度。
-n :该选项禁止端口号到主机名称的转换,这样不仅可以加快lsof的运行速度,而且在主机名称查找不能奏效时非常有用。
-l :该选项禁止用户ID号到登录名的转换,这在登录名查找不正确或很慢时非常有用。
-i  [info]:该选项指定显示与info中互联网地址相匹配的信息。 

2)使用netstat命令

#netstat-tlnp | grep :portnumber
注意:portnumber前面最好加上:,这样便于缩小查询范围。这种方法与第一种方法实际查找的结果不是同一内容,但都可以查到进程名,差别在于,这种方法看到的是最简单的端口监听信息,而第一种方法看到的是跟该端口关联的具体网络连接


评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

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

抵扣说明:

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

余额充值