Finding Octet in a UDP data payload in C program - c

I am trying to collect UDP data payload information using C program by capturing the packet from port 6343. The code I am using is as follows:
#include<stdio.h> //For standard things
#include<stdlib.h> //malloc
#include<string.h> //memset
#include<netinet/ip_icmp.h> //Provides declarations for icmp header
#include<netinet/udp.h> //Provides declarations for udp header
#include<netinet/tcp.h> //Provides declarations for tcp header
#include<netinet/ip.h> //Provides declarations for ip header
#include<sys/socket.h>
#include<arpa/inet.h>
#include<net/ethernet.h>
#include<netinet/if_ether.h>
#define PORT 6343 // define the port to connect
#define ETH_P_IP 0x0800
void ProcessPacket(unsigned char*, int);
void print_ethernet_header(unsigned char*, int);
void print_ip_header(unsigned char* , int);
void print_udp_packet(unsigned char*, int);
void Dataint (unsigned char* , int);
void print(const int *, const int);
int sockt;
int i,j;
struct sockaddr_in source,dest;
const MAX_HEADER_SIZE = 256; /* The maximum sampled header size. */
struct sampled_header {
header_protocol protocol; /* Format of sampled header */
unsigned int frame_length; /* Original length of packet before
sampling */
opaque header{MAX_HEADER_SIZE}; /* Header bytes */
}
/* Packet IP version 4 data */
struct sampled_ipv4 {
unsigned int length; /* The length of the IP packet excluding
lower layer encapsulations */
unsigned int protocol; /* IP Protocol type
(for example, TCP = 6, UDP = 17) */
ip_v4 src_ip; /* Source IP Address */
ip_v4 dst_ip; /* Destination IP Address */
unsigned int src_port; /* TCP/UDP source port number or
equivalent */
unsigned int dst_port; /* TCP/UDP destination port number or
equivalent */
unsigned int tcp_flags; /* TCP flags */
unsigned int tos; /* IP type of service */
}
/* Packet IP version 6 data */
struct sampled_ipv6 {
unsigned int length; /* The length of the IP packet excluding
lower layer encapsulations */
unsigned int protocol; /* IP next header
(for example, TCP = 6, UDP = 17) */
ip_v6 src_ip; /* Source IP Address */
ip_v6 dst_ip; /* Destination IP Address */
unsigned int src_port; /* TCP/UDP source port number or
equivalent */
unsigned int dst_port; /* TCP/UDP destination port number or
equivalent */
unsigned int tcp_flags; /* TCP flags */
unsigned int priority; /* IP priority */
}
struct extended_switch {
unsigned int src_vlan; /* The 802.1Q VLAN id of incoming frame */
unsigned int src_priority; /* The 802.1p priority of incoming
frame */
unsigned int dst_vlan; /* The 802.1Q VLAN id of outgoing frame */
unsigned int dst_priority; /* The 802.1p priority of outgoing
frame */
}
int main()
{
int saddr_size,data_size, datasize;
struct sockaddr_in saddr;
struct sockaddr_in daddr;
struct in_addr addr;
int protocol=17;
unsigned char* buffer = (unsigned char *)malloc(65535); // Its Big ! Malloc allocates a block of size bytes of memory,returning a pointer to the begining of the block
//Create a socket
sockt = socket(AF_INET ,SOCK_DGRAM ,IPPROTO_UDP);
if(sockt < 0)
{
printf("Socket Error\n");
return 1;
}
memset((char *)&daddr,0,sizeof(daddr));
//prepare the sockaddr_in structure
saddr.sin_family = AF_INET;
daddr.sin_family = AF_INET;
daddr.sin_addr.s_addr = htonl(INADDR_ANY);
daddr.sin_port = htons(PORT);
saddr.sin_port = htons(PORT);
//Bind the socket
if(bind(sockt,(struct sockaddr *)&daddr, sizeof(daddr))<0)
{
printf("bind failed");
return 1;
}
printf("bind done");
while(1)
{
saddr_size = sizeof saddr;
printf(" waiting for data...\n");
//Receive a packet
datasize = recvfrom(sockt , buffer ,65535 , 0 , (struct sockaddr*) &saddr , (socklen_t*)&saddr_size);
data_size = recvfrom(sockt , buffer ,65535 , 0 , NULL , NULL);
if(data_size <0)
{
printf("Packets not recieved \n");
return 1;
}
printf("Packets arrived from %d \n",ntohs(daddr.sin_port));
printf("packet recieved : %lu bytes\n", datasize);
ProcessPacket(buffer , data_size);
}
close(sockt);
printf("Finished");
return 0;
}
void ProcessPacket(unsigned char* buffer, int len)
{
print_udp_packet(buffer , len);
}
void print_ethernet_header(unsigned char* buffer, int len)
{
struct ethhdr *eth = (struct ethhdr *)buffer;
printf("Ethernet Header\n");
printf("---------------------------------------\n");
printf("Ethernet Header Length : %u bytes \n",sizeof(eth));
printf("Destination MAC : %.2X-%.2X-%.2X-%.2X-%.2X-%.2X \n", eth->h_dest[0] , eth->h_dest[1] , eth->h_dest[2] , eth->h_dest[3] , eth->h_dest[4] , eth->h_dest[5] );
printf("Source MAC : %.2X-%.2X-%.2X-%.2X-%.2X-%.2X \n", eth->h_source[0] , eth->h_source[1] , eth->h_source[2] , eth->h_source[3] , eth->h_source[4] , eth->h_source[5] );
printf("Ethernet Type : %u \n",eth->h_proto);
printf("---------------------------------------\n");
}
void print_ip_header(unsigned char* buffer, int len)
{
//print_ethernet_header(buffer , len);
struct iphdr *iph = (struct iphdr *)(buffer + sizeof(struct ethhdr));
unsigned short iphdrlen = iph->ihl*4;
memset(&source,0,sizeof(source));
source.sin_addr.s_addr = iph ->saddr;
memset(&dest,0,sizeof(dest));
dest.sin_addr.s_addr = iph->daddr;
printf("IP Header\n");
printf("---------------------------------------\n");
printf("IP Length : %d\n", ntohs(iph->tot_len));
printf("Source IP : %s\n",inet_ntoa(source.sin_addr));
printf("Destination IP : %s\n",inet_ntoa(dest.sin_addr));
printf("Protocol : %d\n", iph->protocol);
printf("Type Of Service : %d\n",htons(iph->tos));
printf("---------------------------------------\n");
}
void print_udp_packet(unsigned char* buffer , int len)
{
struct sockaddr_in saddr;
struct sockaddr_in daddr;
unsigned short iphdrlen;
unsigned char* payload = (unsigned char *)malloc(1024);
struct iphdr *iph = (struct iphdr *)(buffer+ sizeof(struct ethhdr));
iphdrlen = iph->ihl*4;
struct udphdr *udph = (struct udphdr*)(buffer + sizeof(struct iphdr)+sizeof(struct ethhdr));
int header_size = sizeof(struct ethhdr) + iphdrlen + sizeof udph;
print_ip_header(buffer,len);
printf("UDP Header\n");
printf("---------------------------------------\n");
printf("UDP Length : %d\n", ntohs(udph->len));
//printf("UDP Length : %d\n", ntohs(sizeof (struct udphdr)));
printf("Source Port : %d\n ",ntohs(udph->source));
printf("Destination Port : %d\n ",ntohs(udph->dest));
printf("Source Port : %d\n ",ntohs(saddr.sin_port));
printf("Destination Port : %d\n ",ntohs(daddr.sin_port));
printf("---------------------------------------\n");
printf("Data Payload\n");
//PrintData(buffer + header_size , len - header_size);
Dataint(buffer ,len);
printf("--------------------------------------------\n");
}
void Dataint (unsigned char* buffer , int len)
{
int i,j;
i=0;
for(i=0 ; i <= len ; i++)
{
if( i!=0 && i%16==0) // prints every hex line with a space
{
printf(" ");
}
// prints entire data in integer
if(i%16==0)
printf(" "); // prints the first element of hex line
printf(" %d",(unsigned int)buffer[i]);
//print the last spaces
if( i==len-1)
{
for(j=0;j<16-i%16;j++)
printf(" ");
}
}
}
I have the payload converted to integer form as shown below:
0 0 0 5 0 0 0 1 147 188 192 6 0 0 0 0 0 50 170 143 37 107 3 154 0 0 0 6 0 0 0 1 0 0 0 208 1 30 136 36 0 0 0 29 0 0 1 0 236 205 212 188 0 22 44 215 0 0 0 29 0 0 0 40 0 0 0 2 0 0 0 1 0 0 0 144 0 0 0 1 0 0 5 238 0 0 0 4 0 0 0 128 240 146 28 72 194 0 0 14 12 48 199 199 8 0 69 0 5 220 65 28 64 0 47 6 24 125 193 104 215 69 147 188 192 24 0 80 142 152 237 55 211 205 114 104 162 142 128 16 0 54 188 178 0 0 1 1 8 10 139 71 198 30 37 2 188 177 205 144 135 164 154 194 155 33 30 238 48 113 112 179 62 180 223 221 169 24 234 48 163 41 188 139 148 98 130 255 16 229 123 58 202 165 56 101 14 217 132 108 10 156 47 29 77 156 220 141 202 248 196 75 240 252 232 27 19 140 52 187 0 0 3 233 0 0 0 16 0 0 0 3 0 0 0 2 0 0 0 2 255 255 255 255 0 0 0 1 0 0 0 208 1 30 136 37 0 0 0 29 0 0 1 0 236 205 214 47 0 22 44 215 0 0 0 29 0 0 0 40 0 0 0 2 0 0 0 1 0 0 0 144 0 0 0 1 0 0 5 238 0 0 0 4 0 0 0 128 240 146 28 72 194 0 0 14 12 48 199 199 8 0 69 0 5 220 65 243 64 0 47 6 23 166 193 104 215 69 147 188 192 24 0 80 142 152 237 60 147 229 114 104 162 142 128 16 0 54 13 151 0 0 1 1 8 10 139 71 198 66 37 2 188 213 16 243 209 241 120 208 124 252 85 108 101 62 10 255 21 98 62 58 136 127 106 62 238 76 85 231 227 224 70 62 31 217 151 211 47 106 246 111 160 87 164 114 43 83 45 230 197 131 18 49 110 159 251 162 207 148 178 31 212 40 81 190 0 0 3 233 0 0 0 16 0 0 0 3 0 0 0 2 0 0 0 2 255 255 255 255 0 0 0 1 0 0 0 148 1 30 136 38 0 0 0 29 0 0 1 0 236 205 214 158 0 22 44 215 0 0 0 0 0 0 0 29 0 0 0 2 0 0 0 1 0 0 0 84 0 0 0 1 0 0 0 70 0 0 0 4 0 0 0 68 0 14 12 48 199 199 240 146 28 72 194 0 8 0 69 0 0 52 28 175 64 0 63 6 50 146 147 188 192 24 193 104 215 69 142 152 0 80 114 104 162 142 237 62 109 231 128 16 36 63 51 129 0 0 1 1 8 10 37 2 188 231 139 71 198 66 0 0 0 0 3 233 0 0 0 16 255 255 255 255 0 0 0 0 0 0 0 3 255 255 255 255 0 0 0 1 0 0 0 208 1 30 136 39 0 0 0 29 0 0 1 0 236 205 215 173 0 22 44 215 0 0 0 29 0 0 0 40 0 0 0 2 0 0 0 1 0 0 0 144 0 0 0 1 0 0 5 238 0 0 0 4 0 0 0 128 240 146 28 72 194 0 0 14 12 48 199 199 8 0 69 0 5 220 67 10 64 0 47 6 22 143 193 104 215 69 147 188 192 24 0 80 142 152 237 66 188 223 114 104 162 142 128 16 0 54 185 33 0 0 1 1 8 10 139 71 198 102 37 2 188 248 226 4 177 86 140 52 15 181 49 144 230 162 19 81 72 179 190 46 196 123 24 85 38 153 175 213 96 59 3 73 194 138 211 35 187 143 148 46 200 190 255 249 6 223 220 57 180 2 123 223 184 204 149 28 127 218 240 134 94 247 236 103 0 0 3 233 0 0 0 16 0 0 0 3 0 0 0 2 0 0 0 2 255 255 255 255 0 0 0 1 0 0 0 208 1 30 136 40 0 0 0 29 0 0 1 0 236 205 216 48 0 22 44 215 0 0 0 29 0 0 0 40 0 0 0 2 0 0 0 1 0 0 0 144 0 0 0 1 0 0 5 238 0 0 0 4 0 0 0 128 240 146 28 72 194 0 0 14 12 48 199 199 8 0 69 0 5 220 67 144 64 0 47 6 22 9 193 104 215 69 147 188 192 24 0 80 142 152 237 69 173 223 114 104 162 142 128 16 0 54 47 172 0 0 1 1 8 10 139 71 198 102 37 2 188 249 253 49 241 16 12 100 96 130 25 195 170 251 218 202 149 6 45 216 81 206 145 254 7 147 240 20 103 185 112 138 115 50 158 226 156 204 78 113 98 240 114 65 240 51 253 252 102 174 242 80 12 50 241 179 148 204 90 200 196 66 118 137 0 0 3 233 0 0 0 16 0 0 0 3 0 0 0 2 0 0 0 2 255 255 255 255 0 0 0 1 0 0 0 148 1 30 136 41 0 0 0 29 0 0 1 0 236 205 217 14 0 22 44 215 0 0 0 29 0 0 0 25 0 0 0 2 0 0 0 1 0 0 0 84 0 0 0 1 0 0 0 70 0 0 0 4 0 0 0 68 240 146 28 72 194 0 0 14 12 48 199 199 8 0 69 0 0 52 174 239 0 0 48 6 219 72 216 58 210 78 147 188 194 70 1 187 179 154 222 83 63 174 28 240 175 235 128 16 5 91 120 31 0 0 1 1 8 10 94 165 224 71 49 84 232 65 0 0 0 0 3 233 0 0 0 16 0 0 0 3 0 0 0 2 0 0 0 14 255 255 255 255
This is a sflow data collected from a core switch.So I have to find the Ethernet, IPv4, IPv6,extended switch data from this payload and print them. Before that I need to find the octet position of each of these in the payload. can you advise me how should I find the octet position of each of them ?
Errors while using the structs in above code:
udps.c:25: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘ip_v4’
udps.c:26: error: expected ‘=’, ‘,’, ‘;’, ‘asm’ or ‘__attribute__’ before ‘ip_v6’
udps.c:33: error: two or more data types in declaration specifiers
udps.c:33: error: expected ‘)’ before ‘type’
udps.c:45: error: expected specifier-qualifier-list before ‘header_protocol’
udps.c:58: error: expected specifier-qualifier-list before ‘ip_v4’
udps.c:69: error: two or more data types in declaration specifiers
udps.c:74: error: expected specifier-qualifier-list before ‘ip_v6’
udps.c:87: error: two or more data types in declaration specifiers
udps.c:93: error: two or more data types in declaration specifiers
udps.c:93: error: two or more data types in declaration specifiers
udps.c:93: error: expected ‘)’ before ‘type’
udps.c:115: error: two or more data types in declaration specifiers
udps.c: In function ‘main’:
udps.c:131: error: incompatible types when returning type ‘int’ but ‘struct extended_switch’ was expected
udps.c:147: error: incompatible types when returning type ‘int’ but ‘struct extended_switch’ was expected
udps.c:163: error: incompatible types when returning type ‘int’ but ‘struct extended_switch’ was expected
udps.c:173: error: incompatible types when returning type ‘int’ but ‘struct extended_switch’ was expected

When use create a socket of type AF_INET / SOCK_DGRAM, the operating system processes the Ethernet, IP, and UDP headers and strips them off before passing them to you. What you see in buffer is what immediately follows the UDP header.
The fifth parameter to recvfrom gives you the source IP and source port of the incoming packet. If you want to see more than just that you need to use a packet capture library like libpcap.
Edit:
It seems that this data packet contains IP addresses as part of sflow data. You were trying to parse it as if it was a raw Ethernet frame. What you instead need to do is look at the sflow datagram definition and use that to figure out how the packet is laid out and parse accordingly. You don't need to use memcpy to do that, just use pointers to the relevant structs to point to the proper place in the buffer. This is the same basic technique you were using before, just with a different set of structs.
Edit 2:
It looks like we're way off on what the data looks like. I took the bytes from the packet listed above, read them into a buffer and sent it out in a UDP packet. I fired up Wireshark, which gave us this:
So the packet contains:
The sflow version, 32-bit (5)
an 32 bit int (value=1)
a struct sample_datagram_v5
the number of samples (32-bit int, value=6)
six samples
The first sample contains:
The sample type as a data_format (in this case a flow sample)
a struct flow_sample
the number of flow samples (32-bit int, value=2)
The first flow in the first sample:
The flow type as a data_format (int this case a raw packet sample, so...)
the flow data length (32-bit int, value=144)
a struct sampled_header
4 bytes that are skipped as per the value of sampled_header.stripped
ethernet header
IP header (payload=TCP)
TCP header (port=80)
data bytes (62)
The second flow in the first sample:
The flow type as a data_format (int this case extended switch data)
the flow data length (32-bit int, value=16)
a struct extended_switch
Then five more samples. In this case, all the samples contain a raw packet header and extended switch data.
So this should give you a better idea of what you need to do. Since each data packet will be different, you'll need to figure our how many samples you have. Then for each sample, you'll need to figure out the type, and based on that figure out how to parse the individual flows.
If you need more examples I'd strongly suggest using Wireshark to capture these sflow packets so you can see exactly what's in them to validate that your parser works for all expected input.
Related question for reference: use of memcpy to store data from buffer into struct

Related

Can we reduce ESP IDF boiler plate size?

I tested running bare bones code using ESP IDF on an ESP32 chip using duinotech XC-3800, and obtained the following results in terms of image size.
Analysis Binary Size for ESP32
Folder Structure
temp/
main/
CMakeLists.txt
main.c
CMakeLists.txt
File contents
CMakeLists.txt
# The following lines of boilerplate have to be in your project's
# CMakeLists in this exact order for cmake to work correctly
cmake_minimum_required(VERSION 3.5)
include($ENV{IDF_PATH}/tools/cmake/project.cmake)
project(temp)
main>CMakeLists.txt
idf_component_register(SRCS "main.c"
INCLUDE_DIRS "")
Test 1 main>main.c
#include <stdio.h>
void app_main(void) {
printf("Hello world!\n");
for (int i = 10; i >= 0; i--) {
printf("Restarting in %d seconds...\n", i);
}
printf("Restarting now.\n");
fflush(stdout);
}
Test 2 main>main.c
#include <stdio.h>
void app_main(void) { printf("Hello world!\n"); }
Test 3 main>main.c
void app_main(void) {}
Size comparison
Obtained by running idf_size.py build/temp.map
Test 1
Total sizes:
DRAM .data size: 8320 bytes
DRAM .bss size: 4072 bytes
Used static DRAM: 12392 bytes ( 168344 available, 6.9% used)
Used static IRAM: 38804 bytes ( 92268 available, 29.6% used)
Flash code: 75408 bytes
Flash rodata: 23844 bytes
Total image size:~ 146376 bytes (.bin may be padded larger)
Test 2
Total sizes:
DRAM .data size: 8320 bytes
DRAM .bss size: 4072 bytes
Used static DRAM: 12392 bytes ( 168344 available, 6.9% used)
Used static IRAM: 38804 bytes ( 92268 available, 29.6% used)
Flash code: 75240 bytes
Flash rodata: 23796 bytes
Total image size:~ 146160 bytes (.bin may be padded larger)
Test 3
Total sizes:
DRAM .data size: 8320 bytes
DRAM .bss size: 4072 bytes
Used static DRAM: 12392 bytes ( 168344 available, 6.9% used)
Used static IRAM: 38804 bytes ( 92268 available, 29.6% used)
Flash code: 75004 bytes
Flash rodata: 23780 bytes
Total image size:~ 145908 bytes (.bin may be padded larger)
Analysis
Size for code obtained by running stat --format="%s" main/main.c
All Sizes are in Bytes
Test No. | Code | Image | Flash Code | Flash rodata
-------- | -----| ------ | ---------- | ------------
1 | 207 | 146376 | 75408 | 23844
2 | 70 | 146160 | 75240 | 23796
3 | 43 | 145908 | 75004 | 23780
At least 145KB of boiler plate code just to get an empty main run.
Speculation
I suspect that the 145KB is made up of a number of libraries that are always loaded onto the chip whether you use them or not. Some of them must be the FreeRTOS, WiFi, HTTP etc.
Can we bring down this size somehow and load only the bare minimum required for operation?
You can get more detailed size information by running idf.py size-components and idf.py size-files. Here are the results for your "Test 3" (i.e. empty function) on my dev environment (note that my Total Image Size is already slightly larger than the one you posted.
Total sizes:
DRAM .data size: 7860 bytes
DRAM .bss size: 4128 bytes
Used static DRAM: 11988 bytes ( 168748 available, 6.6% used)
Used static IRAM: 32706 bytes ( 98366 available, 25.0% used)
Flash code: 76002 bytes
Flash rodata: 32164 bytes
Total image size:~ 148732 bytes (.bin may be padded larger)
Per-archive contributions to ELF file:
Archive File DRAM .data & .bss IRAM Flash code & rodata Total
libc.a 0 0 0 55348 3829 59177
libesp32.a 2132 2351 6767 5976 8076 25302
libfreertos.a 4140 776 12432 0 1653 19001
libdriver.a 76 20 0 4003 7854 11953
libsoc.a 161 4 4953 612 3852 9582
libvfs.a 240 103 0 5464 950 6757
libheap.a 877 4 3095 830 986 5792
libspi_flash.a 24 290 1855 779 890 3838
libefuse.a 16 4 0 1142 2213 3375
libnewlib.a 152 272 766 830 96 2116
libapp_update.a 0 4 109 159 1221 1493
libesp_ringbuf.a 0 0 848 0 209 1057
liblog.a 8 268 429 82 0 787
libhal.a 0 0 515 0 32 547
libpthread.a 8 12 0 256 0 276
libgcc.a 0 0 0 0 160 160
libbootloader_support.a 0 0 0 126 0 126
libm.a 0 0 0 88 0 88
libcxx.a 0 0 0 11 0 11
libxtensa-debug-module.a 0 0 8 0 0 8
libmain.a 0 0 0 5 0 5
(exe) 0 0 0 0 0 0
libmbedcrypto.a 0 0 0 0 0 0
libmbedtls.a 0 0 0 0 0 0
libwpa_supplicant.a 0 0 0 0 0 0
Per-file contributions to ELF file:
Object File DRAM .data & .bss IRAM Flash code & rodata Total
lib_a-vfprintf.o 0 0 0 14193 756 14949
lib_a-svfprintf.o 0 0 0 13838 756 14594
lib_a-svfiprintf.o 0 0 0 9642 1210 10852
lib_a-vfiprintf.o 0 0 0 9945 738 10683
uart.c.obj 44 12 0 2985 7293 10334
tasks.c.obj 12 700 5546 0 531 6789
vfs_uart.c.obj 48 63 0 3680 808 4599
panic.c.obj 2023 5 1989 0 0 4017
esp_err_to_name.c.obj 0 0 0 50 3947 3997
portasm.S.obj 3084 0 484 0 0 3568
lib_a-dtoa.o 0 0 0 3522 13 3535
multi_heap.c.obj 873 0 2277 0 0 3150
intr_alloc.c.obj 8 22 618 1703 722 3073
esp_efuse_utility.c.obj 0 0 0 867 2205 3072
cpu_start.c.obj 0 1 1068 331 1352 2752
queue.c.obj 0 0 2310 0 325 2635
lib_a-mprec.o 0 0 0 2134 296 2430
rtc_clk.c.obj 161 4 2098 0 0 2263
dbg_stubs.c.obj 0 2072 32 108 0 2212
vfs.c.obj 192 40 0 1784 142 2158
rtc_periph.c.obj 0 0 0 0 2080 2080
esp_timer_esp32.c.obj 8 26 1068 262 538 1902
xtensa_vectors.S.obj 8 0 1776 0 36 1820
flash_mmap.c.obj 0 264 1092 114 339 1809
task_wdt.c.obj 53 4 0 1178 548 1783
heap_caps.c.obj 4 0 818 52 617 1491
timers.c.obj 8 56 1006 0 233 1303
cache_utils.c.obj 4 14 749 81 402 1250
soc_memory_layout.c.obj 0 0 0 0 1181 1181
heap_caps_init.c.obj 0 4 0 778 369 1151
port.c.obj 0 16 625 0 493 1134
esp_ota_ops.c.obj 0 4 0 147 965 1116
xtensa_intr_asm.S.obj 1024 0 51 0 0 1075
ringbuf.c.obj 0 0 848 0 209 1057
rtc_time.c.obj 0 0 815 0 198 1013
memory_layout_utils.c.ob 0 0 0 612 393 1005
rtc_init.c.obj 0 0 992 0 0 992
periph_ctrl.c.obj 8 0 0 615 280 903
lib_a-fseeko.o 0 0 0 866 0 866
time.c.obj 0 32 122 703 0 857
clk.c.obj 0 0 64 559 221 844
esp_timer.c.obj 8 16 261 406 134 825
dport_access.c.obj 8 40 444 189 137 818
log.c.obj 8 268 429 82 0 787
rtc_wdt.c.obj 0 0 743 0 0 743
partition.c.obj 0 8 0 522 149 679
ipc.c.obj 0 28 159 283 120 590
locks.c.obj 8 0 485 0 94 587
crosscore_int.c.obj 8 8 193 130 156 495
syscall_table.c.obj 144 240 0 82 0 466
system_api.c.obj 0 0 439 0 0 439
timer.c.obj 16 0 0 112 281 409
int_wdt.c.obj 0 1 91 306 0 398
freertos_hooks.c.obj 8 128 43 216 0 395
esp_app_desc.c.obj 0 0 109 12 256 377
brownout.c.obj 0 0 0 149 201 350
windowspill_asm.o 0 0 311 0 0 311
rtc_module.c.obj 8 8 0 291 0 307
xtensa_context.S.obj 0 0 306 0 0 306
cpu_util.c.obj 0 0 305 0 0 305
dport_panic_highint_hdl. 8 0 242 0 0 250
lib_a-reent.o 0 0 0 232 0 232
lib_a-fopen.o 0 0 0 224 0 224
lib_a-snprintf.o 0 0 0 214 0 214
esp_efuse_api.c.obj 0 4 0 193 0 197
pthread_local_storage.c. 8 4 0 180 0 192
cache_err_int.c.obj 0 0 56 98 0 154
xtensa_intr.c.obj 0 0 108 0 35 143
list.c.obj 0 0 142 0 0 142
syscalls.c.obj 0 0 91 45 0 136
lib_a-assert.o 0 0 0 68 60 128
lib_a-flags.o 0 0 0 127 0 127
bootloader_common.c.obj 0 0 0 126 0 126
lib_a-s_frexp.o 0 0 0 110 0 110
flash_ops.c.obj 20 4 14 62 0 100
lib_a-vprintf.o 0 0 0 94 0 94
lib_a-s_fpclassify.o 0 0 0 88 0 88
lib_a-fiprintf.o 0 0 0 84 0 84
pthread.c.obj 0 8 0 76 0 84
esp_efuse_fields.c.obj 0 0 0 82 0 82
clock.o 0 0 72 0 0 72
reent_init.c.obj 0 0 68 0 2 70
state_asm--restore_extra 0 0 62 0 0 62
state_asm--save_extra_nw 0 0 62 0 0 62
xtensa_vector_defaults.S 0 0 46 0 0 46
lib_a-fseek.o 0 0 0 45 0 45
_divdi3.o 0 0 0 0 40 40
_moddi3.o 0 0 0 0 40 40
_udivdi3.o 0 0 0 0 40 40
_umoddi3.o 0 0 0 0 40 40
xtensa_init.c.obj 0 4 32 0 0 36
interrupts--intlevel.o 0 0 0 0 32 32
esp_efuse_table.c.obj 16 0 0 0 8 24
lib_a-errno.o 0 0 0 10 0 10
pm_esp32.c.obj 0 0 0 8 0 8
int_asm--set_intclear.o 0 0 8 0 0 8
eri.c.obj 0 0 8 0 0 8
cxx_exception_stubs.cpp. 0 0 0 6 0 6
cxx_guards.cpp.obj 0 0 0 5 0 5
hello_world_main.c.obj 0 0 0 5 0 5
FreeRTOS-openocd.c.obj 4 0 0 0 0 4
dummy_main_src.c.obj 0 0 0 0 0 0
bootloader_flash.c.obj 0 0 0 0 0 0
bootloader_random.c.obj 0 0 0 0 0 0
bootloader_sha.c.obj 0 0 0 0 0 0
esp_image_format.c.obj 0 0 0 0 0 0
flash_partitions.c.obj 0 0 0 0 0 0
lib_a-fputs.o 0 0 0 0 0 0
lib_a-printf.o 0 0 0 0 0 0
lib_a-putc.o 0 0 0 0 0 0
lib_a-putchar.o 0 0 0 0 0 0
lib_a-puts.o 0 0 0 0 0 0
lib_a-sprintf.o 0 0 0 0 0 0
lib_a-strerror.o 0 0 0 0 0 0
lib_a-u_strerr.o 0 0 0 0 0 0
lib_a-xpg_strerror_r.o 0 0 0 0 0 0
gpio.c.obj 0 0 0 0 0 0
hw_random.c.obj 0 0 0 0 0 0
pm_locks.c.obj 0 0 0 0 0 0
_addsubdf3.o 0 0 0 0 0 0
_cmpdf2.o 0 0 0 0 0 0
_divdf3.o 0 0 0 0 0 0
_fixdfsi.o 0 0 0 0 0 0
_floatdidf.o 0 0 0 0 0 0
_floatsidf.o 0 0 0 0 0 0
_muldf3.o 0 0 0 0 0 0
_popcountsi2.o 0 0 0 0 0 0
platform.c.obj 0 0 0 0 0 0
platform_util.c.obj 0 0 0 0 0 0
sha256.c.obj 0 0 0 0 0 0
esp_mem.c.obj 0 0 0 0 0 0
gpio_periph.c.obj 0 0 0 0 0 0
spi_flash_rom_patch.c.ob 0 0 0 0 0 0
md5-internal.c.obj 0 0 0 0 0 0
From a library point of view, the major contributor is libc which is the C standard library. While you could probably cherry-pick some functions and drop others from there, I don't think anyone would recommend that.
Next up is libesp32, which provides critical functions such as start_cpu0(). Again, you may be able to cherry-pick only the functions you need, if you really want to.
You can figure out what a library provides by looking up the .a file (e.g. find build -name libesp32.a, and then running nm build/esp-idf/esp32/libesp32.a on the found path.
The second table lists the same size-data, but split per source-file instead of per library.

RxAndroidBle, value should be in Hexadecimal

Values from the notification should be hexadecimal but I got decimal and negative values (with another app I got the good format) :
123 0 0 72 98 0
124 0 0 39 97 0
125 0 0 -2 95 0
126 0 0 -50 94 0
127 0 0 -105 93 0
-128 0 0 88 92 0
-127 0 0 18 91 0
-126 0 0 -59 89 0
-125 0 0 113 88 0
-124 0 0 22 87 0
-123 0 0 -76 85 0
-122 0 0 76 84 0
-121 0 0 -35 82 0
-120 0 0 103 81 0
Do you know how can I get this in Hexadecimal form?
Best regards
The RxAndroidBle library emits a byte[] when a notification is received. A single byte value can be represented in a different ways.
The log you have presented is just printing the raw values according to Java specification. Java does not have a concept of unsigned values and every value that starts with a 1 bit is treated as a negative number. i.e. 0xA2 is equivalent to -94. (0xA2 == -94) == true
A simple way to display a value as a hex is to use String.format() i.e. String.format("0x%2xh", byteValue)
Most probably you wanted to ask a question: How to convert a byte array to a hex String in Java
I wrote a little method to convert a byte[] into a String that looks like [02 FC 41 5A] etc.:
static String byteArrayToHexDigits(final byte[] bytes) {
int i;
StringBuilder result = new StringBuilder( "[" );
for( i = 0; i < (bytes.length-1); i++ ) {
result.append(String.format( "%02X ", bytes[i] ));
}
result.append(String.format( "%02X]", bytes[i] ));
return result.toString();
}

Store paths of 1's and 0's from root to leaf of a tree (Huffman coding)

I built a tree to be used for Huffman compression. I want to traverse this tree from root to leaf for all leaves. Along these traversals, I would like to store a 0 if the left path was taken and a 1 if the right path was taken. My code works for the leftmost leaf, but when it should store the path of its sibling, it only goes back to the parent node instead of the root node and then goes to the right and stores only a 1 instead of 01.
tree
132 void printArr(){
133 int i;
134 for(i=0; i<top; i++){
135 printf("%d\n", arr[i]);
136 }
137 printf("\n");
138 }
139
140 void storeCode(Node *rootNode){
141
142 if(rootNode->left){
143 arr[top] = 0;
144 top += 1;
145 storeCode(rootNode->left);
146 }
147 if(rootNode->right){
148 arr[top] = 1;
149 top += 1;
150 storeCode(rootNode->right);
151 }
152 if(isLeafNode(rootNode)){
153 arr[top] = rootNode->data;
154 top += 1;
155 return;
156 }
157
158 }
The result looks like this (the non 0 or 1 numbers are the characters):
0 0 103 1 111 1 0 0 115 1 32 1 0 0 101 1 104 1 0 112 1 114
The result should look like this:
0 0 103 0 1 111 1 0 0 115 1 0 1 32 1 1 0 0 101 1 1 0 1 104 1 1 1 0 112 1 1 1 1 114
How do I change my code so that the function traverses the tree from the root to a different leaf each time (until all leaves have been visited).

Working with PPM image as an int *img

I've been trying to implement the MSF using a grayscale PPM image and a template. I need to declare the image as "*int" img instead of unsigned char img. But when I compute the zero-mean center at the template, I get values that doesn't make any sense. I tried unsigned char and it gives the right pixel values before the zero-mean center and wrong after because 'unsigned char' does't have enough 'space' and doesn't accept negative values but at least it's consistent values. I know it's a silly mistake but I'm stuck on it. Could anyone help me on how could I implement it using int*? Thanks
Below is part of my code and both results
FILE *fpt1, *fpt2, *fpt3;
int *img, *gt, *int;
char header[320], header2[320];
int COLS, ROWS, BYTES, COLS2, ROWS2, BYTES2, i, len;
int r , c, count, sum;
/*Read template*/
fpt2 = fopen("parenthood_e_template.ppm", "r");
if (fpt2 == NULL){
printf("Unable to open template of parenthood.ppm for reading\n");
exit(0);
}
fscanf(fpt2,"%s %d %d %d\n", header2, &COLS2, &ROWS2, &BYTES2);
if (strcmp(header2, "P5") != 0 || BYTES2 != 255){
printf("Not a template for parenthood.ppm\n");
exit(0);
}
/*Allocate memory for template*/
temp = (int*) calloc (COLS2*ROWS2, sizeof(int));
/* Copy template into memory*/
header2[0] = fgetc(fpt2);
fread(temp,1,COLS2*ROWS2,fpt2);
fclose(fpt2);
/* Matched Spatial-Filter */
/* zero-mean the template*/
sum=0;
count=0;
for (r=0; r<ROWS2; r++) {
for (c=0; c<COLS2; c++) {
sum += temp[r*COLS2+c];
printf("temp[%d]= %d\n", count, temp[r*COLS2+c]);
count += 1;
}
}
sum = sum/126;
The result for char*
temp[0]= 199
temp[1]= 196
temp[2]= 199
temp[3]= 198
temp[4]= 198
temp[5]= 199
temp[6]= 199
temp[7]= 202
temp[8]= 197
temp[9]= 196
temp[10]= 195
temp[11]= 198
temp[12]= 200
temp[13]= 197
temp[14]= 199
temp[15]= 199
temp[16]= 198
temp[17]= 195
temp[18]= 196
temp[19]= 196
temp[20]= 199
temp[21]= 197
temp[22]= 198
temp[23]= 196
temp[24]= 196
temp[25]= 193
temp[26]= 194
temp[27]= 195
temp[28]= 193
temp[29]= 155
temp[30]= 133
temp[31]= 150
temp[32]= 187
temp[33]= 196
temp[34]= 196
temp[35]= 195
temp[36]= 192
temp[37]= 109
temp[38]= 69
temp[39]= 105
temp[40]= 88
temp[41]= 78
temp[42]= 184
temp[43]= 194
temp[44]= 193
temp[45]= 145
temp[46]= 74
temp[47]= 177
temp[48]= 189
temp[49]= 186
temp[50]= 100
temp[51]= 105
temp[52]= 191
temp[53]= 191
temp[54]= 72
temp[55]= 139
temp[56]= 191
temp[57]= 192
temp[58]= 188
temp[59]= 168
temp[60]= 46
temp[61]= 183
temp[62]= 186
temp[63]= 43
temp[64]= 89
temp[65]= 110
temp[66]= 114
temp[67]= 114
temp[68]= 107
temp[69]= 37
temp[70]= 176
temp[71]= 191
temp[72]= 43
temp[73]= 126
temp[74]= 133
temp[75]= 133
temp[76]= 137
temp[77]= 129
temp[78]= 132
temp[79]= 187
temp[80]= 191
temp[81]= 52
temp[82]= 167
temp[83]= 188
temp[84]= 192
temp[85]= 195
temp[86]= 195
temp[87]= 195
temp[88]= 191
temp[89]= 189
temp[90]= 94
temp[91]= 108
temp[92]= 189
temp[93]= 193
temp[94]= 192
temp[95]= 191
temp[96]= 192
temp[97]= 192
temp[98]= 193
temp[99]= 173
temp[100]= 49
temp[101]= 141
temp[102]= 175
temp[103]= 177
temp[104]= 108
temp[105]= 125
temp[106]= 195
temp[107]= 199
temp[108]= 197
temp[109]= 163
temp[110]= 90
temp[111]= 70
temp[112]= 75
temp[113]= 109
temp[114]= 180
temp[115]= 191
temp[116]= 194
temp[117]= 197
temp[118]= 193
temp[119]= 192
temp[120]= 185
temp[121]= 188
temp[122]= 195
temp[123]= 196
temp[124]= 195
temp[125]= 0
C= 9 R= 14
temp = 35 mean=161
And the result for int*
temp[0]= -959986489
temp[1]= -892876858
temp[2]= -960248635
temp[3]= -943209016
temp[4]= -993737786
temp[5]= -993606201
temp[6]= -1010646588
temp[7]= -1769628735
temp[8]= -1010514757
temp[9]= 1766157760
temp[10]= -1028108712
temp[11]= -1320513087
temp[12]= 1768209085
temp[13]= -1958166593
temp[14]= -1464024897
temp[15]= 733656878
temp[16]= 1920101977
temp[17]= -1078975125
temp[18]= -2054848981
temp[19]= -1148943991
temp[20]= -1129892673
temp[21]= -1010580544
temp[22]= 1818148287
temp[23]= -1077886531
temp[24]= -1379811136
temp[25]= -1313895119
temp[26]= -943489684
temp[27]= 1180345285
temp[28]= -1078694581
temp[29]= -1061042750
temp[30]= -993805127
temp[31]= 195
temp[32]= 0
temp[33]= 0
temp[34]= 0
temp[35]= 0
temp[36]= 0
temp[37]= 0
temp[38]= 0
temp[39]= 0
temp[40]= 0
temp[41]= 0
temp[42]= 0
temp[43]= 0
temp[44]= 0
temp[45]= 0
temp[46]= 0
temp[47]= 0
temp[48]= 0
temp[49]= 0
temp[50]= 0
temp[51]= 0
temp[52]= 0
temp[53]= 0
temp[54]= 0
temp[55]= 0
temp[56]= 0
temp[57]= 0
temp[58]= 0
temp[59]= 0
temp[60]= 0
temp[61]= 0
temp[62]= 0
temp[63]= 0
temp[64]= 0
temp[65]= 0
temp[66]= 0
temp[67]= 0
temp[68]= 0
temp[69]= 0
temp[70]= 0
temp[71]= 0
temp[72]= 0
temp[73]= 0
temp[74]= 0
temp[75]= 0
temp[76]= 0
temp[77]= 0
temp[78]= 0
temp[79]= 0
temp[80]= 0
temp[81]= 0
temp[82]= 0
temp[83]= 0
temp[84]= 0
temp[85]= 0
temp[86]= 0
temp[87]= 0
temp[88]= 0
temp[89]= 0
temp[90]= 0
temp[91]= 0
temp[92]= 0
temp[93]= 0
temp[94]= 0
temp[95]= 0
temp[96]= 0
temp[97]= 0
temp[98]= 0
temp[99]= 0
temp[100]= 0
temp[101]= 0
temp[102]= 0
temp[103]= 0
temp[104]= 0
temp[105]= 0
temp[106]= 0
temp[107]= 0
temp[108]= 0
temp[109]= 0
temp[110]= 0
temp[111]= 0
temp[112]= 0
temp[113]= 0
temp[114]= 0
temp[115]= 0
temp[116]= 0
temp[117]= 0
temp[118]= 0
temp[119]= 0
temp[120]= 0
temp[121]= 0
temp[122]= 0
temp[123]= 0
temp[124]= 0
temp[125]= 0
C= 9 R= 14
temp = -8605725 mean=8605725

Can't get negative inputs set to zero. How can negative arrays get set?

The following code works for all positive inputs correctly but, negative values are bogus. It would work if negative values are set to 0 initially, because they do add. Example at the end.
#include <stdio.h> /* Necessary header */
#define MAX_RESPONDENTS 6
#define MIN_RESPONSE_VALUE -100 /* Abbreviated MiRV */
#define MAX_RESPONSE_VALUE 86 /* Abbreviated MaRV */
#define RESPONSE_VALUE 187 /* Equals |(MiRV)| + or - |(MaRV)| + 1 */
#define STOP 3
#define BREAK 1
int main(void)
{
CountRating();
return 0;
}
CountRating()
{
int ratingCounters, rating[RESPONSE_VALUE] = {0}, Counter, response;
for (ratingCounters = 0; ratingCounters < MAX_RESPONDENTS;)
{
int response = ratingCounters, stop = STOP;
printf("Enter a integer rating between %d and %d for the product: ", MIN_RESPONSE_VALUE, MAX_RESPONSE_VALUE);
scanf("%d", &response);
if (response <= MAX_RESPONSE_VALUE && response >= MIN_RESPONSE_VALUE)
stop = STOP;
else
{
int stopElse = stop;
if (stopElse < BREAK)
break;
else
{
do
{
printf("\nNot within range. Try again.\nYou have %d more attempts before program outputs total:", stop);
scanf("%d", &response);
printf("\n");
--stop;
if (stop < BREAK)
break;
} while (response > MAX_RESPONSE_VALUE || response < MIN_RESPONSE_VALUE);
} if (stop < BREAK)
break;
}
++rating[response];
++ratingCounters;
}
printf("\nRating Number of Responses\n");
printf("------ -------------------");
for (Counter = MAX_RESPONSE_VALUE; Counter >= MIN_RESPONSE_VALUE; --Counter)
{
printf("\n%3d%24d", Counter, rating[Counter]);
}
}
Example Output:
Enter a integer rating between -100 and 86 for the product: 66
Enter a integer rating between -100 and 86 for the product: 66
Enter a integer rating between -100 and 86 for the product: 66
Enter a integer rating between -100 and 86 for the product: 66
Enter a integer rating between -100 and 86 for the product: 66
Enter a integer rating between -100 and 86 for the product: 55
Rating Number of Responses
------ -------------------
86 0
85 0
84 0
83 0
82 0
81 0
80 0
79 0
78 0
77 0
76 0
75 0
74 0
73 0
72 0
71 0
70 0
69 0
68 0
67 0
66 5
65 0
64 0
63 0
62 0
61 0
60 0
59 0
58 0
57 0
56 0
55 1
54 0
53 0
52 0
51 0
50 0
49 0
48 0
47 0
46 0
45 0
44 0
43 0
42 0
41 0
40 0
39 0
38 0
37 0
36 0
35 0
34 0
33 0
32 0
31 0
30 0
29 0
28 0
27 0
26 0
25 0
24 0
23 0
22 0
21 0
20 0
19 0
18 0
17 0
16 0
15 0
14 0
13 0
12 0
11 0
10 0
9 0
8 0
7 0
6 0
5 0
4 0
3 0
2 0
1 0
0 0
-1 55
-2 2686244
-3 2686244
-4 -3
-5 4206858
-6 4199517
-7 1965606432
-8 -2
-9 -533773290
-10 1965657301
-11 2686916
-12 1965975817
-13 2685900
-14 28
-15 2685972
-16 0
-17 2686720
-18 -1792050746
-19 1965606432
-20 1966156064
-21 1
-22 1965606483
-23 2685944
-24 17
-25 1965552124
-26 2685880
-27 1966146752
-28 1965532226
-29 2685868
-30 1966156064
-31 1
-32 0
-33 1966156064
-34 0
-35 28
-36 6105760
-37 1
-38 1965551966
-39 1965572357
-40 -2
-41 -533740746
-42 1965657301
-43 2685928
-44 1966156064
-45 2685768
-46 28
-47 1965572357
-48 0
-49 1966156064
-50 28
-51 -1792050874
-52 1965572357
-53 1
-54 1965572401
-55 2685816
-56 6097440
-57 1965552169
-58 2685752
-59 36
-60 1966146816
-61 0
-62 1966146816
-63 36
-64 0
-65 -1792050942
-66 1965552271
-67 1965552263
-68 2685756
-69 6105754
-70 4104
-71 4096
-72 6097428
-73 36
-74 -2
-75 358724962
-76 1999401429
-77 2685928
-78 -1
-79 2685472
-80 16777216
-81 6094848
-82 1
-83 0
-84 6105755
-85 6105760
-86 6095044
-87 8
-88 2
-89 1999167428
-90 1
-91 6095044
-92 -218103565
-93 2685640
-94 -254549010
-95 0
-96 1136989510
-97 -503245737
-98 2752512
-99 6098688
-100 0
Process returned 0 (0x0) execution time : 9.734 s
Press any key to continue.
Rating is an array of size 187. You're indexing negative values, which means C is accessing memory before the beginning of the array and printing whatever garbage values are stored there. You can only access values between 0 and 186 legally, so you should just add 100 to the index whenever you access and store rating. That way, the number -100 corresponds to index 0, -99 to index 1, etc.
The index of an array always starts from zero. You should not pass a negative index for an array. If you want to have negative indexes, add a constant to the index.
In your example code, you can add -MIN_RESPONSE_VALUE to the index, so accessing rating[k - MIN_RESPONSE] if you want to access index k.
Your code is assigning to negative indices of an array. This is generally not good - you have only reserved memory from 0:RESPONSE_VALUE-1, writing to anything outside that range will have unpredictable consequences. You have two general options. One is to map your range MIN_RESPONSE_VALUE:MAX_RESPONSE_VALUE to 0:(MAX_RESPONSE_VALUE-MIN_RESPONSE_VALUE). I.e. subtract MIN_RESPONSE_VALUE whenever you index rating:
++rating[response-MIN_RESPONSE_VALUE];
The other is to repoint response, giving it a new zero point. This will save you from having to subtract MIN_RESPONSE_VALUE all the time, but may be confusing to readers:
rating -= MIN_RESPONSE_VALUE;
Do this before the for loop. After doing this, rating[MIN_RESPONSE_VALUE] is a valid index, even though it is negative.
Actually the negative index is totally acceptable. The problem is that you index goes into areas outside memory dedicated for array on the stack. Changing rating[-1] you changing your stack outside the array and thus corrupting it. No wonder the values there are not initialized to zero with rating[RESPONSE_VALUE] = {0}, again they are outside the array and show you some data on your stack.
Took me a while but I got it. Thanks.
#include <stdio.h> /* Necessary header */
#define MAX_RESPONDENTS 6
#define MIN_RESPONSE_VALUE -100 /* Abbreviated MiRV */
#define MAX_RESPONSE_VALUE 86 /* Abbreviated MaRV */
#define RESPONSE_VALUE 187 /* Equals |(MiRV)| + or - |(MaRV)| + 1 */
#define STOP 3
#define BREAK 1
#define DOUBLE_RESPONSE_VALUE 374
int main(void)
{
CountRating();
return 0;
}
CountRating()
{
int ratingCounters, rating[DOUBLE_RESPONSE_VALUE] = {0}, Counter, response;
for (ratingCounters = 0; ratingCounters < MAX_RESPONDENTS;)
{
int response = ratingCounters, stop = STOP;
printf("Enter a integer rating between %d and %d for the product: ", MIN_RESPONSE_VALUE, MAX_RESPONSE_VALUE);
scanf("%d", &response);
if (response <= MAX_RESPONSE_VALUE && response >= MIN_RESPONSE_VALUE)
stop = STOP;
else
{
int stopElse = stop;
if (stopElse < BREAK)
break;
else
{
do
{
printf("\nNot within range. Try again.\nYou have %d more attempts before program outputs total:", stop);
scanf("%d", &response);
printf("\n");
--stop;
if (stop < BREAK)
break;
} while (response > MAX_RESPONSE_VALUE || response < MIN_RESPONSE_VALUE);
} if (stop < BREAK)
break;
}
if (response < 0)
++rating[response + abs(RESPONSE_VALUE)];
else
++rating[response + abs(RESPONSE_VALUE)];
++ratingCounters;
}
printf("\nRating Number of Responses\n");
printf("------ -------------------");
for (Counter = MAX_RESPONSE_VALUE; Counter >= MIN_RESPONSE_VALUE; --Counter)
{
printf("\n%3d%24d", Counter, rating[Counter + (RESPONSE_VALUE)]);
}
}

Resources