I need to build a function that returns the most frequent sourceIP (and then Destination IP) within an array of structs. This is my structure.
typedef enum { IN_IN, IN_OUT, OUT_IN} Direction;
typedef enum { IGMP, TCP, UDP} Protocol;
typedef unsigned int Count;
#define NUM 6
typedef struct {
long long timestamp;
Direction direction;
char sourceIP[16];
char destIP[16];
Protocol protocol;
unsigned int port;
Count bytes;
}Packet;
I need to implement a function which receives the size of the array, an array type Packet and returns the most frequent IP source address within an array of structs. Here is my STRUCT array:
Packet packetsarray[NUM] = {
{42069, IN_OUT, "192.100.200.2", "192.10.0.6", TCP, 30, 256 },
{666, OUT_IN, "148.201.196.208", "148.201.196.1", UDP, 80,666},
{1002, IN_IN, "192.100.200.2", "10.10.0.6", IGMP, 30, 256 },
{1002, IN_OUT, "192.100.200.2", "10.10.0.6", IGMP, 30, 256 },
{1002, OUT_IN, "192.100.200.2", "10.10.0.6", IGMP, 30, 256 },
{1002, IN_OUT, "192.100.200.2", "10.10.0.6", IGMP, 30, 256 }};
However my teacher explicitly states do the operation without using any brackets, ONLY using pointer arithmetrics this is what I have so far for my function:
void CountDirections(Packet packets[], int N, int *c1, int *c2, int *c3)
{
*c1 = 0;
*c2 = 0;
*c3 = 0;
Packet *packetpointer = packets;
Packet *packetpointer2 = packets;
packetpointer2++;
int i, maxcount = 0, count = 0;
char word[16];
for (i= 0; i < N; i++)
{
if(packetpointer->direction == IN_OUT)
*c2 += 1;
else if(packetpointer->direction == OUT_IN)
*c3 += 1;
else if (packetpointer->direction == IN_IN)
*c1 += 1;
packetpointer++;
}
packetpointer = packets;
for (i= 0; i < N; i++)
{
strcpy(word, packetpointer->sourceIP);
printf("%s\n", word);
packetpointer++;
}
}
I have NO CLUE how to find the most frequent SourceIP within the array of structs without using brackets [] a friend told me to use a MODE algorithm but I don't know how to implement it using pointers only. Please help.
Related
I have to handle the communication between a computer running a program written in Python and microcontroller using C code. The protocol struct is designed to prevent padding using uin32_t for all fields except the value which is restricted to be either int or double. It looks something like this:
struct head {
#define CMD_SET 1
#define CMD_GET 2
uint32_t cmd;
uint32_t err;
#define TYPE_INT 1
#define TYPE_DOUBLE 2
uint32_t type;
};
struct frame {
struct head *head;
void *val;
};
If I initially get the raw bytes in a uint8_t buffer and the buffer was made to comply with the struct layout above, can I cast to and from this buffer to struct head and to void *val?
I have tried the code below and it seems to be working but I am afraid that it might invoke UB. Is the code below safe? If not, what techniques should I use to handle this process? Use memcpy? Maybe #pragma pack?
// Example:
uint8_t buf[sizeof(struct head) * 2] = {0}; // Make the buffer big enough
void process_cmd(uint8_t *buf)
{
struct frame frame = {0};
frame.head = (struct frame *)buf; // UB?
frame.val = frame.head + 1
if (frame.head->cmd == CMD_SET) {
if (frame.head->type == TYPE_INT) {
do_work_with_int(*(int *)frame.val); // UB?
} else if (frame.head->type == TYPE_DOUBLE) {
do_work_with_dobule(*(double *)frame.val); // UB?
}
} else if (frame.head->cmd == CMD_GET) {
if (frame.head->type == TYPE_INT) {
int val = 1;
memcpy(frame.val, &val, sizeof(val));
} else if (frame.head->type == TYPE_DOUBLE) {
double val = 2.0;
memcpy(frame.val, &val, sizeof(val));
}
} else {
frame.err = 1;
}
}
int main(void)
{
uart_read(uart_hdlr, buf, sizeof(buf));
process_cmd(buf);
uart_send(uart_hdlr, buf, sizeof(buf));
}
I'm beginner and I have a problem. I have this structure:
typedef struct {
char data[26];
int index;
Placa_baza pb; // char nume_placa[10], int index_placa;
} PC;
And a structure vector:
static PC computers[5] = { ... };
I need to have a vector of type uint8_t pc[5*sizeof(computers)] instead of the structure vector.
Is it well declared that way? :
uint8_t pc[5*sizeof(computers)]
How can I convert (cast) vector uint8_t pc[5*sizeof(computers)] to PC?
To use the uint8_t pointer to address the structure, how should it be written?
Thank you in advance.
Your pc array, which could serve as a backup for the PC data is too large: it is sufficient to define it as:
uint8_t pc[sizeof(computers)];
Or possibly:
uint8_t pc[5 * sizeof(PC)];
You can then copy computers to pc with:
memcpy(pc, computers, sizeof pc);
You could also use a pointer to access the pc array as an array of PC:
PC *p = (PC *)pc; // Don't do this!
Note however that this has undefined behavior as the byte array pc might not be properly aligned to access members of the PC structure, especially the index member and using such a pointer is a violation of the strict aliasing rule. It would be much better to define pc as PC pc[5]; and access this array via a uint8_t pointer of so required.
WARNING: Below program is just demonstration purpose, it may not behave same way with all compilers/systems. You can use it to test your compilers or systems behavior and modify accordingly.
In the below program am copying the contents from the structure computers to unit8_t.
as you can see its not easy and not portable, because we need to extract the data as per the boundaries of memory, allocated for variables.
#include <stdio.h>
#include <stdint.h>
#include <string.h>
typedef struct
{
char nume_placa[10];
int index_placa;
}Placa_baza;
typedef struct {
char data[26];
int index;
Placa_baza pb;
}PC;
int main()
{
printf("sizeof(int) = %zu\n", sizeof(int));
printf("sizeof(Placa_baza) = %zu\n", sizeof(Placa_baza));
printf("sizeof(PC) = %zu\n", sizeof(PC));
static PC computers[3] = { {"data1",1,"comp1", 0}, {"data2",2,"comp2", 1}, {"data3",3,"comp3", 2} };
printf("sizeof(computers) = %zu\n\n", sizeof(computers));
for(int i =0; i<3; i++)
printf("data = %s, index =%d, pb.nume_placa =%s, pb.index_placa =%d\n",
computers[i].data,
computers[i].index,
computers[i].pb.nume_placa,
computers[i].pb.index_placa
);
uint8_t uint8_t_pc[sizeof(computers)] = {0};
// for copying the contents from pc (uint8_t), used same variable names as that of structures
/* typedef struct { */
char data[26];
int index;
/* Placa_baza pb;
} PC; */
/* typedef struct
{ */
char nume_placa[10];
int index_placa;
/* }Placa_baza;
*/
printf("\n sizeof(uint8_t_pc) = %zu\n", sizeof(uint8_t_pc));
memcpy(uint8_t_pc,computers,sizeof(computers));
int count = 0;
uint8_t* temp = uint8_t_pc;
printf("\n **From uint8_t memory ***\n");
while(count < 3) {
memcpy(data, temp, 26);
// since there is a padding of 2 bytes , so extract from 28
memcpy(&index, temp+28, 4);
memcpy(nume_placa, temp+32, 10);
//again there is a padding of 2 bytes
memcpy(&index_placa, temp+44, 4);
printf("data = %s, index = %d, nume_placa =%s , index_placa =%d\n", data, index, nume_placa, index_placa);
temp = temp+sizeof(computers[0]);
count++;
}
return 0;
}
Output:
sizeof(int) = 4
sizeof(Placa_baza) = 16
sizeof(PC) = 48
sizeof(computers) = 144
data = data1, index =1, pb.nume_placa =comp1, pb.index_placa =0
data = data2, index =2, pb.nume_placa =comp2, pb.index_placa =1
data = data3, index =3, pb.nume_placa =comp3, pb.index_placa =2
sizeof(uint8_t_pc) = 144
**From uint8_t memory ***
data = data1, index = 1, nume_placa =comp1 , index_placa =0
data = data2, index = 2, nume_placa =comp2 , index_placa =1
data = data3, index = 3, nume_placa =comp3 , index_placa =2
online source
Update:
Indeed we can use offsetof to get the offset of any member of the structure, so the statements inside while can also be replaced by below statments.
memcpy(data, temp+offsetof(PC, data), sizeof(computers[count].data));
memcpy(&index, temp+offsetof(PC, index), sizeof index);
memcpy(nume_placa, temp+offsetof(PC, pb.nume_placa), sizeof computers[count].pb.nume_placa);
memcpy(&index_placa, temp+offsetof(PC, pb.index_placa), sizeof index_placa);
I need to serialise a struct and I am trying to do this using memcpy. But it is not working. I can tell by looking at the byte stream - I see garbage characters. Why?
Also I get runtime error:
Run-Time Check Failure #2 - Stack around the variable 'addresses' was corrupted.
What is happening and how can I fix this?
I am using #pragma pack(push, 1) which I thought would mean there would be no padding of the structs.
#include <stdio.h>
#include <string.h>
#include <stdint.h>
#pragma pack(push, 1) /* padding has to be disabled for casting to struct to work at other end */
typedef struct {
uint8_t start_char;
uint8_t msg_type;
uint8_t length;
} MSG_HEADER;
typedef struct {
uint8_t denomination[6];
uint8_t path;
uint8_t min_level;
uint16_t max_level;
uint16_t weight;
uint8_t address;
} CONFIG_DATA;
typedef struct {
MSG_HEADER header;
uint8_t clear_type;
CONFIG_DATA config_data[12];
uint8_t system_algorithm;
uint8_t max_transaction;
} MSG_CONFIGURATION;
#pragma pack(pop) /* only affect this file */
typedef struct {
unsigned char data[256];
size_t length;
int msg_type;
} TCHU_MESSAGE;
enum DRM_MESSAGE_TYPE {
CONFIG, CLEAR_COUNT, DISPENSE, CANCEL_TRANSACTION };
void TestCopy()
{
MSG_CONFIGURATION config;
config.clear_type = 0;
config.system_algorithm = 0;
config.max_transaction = 17;
const int NumItems = 12;
const uint16_t maxLevel = 300;
static const char* denoms[] = { "GB005A","GB005B","GB010A","GB010B",
"GB020A","GB050A","GB050B","GB100A",
"GB100B","GB200A", "EU100A", "EU100B" };
const uint8_t addresses[] = { 0, 0, 5, 5, 0, 7, 7, 8, 8, 9, 0, 0 };
const uint8_t sorting_paths[] = { 5, 5, 4, 4, 5, 2, 2, 1, 1, 3, 0, 0 };
for(int i = 0; i < NumItems; ++i) {
memcpy(config.config_data[i].denomination, denoms[i], 6);
config.config_data[i].address = addresses[i];
config.config_data[i].path = sorting_paths[i];
config.config_data[i].min_level = 3;
config.config_data[i].max_level = maxLevel;
config.config_data[i].weight = 1000;
}
config.header.start_char = 1;
config.header.msg_type = 2;
config.header.length = sizeof(MSG_CONFIGURATION);
TCHU_MESSAGE tchu_msg = {0};
// why does the memcpy not work? How can I get it to work?
memcpy(tchu_msg.data, &config+sizeof(MSG_HEADER), sizeof(MSG_CONFIGURATION) - sizeof(MSG_HEADER));
printf("sizeof(MSG_HEADER) = %u\n", sizeof(MSG_HEADER));
printf("sizeof(MSG_CONFIGURATION) = %u\n", sizeof(MSG_CONFIGURATION));
// get garbage in copyconfig
MSG_CONFIGURATION copyconfig;
memcpy(©config+sizeof(MSG_HEADER), tchu_msg.data, sizeof(MSG_CONFIGURATION) - sizeof(MSG_HEADER));
if(copyconfig.header.start_char != config.header.start_char)
{
// we get to here
printf("mismatch between original and copy\n");
}
}
int main() {
TestCopy();
// I also get Run-Time Check Failure #2 - Stack around the variable 'addresses' was corrupted.
// when program ends
}
My compiler instantly told me what was wrong:
warning: '__builtin___memcpy_chk' will always overflow destination buffer [-Wbuiltin-memcpy-chk-size]
memcpy(©config+sizeof(MSG_HEADER), tchu_msg.data, sizeof(MSG_CONFIGURATION) - sizeof(MSG_HEADER));
Why is that? Well, let's look at the destination:
©config + sizeof(MSG_HEADER)
That means "Take the address of copyconfig, treat it as an array, and take the Nth object where N is sizeof(MSG_HEADER). I think you thought it would add N bytes, but it actually adds N instances of MSG_CONFIGURATION. Instead, use this:
©config.header + 1
That is, "Take the address of copyconfig.header and go to just beyond it."
You could equally do this:
(char*)©config + sizeof(MSG_HEADER)
Because the size of one char is one byte. Or, since your struct is packed:
©config.clear_type
Because that's the address of the first byte you actually want to copy into.
For more details, read: Pointer Arithmetic .
I want to send packets over a socket which have the following format:
struct Packet{
uint32_t seqnum;
uint16_t check;
char data[1024]
};
Each packet has a sequence number, a checksum, and the data that the packet contains. How could I put these 3 fields into a buffer to be sent over a socket, and then when received, the fields can be extracted? For example, is it possible to maybe make the first 4 bytes of the buffer the seqnum, the next 4 bytes the check, and then the remainder the data which is 1024 bytes? So the receiver will expect to receive a total of 1032 bytes and then should be able to extract the first 4 and make that seqnum, the next 4 and make that check sum and the last 1024 as the data? I am doing this over UDP so I cannot send the fields separately.
edit - OP didn't ask for C++, however the underlying implementation is done in C if that helps.
I modified a class from the Boost example website to suit your needs, it's a convenience wrapper for your buffers and struct. This should suit your needs, but it doesn't take into account big or little endianess.
It makes it a lot easier when your message is always a fixed size, but adding another 4 byte integer to your header that holds message length will save you a lot of bandwidth and it's very simple to do.
message myMessage;
myMessage.setSequence(nextSequenceNumber);
myMessage.setCheckSum(mycheckSum);
//assuming the message you have is a std::string
memcpy( myMessage.body(), message.c_str(), myMessage.body_length() );
myMessage.encode_header();
sendto(socket, myMessage.data(), myMessage.length(), 0, &my_sockaddrsizeof(my_sockaddr));
myMessage.reset();
recvfrom(socket, myMessage.data(), myMessage.length(), 0, &my_sockaddr, &my_sockaddr_len);
if(!myMessage.decodeHeader()){
// handle bad header/corrupt message
}
int32_t sequence = myMessage.getSequence();
int32_t checkSum = myMessage.getSheckSum();
class message
{
public:
enum { check_length = 4 };
enum { seq_length = 4 };
enum { body_length = 1024 };
message() : _checkSum(0), _sequence(0), _body_length(1024), _header_length(8) {} // constructor + init list
const char* data() const { return data_; }
char* data() { return data_; }
const char* body() const { return data_ + check_length + seq_length; }
char* body() { return data_ + check_length + seq_length; }
std::size_t length() { return _body_length + _header_length; }
std::size_t body_length() { return _body_length; }
int32_t const& getCheckSum() const { return _checkSum; }
int32_t const& getSequence() const { return _sequence; }
void setCheckSum(const int32_t& s) { _checkSum = s; }
void setSequence(const int32_t& s) { _sequence = s; }
bool decode_header()
{
char check_sum[check_length + seq_length + 1] = "";
char sequence[check_length + seq_length + 1] = "";
strncat_s(check_sum, data_, seq_length);
strncat_s(sequence, data_ + check_length, check_length);
_checkSum = std::atoi(check_sum);
_sequence = std::atoi(sequence);
if (_checkSum == 0 || _sequence == 0)
{
std::cout << "Header malfunction" << std::endl;
return false;
}
return true;
}
void encode_header()
{
char header[check_length + seq_length + 1] = "";
std::memcpy(header, &_sequence, sizeof(int32_t));
std::memcpy(header + seq_length, &_checkSum, sizeof(int32_t));
std::memcpy(data_, header, check_length + seq_length);
}
void reset()
{
memset(&data_[0], 0, sizeof(data_));
int32_t _checkSum = 0;
int32_t _sequence = 0;
}
private:
char data_[check_length + seq_length + body_length];
int32_t _body_length, _header_length;
int32_t _checkSum;
int32_t _sequence;
};
You have to make sure your struct is set up properly to have fields properly aligned at the proper byte boundaries.
So this is fine:
struct Packet{
uint32_t seqnum;
uint32_t check;
char data[1024];
};
But this is not:
struct Packet{
uint16_t other;
// 2 bytes of padding exist here so seqnum sits on a 4-byte boundary
uint32_t seqnum;
uint32_t check;
char data[1024];
};
Any integer fields larger than 8 bit should be converted to network byte order before sending and back to host byte order after receiving. Use htonl and ntohl for 32-bit values and htons and ntohs for 16-bit values.
Once you've done that, you can send that structure directly:
struct Packet packet;
// populate packet
int sock = socket(AF_INET, SOCK_DGRAM, 0);
// perform error checking, call bind, etc.
int sendLen = sendto(socket, &packet, sizeof(packet), 0, &my_sockaddr, sizeof(my_sockaddr));
And similarly receive it:
struct Packet packet;
int sock = socket(AF_INET, SOCK_DGRAM, 0);
// perform error checking, call bind, etc.
int recvLen = recvfrom(socket, &packet, sizeof(packet), 0, &my_sockaddr, &my_sockaddr_len);
// read packet
I'm having some trouble implementing a general sorting algorithm for any type. I've got the general sorting down, but I can't figure out how to write a compare function for structures I've made. The structures are automobiles, which have a name, model year, and price. I'm comparing the years, and sorting them in ascending order.
So far, I've written functions for sorting strings which works with the general algorithm. The general sorting algorithm is written correctly I believe and it is designed here in sort.c:
#include "sort.h"
#include <string.h>
/* Swap two pointers. */
static
void swap(void** left, void** right) {
void* temp = *left;
*left = *right;
*right = temp;
}
/* Sort Array
* This function sorts the data stored in the array.
* The actual sorting routine is
* Bubble-Sort.
*/
void sort_array(void* Array[], unsigned size, int (*compare)(void*,void*))
{
int i;
int have_swapped = 1;
while (have_swapped) {
have_swapped = 0;
for (i = 0; i < size - 1; ++i ){
if (compare(Array[i],Array[i+1])) {
swap(&Array[i+1], &Array[i]);
have_swapped = 1;
}
}
}
}
I think I have written the code for compare_structs correctly, but when I try to run the program it enters an infinite loop in the terminal. I have no idea why it's doing this.
I'm trying to learn C and passing pointers/functions as arguments. I want to write this compare_structs program so that it fits with the general sorting algorithm in sort.c, so I believe it has to return -1 in order to be swapped. I can't find the bug that's causing an infinite loop. Any help is appreciated!
Here is sort_structs.c:
#include <stdio.h>
#include <string.h>
#include "sort.h"
#include <stdlib.h>
/* Automobile */
struct automobile {
const char* name;
unsigned year;
unsigned price;
};
struct automobile one = { "AMC Pacer", 1975, 12900 };
struct automobile two = { "Cadillac Fleetwood", 1981, 4995 };
struct automobile three = { "Ford Pinto", 1971, 4200 };
struct automobile four = { "Suzuki X90", 1996, 1625 };
struct automobile five = { "Chrysler TC", 1991, 2495 };
struct automobile six = { "Cadillac Cimarron", 1986, 4990 };
struct automobile seven = { "Plymouth Prowler", 1997, 60000 };
struct automobile eight = { "Ford Edsel", 1958, 17000 };
struct automobile nine = { "Yugo", 1985, 3990 };
struct automobile ten = { "Pontiac Aztek", 2001, 603 };
/* Test Data
* Here I'm creating an array that points to the structures defined
*/
unsigned data_size = 10;
struct automobile* data[10] = {
&one,
&two,
&three,
&four,
&five,
&six,
&seven,
&eight,
&nine,
&ten
};
static
int compare_structs(void* left, void* right) {
struct automobile *x = left;
struct automobile *y = right;
int xYear = x->year;
int yYear = y->year;
if (xYear > yYear) return -1;
}
/* Test program
*
* This program tests sort_array with an array of automobile objects. Or
* rather, an array of pointers to automobile objects.
*/
int main() {
int i;
int status = EXIT_SUCCESS;
sort_array((void**)data, data_size, &compare_structs);
for(i = 0; i < data_size - 1; ++i) {
if (data[i]->year > data[i+1]->year) {
fprintf(stderr, "\"%s\" and \"%s\" are out of order\n",data[i]->name, data[i+1]->name);
status = EXIT_FAILURE;
}
}
return status;
}
There were quite a number of changes that I made in order to get the code to function. I'll do what I can to recall and explain each of them.
1. Call to sort_array
You originally called sort_array like this:
sort_array((void**)data, data_size, &compare_structs);
While it needs to (a) just cast the data variable to a void* and (b) doesn't need the address-of operator before the compare-function. (if you refer to a function but don't call it, the statement evaluates as the address of the function)
The result is:
sort_array((void*)data, data_size, compare_structs);
2. return value from compare_structs
You only returned a value from compare_structs if the year value of left is greater that the year value of right. You should return 1 of 3 values. -1, 0 and 1 to facilitate ascending/descending sort, with the 0 indicating that no swap is required.
if (xYear > yYear) return -1;
becomes
return (xYear - yYear);
3. Checking the return value from compare
You originally only checked if the return was something. You can check for greater than 0 or less than 0 to allow for ascending/descending sort order.
Thus,
if (compare(Array[i],Array[i+1]))
becomes (for an ascending order sort)
if (compare(Array[i],Array[i+1]) > 0)
Collating these modifications and running the result with a small mod to print the output, results in the following being printed to the console.
0. - 1958
1. - 1971
2. - 1975
3. - 1981
4. - 1985
5. - 1986
6. - 1991
7. - 1996
8. - 1997
9. - 2001
Finally, here's the complete code:
#include <stdio.h>
#include <string.h>
//#include "sort.h"
#include <stdlib.h>
//#include <string.h>
/* Swap two pointers. */
static
void swap(void** left, void** right)
{
void* temp = *left;
*left = *right;
*right = temp;
}
/* Sort Array
* This function sorts the data stored in the array.
* The actual sorting routine is
* Bubble-Sort.
*/
void sort_array(void* Array[], unsigned size, int (*compare)(void*,void*))
{
int i;
int have_swapped = 1;
while (have_swapped)
{
have_swapped = 0;
for (i = 0; i < size - 1; ++i )
{
if (compare(Array[i],Array[i+1]) > 0)
{
swap(&Array[i+1], &Array[i]);
have_swapped = 1;
}
}
}
i = 100;
}
/* Automobile
*/
struct automobile
{
const char* name;
unsigned year;
unsigned price;
};
struct automobile one =
{
"AMC Pacer",
1975,
12900
};
struct automobile two =
{
"Cadillac Fleetwood",
1981,
4995
};
struct automobile three =
{
"Ford Pinto",
1971,
4200
};
struct automobile four =
{
"Suzuki X90",
1996,
1625
};
struct automobile five =
{
"Chrysler TC",
1991,
2495
};
struct automobile six =
{
"Cadillac Cimarron",
1986,
4990
};
struct automobile seven =
{
"Plymouth Prowler",
1997,
60000
};
struct automobile eight =
{
"Ford Edsel",
1958,
17000
};
struct automobile nine =
{
"Yugo",
1985,
3990
};
struct automobile ten =
{
"Pontiac Aztek",
2001,
603
};
/* Test Data
* Here I'm creating an array that points to the structures defined
*/
unsigned data_size = 10;
struct automobile* data[10] =
{
&one,
&two,
&three,
&four,
&five,
&six,
&seven,
&eight,
&nine,
&ten
};
static
int compare_structs(void* left, void* right)
{
struct automobile *x = left;
struct automobile *y = right;
int xYear = x->year;
int yYear = y->year;
//if (xYear > yYear) return -1;
return (xYear - yYear);
}
/* Test program
*
* This program tests sort_array with an array of automobile objects. Or
* rather, an array of pointers to automobile objects.
*/
int main()
{
int i;
int status = EXIT_SUCCESS;
sort_array((void*)data, data_size, compare_structs);
for(i = 0; i < data_size - 1; ++i)
{
if (data[i]->year > data[i+1]->year)
{
fprintf(stderr, "\"%s\" and \"%s\" are out of order\n",data[i]->name, data[i+1]->name);
status = EXIT_FAILURE;
}
}
for (i=0; i<data_size; i++)
printf("%d. - %d\n", i, data[i]->year);
return status;
}