欧美bbbwbbbw肥妇,免费乱码人妻系列日韩,一级黄片

C++利用Socket實(shí)現(xiàn)主機(jī)間的UDP/TCP通信

 更新時(shí)間:2023年01月04日 08:41:08   作者:cout丶shy  
這篇文章主要為大家詳細(xì)介紹了C++如何利用Socket實(shí)現(xiàn)主機(jī)間的UDP/TCP通信功能,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以了解一下

前言

完整代碼放到github上了:cppSocketDemo

服務(wù)器端的代碼做了跨平臺(POSIX和WINDOWS),基于POSIX平臺(Linux、Mac OS X、PlayStation等)使用sys/socket.h庫,windows平臺使用winsock2.h庫。

客戶端代碼因?yàn)榛径荚趙indows運(yùn)行,所以沒做跨平臺,需要的話你可以參考服務(wù)器端代碼自己做一下。
文中寫的函數(shù)原型均為windows平臺,部分函數(shù)的返回類型或參數(shù)類型在POSIX會有不同。

頭文件

根據(jù)_WIN32標(biāo)志區(qū)分,導(dǎo)入頭文件。

#include<iostream>
#include<cstring>
#ifdef _WIN32

#include<winsock2.h>

#else

#include <sys/socket.h>
#include <netinet/in.h>
#include <sys/types.h>
#include <netdb.h>
#include <errno.h>
#include <fcntl.h>
#include <unistd.h>
typedef int SOCKET;

#endif

因?yàn)镻OSIX平臺的socket庫沒有SOCKET類型,所以我們手動定義一下。

UDP Socket

服務(wù)器端

對于windows,使用socket前需要手動開啟:

#ifdef _WIN32
    WSADATA wsd;
    if(WSAStartup(MAKEWORD(2, 2), &wsd)){
        std::cout << "WSAStartup Error" << std::endl;
        exit(-1);
    }   
#endif

WSAStartup第一個(gè)參數(shù)表示使用版本號。該函數(shù)會向第二個(gè)參數(shù)填入被激活的socket庫的信息。

SOCKET函數(shù)

SOCKET socket(int af, int type, int protocol);

參數(shù):

af:socket使用協(xié)議族,如AF_INET表示IPv4, AF_INET6表示IPv6等。

type:指明通過socket發(fā)送和接收分組的形式。如SOCK_STREAM表示有序、可靠的數(shù)據(jù)流分段;SOCK_DGRAM表示離散的報(bào)文;SOCK_RAW表示數(shù)據(jù)頭部可以由應(yīng)用層自定義。

protocol:指明發(fā)送數(shù)據(jù)使用什么協(xié)議。IPPROTO_UDP;IPPROTO_TCP;IPPROTO_IP;0表示根據(jù)socket類型選擇默認(rèn)協(xié)議。

通過socket函數(shù)創(chuàng)建并返回一個(gè)udp類型socket對象:

SOCKET udpSocket = socket(AF_INET, SOCK_DGRAM, 0);

bind函數(shù)

將一個(gè)socket綁定到一個(gè)地址和端口號,使用bind函數(shù):

int bind(SOCKET sock, const sockaddr *address, int address_len);

參數(shù):

sock: 綁定socket

address:注意是指發(fā)送數(shù)據(jù)包的源地址,而不是發(fā)送目的地址

address_len:存儲address的sockaddr結(jié)構(gòu)體大小

bind成功時(shí)返回0,出現(xiàn)錯(cuò)誤時(shí)返回-1

給端口號賦值0,將告訴socket庫找一個(gè)未被使用的端口并綁定

如果一個(gè)進(jìn)程試圖使用一個(gè)未綁定的socket發(fā)送數(shù)據(jù),網(wǎng)絡(luò)庫將自動為這個(gè)socket綁定一個(gè)可用的端口號。

所以對于服務(wù)器來說手動調(diào)用bind綁定是必須的,而對于客戶端來說通常是沒有必要的。

服務(wù)器端socket需要顯式綁定地址和端口,以便客戶端訪問:

sockaddr_in sain;
sain.sin_family = AF_INET;    //使用IPv4
sain.sin_addr.s_addr = htonl(INADDR_ANY);
sain.sin_port = htons(atoi("50002"));

???????if(bind(udpSocket, (sockaddr *)&sain, sizeof(sockaddr)) == -1){
    std::cout << "綁定失敗" << std::endl;
}

recvfrom函數(shù)

從UDP Socket接收數(shù)據(jù)

int recvfrom(SOCKET s,char *buf,int len,int flags,struct sockaddr *from,int *fromlen);

參數(shù):

s: 查詢數(shù)據(jù)的socket。默認(rèn)情況下,

buf: 接收的數(shù)據(jù)包的緩沖區(qū)。

len: buf可以存儲的最大字節(jié)數(shù)。到達(dá)的數(shù)據(jù)包的剩余字節(jié)將被丟棄。

flags: 同sendto flags。

from: 指向發(fā)送者的地址和端口號的指針,該值由recvfrom函數(shù)寫入(每接收一個(gè)數(shù)據(jù)包寫入一次)。不要手動填寫。

fromlen: from所指向sockaddr的大小

如果recvfrom成功執(zhí)行會返回復(fù)制到buf的字節(jié)數(shù),發(fā)生錯(cuò)誤返回-1。

服務(wù)器通過recvfrom函數(shù)接收客戶端信息:

const size_t BufMaxSize = 1000;
char buf[BufMaxSize] = {}; 
sockaddr fromAddr;
#ifndef _WIN32
unsigned
#endif
int fromAddrLen = sizeof(sockaddr);
std::cout << "等待接收..." << std::endl;
while(true){
    if(recvfrom(udpSocket, buf, BufMaxSize, 0, &fromAddr, &fromAddrLen) != -1){
        std::cout << "接收到數(shù)據(jù):" << buf << std::endl;
        memset(buf, 0, sizeof(buf));
    }   
    else{
        std::cout << "接收失敗或發(fā)生錯(cuò)誤!" << std::endl;
        return -1; 
    }   
}

最后記得做關(guān)閉工作

#ifdef _WIN32
    WSACleanup();
    closesocket(udpSocket);
#else
    close(udpSocket);
#endif

客戶端

和服務(wù)器一樣的先激活:

WSADATA wsd;
if(WSAStartup(MAKEWORD(2, 2), &wsd)){
    std::cout << "WSAStartup Error" << std::endl;
    exit(-1);
}

創(chuàng)建socket:

SOCKET udpSocket = socket(AF_INET, SOCK_DGRAM, 0);

將目標(biāo)遠(yuǎn)程主機(jī)的IP和端口信息填入sockaddr:

先寫一個(gè)工具函數(shù):

sockaddr GetSockAddr(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint16_t inPort){
    sockaddr addr;
    sockaddr_in *addrin = reinterpret_cast<sockaddr_in*>(&addr);
    addrin->sin_family = AF_INET;
    addrin->sin_addr.S_un.S_un_b.s_b1 = b1;
    addrin->sin_addr.S_un.S_un_b.s_b2 = b2;
    addrin->sin_addr.S_un.S_un_b.s_b3 = b3;
    addrin->sin_addr.S_un.S_un_b.s_b4 = b4;
    addrin->sin_port = htons(inPort);
    
    return addr;
}
sockaddr toAddr = GetSockAddr(127, 0, 0, 1, 50002);

sendTo函數(shù)

從UDP Socket發(fā)送數(shù)據(jù)

int sendto(SOCKET s,const char *buf,int len,int flags,const struct sockaddr *to,int tolen);

參數(shù):

s: 數(shù)據(jù)包應(yīng)該使用的socket,如果沒有綁定,socket庫將自動綁定一個(gè)可用的端口。

buf: 待發(fā)送數(shù)據(jù)的起始地址的指針??梢允侨魏文軌虮晦D(zhuǎn)為char*的數(shù)據(jù)類型。

len: 待發(fā)送數(shù)據(jù)的大小。盡量避免發(fā)送數(shù)據(jù)大于1300字節(jié)的數(shù)據(jù)包,詳見p75。

flags: 對控制發(fā)送的標(biāo)志進(jìn)行按位或運(yùn)算的結(jié)果,該值通常取0即可。

to: 目標(biāo)接收者的sockaddr。注意to的地址族必須和用于創(chuàng)建socket的地址族一致。

tolen:to的sockaddr的大小。對于IPv4,傳入sizeof(sockaddr_in)即可。

sendto操作成功返回等待發(fā)送的數(shù)據(jù)長度(說明成功進(jìn)入發(fā)送隊(duì)列),否則返回-1。

通過senTo函數(shù)發(fā)送數(shù)據(jù):

const size_t BufMaxSize = 1000;
char buf[BufMaxSize] = {};
sockaddr toAddr = GetSockAddr(127, 0, 0, 1, 50002); 
int toAddrLen = sizeof(sockaddr);
std::cout << ">>> ";
while(true){
    if(std::cin >> buf){
        sendto(udpSocket, buf, strlen(buf), 0, &toAddr, toAddrLen);
        std::cout << "已發(fā)送!" <<std::endl;
        std::cout << ">>> ";
        memset(buf, 0, sizeof(buf));
    }
}

注意,這樣發(fā)送給linux服務(wù)器帶中文的字符串的話,可能出現(xiàn)亂碼,因?yàn)閘inux通常為UTF-8編碼,而windows通常為gb2312編碼,所以我們可以在客戶端實(shí)現(xiàn)兩個(gè)編碼轉(zhuǎn)換函數(shù),并在恰當(dāng)時(shí)機(jī)轉(zhuǎn)換:

//UTF-8轉(zhuǎn)GB2312
char* U2G(const char* utf8){
    int len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0);
    wchar_t* wstr = new wchar_t[len+1];
    memset(wstr, 0, len+1);
    MultiByteToWideChar(CP_UTF8, 0, utf8, -1, wstr, len);
    len = WideCharToMultiByte(CP_ACP, 0, wstr, -1, NULL, 0, NULL, NULL);
    char* str = new char[len+1];
    memset(str, 0, len+1);
    WideCharToMultiByte(CP_ACP, 0, wstr, -1, str, len, NULL, NULL);
    if(wstr) delete[] wstr;
    return str;
}
//GB2312轉(zhuǎn)UTF-8
char* G2U(const char* gb2312){
    int len = MultiByteToWideChar(CP_ACP, 0, gb2312, -1, NULL, 0);
    wchar_t* wstr = new wchar_t[len+1];
    memset(wstr, 0, len+1);
    MultiByteToWideChar(CP_ACP, 0, gb2312, -1, wstr, len);
    len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
    char* str = new char[len+1];
    memset(str, 0, len+1);
    WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, len, NULL, NULL);
    if(wstr) delete[] wstr;
    return str;
}

發(fā)送改為:

char *buf_UTF8 = G2U(buf);
sendto(udpSocket, buf_UTF8, strlen(buf_UTF8), 0, &toAddr, toAddrLen);

最后同樣的關(guān)閉操作:

closesocket(udpSocket);
WSACleanup();

測試

注意,如果把服務(wù)器代碼放到windows下執(zhí)行,記得把客戶端的轉(zhuǎn)編碼代碼改下。

注意,編譯使用C++11以上編譯,鏈接時(shí)加入庫:

-lwsock32

將udpServer.cpp放到服務(wù)器上,服務(wù)器防火墻記得放行目標(biāo)端口或暫時(shí)關(guān)閉防火墻。

udpClient.cpp在本地(windows)。

udpClient中的目標(biāo)遠(yuǎn)程主機(jī)地址改為服務(wù)器ip地址,編譯運(yùn)行:

服務(wù)器:

客戶端:

TCP Socket(單客戶端連接)

服務(wù)器

同樣先激活winsock:

#ifdef _WIN32
    WSADATA wsd;
    if(WSAStartup(MAKEWORD(2, 2), &wsd)){
        std::cout << "WSAStartup Error" << std::endl;
        return -1;
    }
#endif

創(chuàng)建tcp類型socket:

SOCKET tcpsocket = socket(AF_INET, SOCK_STREAM, 0);

綁定本機(jī)地址和指定端口號:

sockaddr_in sain;
sain.sin_family = AF_INET;
sain.sin_addr.s_addr = htonl(INADDR_ANY);
sain.sin_port = htons(atoi("50002"));
if(bind(tcpsocket, (sockaddr*)&sain, sizeof(sockaddr)) == -1){
    std::cout << "bind Error" <<  std::endl;
    return -1;
}

listen函數(shù)

用listen函數(shù)啟動監(jiān)聽,等待客戶端的連接:

int listen(SOCKET sock, int backlog);

backlog指隊(duì)列允許傳入的最大連接數(shù),超過最大值的連接都將被丟棄??梢允褂肧OMAXCONN表示默認(rèn)的backlog值。

函數(shù)執(zhí)行成功返回0,失敗返回-1。

使用listen函數(shù)開啟監(jiān)聽:

listen(tcpsocket, 10);

主機(jī)針對每個(gè)保持的TCP連接,都需要一個(gè)獨(dú)立的socket存儲連接狀態(tài)。

這里先做只能連接單個(gè)客戶端,創(chuàng)建連接客戶端的socket:

sockaddr clientAddr;        //
    
#ifndef _WIN32
    unsigned
#endif
    int clientAddrLen = sizeof(sockaddr);

accept函數(shù)

接受傳入的連接并繼續(xù)TCP握手過程,調(diào)用accept函數(shù):

SOCKET accept(SOCKET sock, sockaddr* addr, int* addrlen);

參數(shù):

sock: 接收傳入連接的監(jiān)聽socket

addr: 將被寫入請求連接的遠(yuǎn)程主機(jī)地址。同樣不要手動填寫

addrlen: 指向addr緩沖區(qū)大小的指針。當(dāng)真正寫入地址之后,accept會更新該值。

如果accept執(zhí)行成功,將創(chuàng)建并返回一個(gè)可以與遠(yuǎn)程主機(jī)通信的新socket。

接受傳入的連接并繼續(xù)TCP握手過程:

SOCKET linkSocket = accept(tcpsocket, &clientAddr, &clientAddrLen);

recv函數(shù)

調(diào)用recv函數(shù)從一個(gè)連接的TCP socket接收數(shù)據(jù):

int recv(SOCKET s,char *buf,int len,int flags);

參數(shù):

s: 待接收數(shù)據(jù)的socket

buf: 數(shù)據(jù)接收緩沖區(qū)。

len: 拷貝到buf中的數(shù)據(jù)的最大數(shù)量。

flags: 標(biāo)志位,大多數(shù)情況填0。

調(diào)用成功返回接收的數(shù)據(jù)大小。如果返回0,說明連接的另一端發(fā)送了一個(gè)FIN數(shù)據(jù)包,承諾沒有更多需要發(fā)送的數(shù)據(jù)。

如果發(fā)生錯(cuò)誤,返回-1

默認(rèn)情況下,如果socket的接收緩沖區(qū)中沒有數(shù)據(jù),recv函數(shù)將阻塞調(diào)用線程,直到數(shù)據(jù)流中的下一組數(shù)據(jù)到達(dá)或超時(shí)。

send函數(shù)

通過連接的socket使用send函數(shù)發(fā)送數(shù)據(jù):

因?yàn)檫B接的socket存儲了遠(yuǎn)程主機(jī)地址信息,所以不需要傳入地址參數(shù):

int send(SOCKET s,const char *buf,int len,int flags);

參數(shù):

s: 用于發(fā)送數(shù)據(jù)的socket

buf: 寫入緩沖區(qū)。注意:和UDP不同,是將數(shù)據(jù)放到socket的輸出緩沖區(qū)中,由socket庫來決定在將來某一時(shí)刻發(fā)出。

len: 傳輸?shù)淖止?jié)數(shù)量。注意:與UDP不同,不需要保持這個(gè)值低于鏈路層的MTU。

flags:標(biāo)志位,大多數(shù)情況下填0即可。

send調(diào)用成功返回發(fā)送數(shù)據(jù)的大小,如果發(fā)送錯(cuò)誤返回-1.

默認(rèn)情況下該函數(shù)會阻塞線程,直到調(diào)用超時(shí)或發(fā)送了足夠的數(shù)據(jù)。

非0的返回值不代表成功發(fā)送出去了,只說明數(shù)據(jù)被存入隊(duì)列中等待發(fā)送。

使用recv函數(shù)和send函數(shù)接收和響應(yīng)客戶端信息:

const size_t BufMaxLen = 1000;
char buf[BufMaxLen] = {};
char sendBuf[BufMaxLen] = "服務(wù)器成功接收!";
while(true){
    int ret = recv(linkSocket, buf, BufMaxLen, 0);
    if(ret > 0){
        std::cout << "從客戶端接收到數(shù)據(jù):" << buf << std::endl;
        memset(buf, 0, BufMaxLen);
        send(linkSocket, sendBuf, strlen(sendBuf), 0);
    }
    else if(ret == 0){
        std::cout << "客戶端停止發(fā)送數(shù)據(jù),準(zhǔn)備關(guān)閉連接..." << std::endl;
        break;
    }
    else{
        std::cout << "recv發(fā)生錯(cuò)誤!" << std::endl;
    }
}

最后關(guān)閉:

#ifdef _WIN32
    closesocket(tcpsocket);
    closesocket(linkSocket);
    WSACleanup();
#else
    close(tcpsocket);
    close(linkSocket);
#endif
    std::cout << "已關(guān)閉服務(wù)器Socket..." << std::endl;

客戶端

客戶端沒有新函數(shù),直接看代碼吧!

TCPSocketClient.cpp:

#include<iostream>
#include<winsock2.h>
#include<windows.h>
#include<memory>
#include<cstring>

using namespace std;

//UTF-8轉(zhuǎn)GB2312
char* U2G(const char* utf8){
	int len = MultiByteToWideChar(CP_UTF8, 0, utf8, -1, NULL, 0);
	wchar_t* wstr = new wchar_t[len+1];
	memset(wstr, 0, len+1);
	MultiByteToWideChar(CP_UTF8, 0, utf8, -1, wstr, len);
	len = WideCharToMultiByte(CP_ACP, 0, wstr, -1, NULL, 0, NULL, NULL);
	char* str = new char[len+1];
	memset(str, 0, len+1);
	WideCharToMultiByte(CP_ACP, 0, wstr, -1, str, len, NULL, NULL);
	if(wstr) delete[] wstr;
	return str;
}
//GB2312轉(zhuǎn)UTF-8
char* G2U(const char* gb2312){
	int len = MultiByteToWideChar(CP_ACP, 0, gb2312, -1, NULL, 0);
	wchar_t* wstr = new wchar_t[len+1];
	memset(wstr, 0, len+1);
	MultiByteToWideChar(CP_ACP, 0, gb2312, -1, wstr, len);
	len = WideCharToMultiByte(CP_UTF8, 0, wstr, -1, NULL, 0, NULL, NULL);
	char* str = new char[len+1];
	memset(str, 0, len+1);
	WideCharToMultiByte(CP_UTF8, 0, wstr, -1, str, len, NULL, NULL);
	if(wstr) delete[] wstr;
	return str;
}

sockaddr GetSockAddr(uint8_t b1, uint8_t b2, uint8_t b3, uint8_t b4, uint16_t inPort){
	sockaddr addr;
	sockaddr_in *addrin = reinterpret_cast<sockaddr_in*>(&addr);
	addrin->sin_family = AF_INET;
	addrin->sin_addr.S_un.S_un_b.s_b1 = b1;
	addrin->sin_addr.S_un.S_un_b.s_b2 = b2;
	addrin->sin_addr.S_un.S_un_b.s_b3 = b3;
	addrin->sin_addr.S_un.S_un_b.s_b4 = b4;
	addrin->sin_port = htons(inPort);
	
	return addr;
}


int main(){
	WSADATA wsd;
	if(WSAStartup(MAKEWORD(2, 2), &wsd)){
		std::cout << "WSAStartup Error" << std::endl;
		return -1;
	}
	SOCKET tcpSocket = socket(AF_INET, SOCK_STREAM, 0);
	sockaddr serverAddr = GetSockAddr(127, 0, 0, 1, 50002);   
	int serverAddrLen = sizeof(sockaddr);
	if(connect(tcpSocket, &serverAddr, serverAddrLen) == -1){
		std::cout << "connect Error!" << std::endl;
		return -1;
	}
	std::cout << "已成功連接到服務(wù)器" << std::endl;
	//客戶端的socket就是用于連接的socket
	const int BufMaxLen = 1000;
	char sendBuf[BufMaxLen] = {};
	char buf[BufMaxLen] = {};
	std::cout << ">>> ";
	while(true){
		if(std::cin >> sendBuf){
			if(strcmp(sendBuf, "exit") == 0){
				std::cout << "正在關(guān)閉連接..." << std::endl;
				break;
			}
			char *sendBuf_UTF8 = G2U(sendBuf);
			send(tcpSocket, sendBuf_UTF8, strlen(sendBuf_UTF8), 0);
			memset(sendBuf, 0, BufMaxLen);
			int ret = recv(tcpSocket, buf, BufMaxLen, 0);
			if(ret > 0){
				std::cout << "從服務(wù)器接收到回應(yīng):" << U2G(buf) << std::endl;
				memset(buf, 0, BufMaxLen);
			}
			std::cout << ">>> ";
		}
	}
	
	
	shutdown(tcpSocket, SB_BOTH);
	closesocket(tcpSocket);
	WSACleanup();
	std::cout << "已關(guān)閉客戶端Socket..." << std::endl;
	
	return 0;
}

測試

注意,如果把服務(wù)器代碼放到windows下執(zhí)行,記得把客戶端的轉(zhuǎn)編碼代碼改下。

測試方式同上面UDP。

客戶端:

服務(wù)器:

TCP Socket(多客戶端連接)

服務(wù)端

使用多線程,每響應(yīng)一個(gè)客戶端連接為它創(chuàng)建一個(gè)線程。

多線程頭文件:

#include<thread>

將之前的響應(yīng)代碼搬到函數(shù)中作為線程入口:

void linkClientThread(SOCKET linkSocket, unsigned int linkId){
    printf("客戶端(id:%d) 已連接!\n", linkId);
    const size_t BufMaxLen = 1000;
    char buf[BufMaxLen] = {};
    char sendBuf[BufMaxLen] = "服務(wù)器成功接收!";
    while(true){
        int ret = recv(linkSocket, buf, BufMaxLen, 0);
        if(ret > 0){
            printf("從客戶端(id:%d)接收到數(shù)據(jù):%s\n", linkId, buf);
            memset(buf, 0, BufMaxLen);
            send(linkSocket, sendBuf, strlen(sendBuf), 0);
        }
        else if(ret == 0){
            printf("客戶端(id:%d)停止發(fā)送數(shù)據(jù),關(guān)閉連接...\n", linkId);
            break;
        }
        else{
            printf("recv發(fā)生錯(cuò)誤!\n");
            break;
        }
    }
    
#ifdef _WIN32
    closesocket(linkSocket);
#else
    close(linkSocket);
#endif
    
}

當(dāng)接收到連接請求,為它單獨(dú)創(chuàng)建一個(gè)線程服務(wù):

while(true){
    SOCKET linkSocket = accept(tcpsocket, &clientAddr, &clientAddrLen);
    std::thread linkThread(linkClientThread, linkSocket, ++linkId);
    linkThread.detach();
}

客戶端

客戶端直接繼續(xù)使用之前的tcpClient.cpp即可,沒有區(qū)別。

測試

同樣的注意,如果把服務(wù)器代碼放到windows下執(zhí)行,記得把客戶端的轉(zhuǎn)編碼代碼改下。

服務(wù)器還是使用linux系統(tǒng)的,所有客戶端在本地的windows執(zhí)行:
注意:server代碼在linux編譯時(shí)要加入-lpthread.h選項(xiàng):

g++ -g tcpServer_multiConnection.cpp -o tcpServer_multiConnection -std=c++11 -lpthread

客戶端1:

客戶端2:

服務(wù)器:

以上就是C++利用Socket實(shí)現(xiàn)主機(jī)間的UDP/TCP通信的詳細(xì)內(nèi)容,更多關(guān)于C++ Socket實(shí)現(xiàn)UDP/TCP通信的資料請關(guān)注腳本之家其它相關(guān)文章!

相關(guān)文章

  • C語言實(shí)現(xiàn)數(shù)據(jù)結(jié)構(gòu)迷宮實(shí)驗(yàn)

    C語言實(shí)現(xiàn)數(shù)據(jù)結(jié)構(gòu)迷宮實(shí)驗(yàn)

    這篇文章主要為大家詳細(xì)介紹了C語言實(shí)現(xiàn)數(shù)據(jù)結(jié)構(gòu)迷宮實(shí)驗(yàn),文中示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2019-03-03
  • C語言實(shí)現(xiàn)繪制立體餅圖的示例代碼

    C語言實(shí)現(xiàn)繪制立體餅圖的示例代碼

    這篇文章主要為大家詳細(xì)介紹了如何使用C語言實(shí)現(xiàn)繪制立體餅圖,文中的示例代碼講解詳細(xì),感興趣的小伙伴可以跟隨小編一起學(xué)習(xí)一下
    2024-03-03
  • 如何區(qū)分C++中的inline和#define宏

    如何區(qū)分C++中的inline和#define宏

    這篇文章主要介紹了如何區(qū)分C++中的inline和#define宏,文中講解非常詳細(xì),代碼幫助大家更好的參考和學(xué)習(xí),感興趣的朋友可以了解下
    2020-06-06
  • C語言?分析逆序字符串與字符串的逆序輸出有什么區(qū)別

    C語言?分析逆序字符串與字符串的逆序輸出有什么區(qū)別

    例如,給定一個(gè)字符串?s,將?s?中的字符順序顛倒過來,如?s?=?“abcd”,逆序后變成?“dcba”。可以采用多種方法對字符串進(jìn)行逆序,以下將對其中的方法和字符串的逆序輸出的區(qū)別進(jìn)行分析
    2022-04-04
  • 基于QT設(shè)計(jì)一個(gè)春聯(lián)自動生成器

    基于QT設(shè)計(jì)一個(gè)春聯(lián)自動生成器

    春節(jié)是中國最隆重的傳統(tǒng)節(jié)日,一到過年家家戶戶肯定是要貼春聯(lián);在春節(jié)前夕,會用大紅紙張,加上濃墨書寫祝福詞語。本文將利用Qt框架設(shè)計(jì)一個(gè)春聯(lián)自動生成器,需要的可以參考一下
    2022-01-01
  • C語言:利用指針編寫程序,用梯形法計(jì)算給定的定積分實(shí)例

    C語言:利用指針編寫程序,用梯形法計(jì)算給定的定積分實(shí)例

    今天小編就為大家分享一篇C語言:利用指針編寫程序,用梯形法計(jì)算給定的定積分實(shí)例,具有很好的參考價(jià)值,希望對大家有所幫助。一起跟隨小編過來看看吧
    2019-12-12
  • C++實(shí)現(xiàn)帶頭雙向循環(huán)鏈表的示例詳解

    C++實(shí)現(xiàn)帶頭雙向循環(huán)鏈表的示例詳解

    這篇文章主要介紹了如何利用C++實(shí)現(xiàn)帶頭雙向循環(huán)鏈表,文中通過示例代碼介紹的非常詳細(xì),具有一定的參考價(jià)值,感興趣的小伙伴們可以參考一下
    2022-12-12
  • C++中的strcmp函數(shù)

    C++中的strcmp函數(shù)

    strcmp函數(shù)是C++標(biāo)準(zhǔn)庫中用于字符串比較的重要函數(shù),在C++中,字符串比較是一項(xiàng)常見的操作,用于判斷兩個(gè)字符串是否相等或者大小關(guān)系,本文介紹C++中的strcmp函數(shù),感興趣的朋友一起看看吧
    2024-03-03
  • C/C++中命名空間(namespace)詳解及其作用介紹

    C/C++中命名空間(namespace)詳解及其作用介紹

    今天小編就為大家分享一篇關(guān)于C++命名空間namespace的介紹與使用,小編覺得內(nèi)容挺不錯(cuò)的,現(xiàn)在分享給大家,具有很好的參考價(jià)值,需要的朋友一起跟隨小編來看看吧
    2021-09-09
  • C++中指針的詳解及其作用介紹

    C++中指針的詳解及其作用介紹

    這篇文章主要介紹了C++中指針的詳解及其作用介紹,本文給大家介紹的非常詳細(xì),對大家的學(xué)習(xí)或工作具有一定的參考借鑒價(jià)值,需要的朋友可以參考下
    2021-09-09

最新評論