How do i get ascii character from read? - c

in this program, I need to store the frequency of the ascii characters i read in an array (in order to print the most frequent). the problem is that what i get from read is not ascii (most probably some kind of address) so in the buf[] array i get out of bounds.
Can anybody tell help me with that?
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <stdio.h>
#include<stdlib.h>
#include<unistd.h>
#include<strings.h>
#define MODEMDEVICE "/dev/ttyAMA0"
#define FALSE 0
#define TRUE 1
volatile int STOP=FALSE;
int main()
{
int fd,c, res=0,i;
struct termios oldtio,newtio;
int buf[128] ;
for (i=0;i<128;i++) buf[i]=0;
fd = open(MODEMDEVICE, O_RDWR | O_NOCTTY );
if (fd <0) {perror(MODEMDEVICE); exit(-1); }
tcflush(fd, TCIFLUSH);
while (STOP==FALSE) { /* loop until we have a terminating condition */
int r=read(fd,&c,1);
write(1,&c,1);
if (c=='\n') {
for(i=0;i<128;i++)
if (res < buf[i] )
res = buf[i];
printf("first char %d \n", res);
}
else {
buf[c]++;
}
}
}

int c creates a variable of probably 4 bytes. It is not initialized, thus it may contain any garbage.
Then the system call
read(fd,&c,1)
changes one of these bytes, probably the highest or lowest, while leaving the others unchanged. Now you have a combination of 3 bytes of random garbage plus the one byte fresh from fd, placed somewhere in c.
And then you try to get sense out of that combination.
Things might work much better if you define c as char:
char c;

Related

Writing an array to a file using C

I am creating a model of Unix v6 File system. I have tried to first allocate the available free blocks by writing it to the file and then reading the same when need. I am having a free array of 100 blocks, so when the number of free blocks goes beyond hundred, the present free array will be written to the memory block in free[0] and the new free block will be assigned to free[0]. The following is the sample code that I have written
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
void splitCommand(char**,char*, char*);
unsigned short freeArr[100];
unsigned short nfree=1,fd;
int main()
{
fd = open("v6", O_RDWR | O_CREAT | O_TRUNC, S_IREAD | S_IEXEC | S_IWRITE);
freeArr[0] = 0;
for (int i = 28; i < 5000; i++)
{
addFreeBlock(i);
}
unsigned short free1=0 ;
lseek(fd, 3127 * 512, SEEK_SET);
read(fd, &(nfree), sizeof(unsigned short));
printf("%d\n",nfree);
for(int i=0; i<nfree; i++)
{
read(fd, &free1, sizeof(unsigned short));
printf("%d\n",free1);
}
}
void addFreeBlock(int block_no)
{
if(block_no==3127)
{
int a=0;
}
if (nfree == 100)
{
lseek(fd, block_no * 512, SEEK_SET);
write(fd, &(nfree), sizeof(unsigned short)); // copy nfree into free array
write(fd, freeArr, 200);// copy free array
nfree=0;
}
freeArr[nfree] = block_no;
nfree++;
}
Consider we have 5000 blocks in total. Each block is 512 bytes long. I am using the first 27 blocks for other purposes and so I am writing the blocks from 28 to 5000.
Now after writing all the blocks, I tried reading the blocks stored at random location. When I tried reading the blocks stored at 3027, I am able to read the 100 blocks numbered from 2927,2928,2929,....,3026. But when I read the blocks stored at 3127, I am able to read only the blocks from 3027, 3028, 3029,....,3081. The remaining is just random. I also tried at some other positions. It works for some of them.
Can anyone tell me where I went wrong?
Sorry, this is not really an answer but I cannot write this in a comment. It does however answer the question somehow.
Your code works correctly, I tested with valgrind and there are no errors, but you should think about it a lot.
There is no need for a single global variable in your code, you should only use a global variable when you really know there is no better solution, this is an improved version of your exact code,
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <unistd.h>
#include <fcntl.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <stdint.h>
uint16_t add_free_block(int fd, int block_number, uint16_t *free_blocks, uint16_t free_block_count);
int main(void)
{
uint16_t free_blocks[100];
uint16_t free_block_count;
int fd;
fd = open("v6", O_RDWR | O_CREAT | O_TRUNC, S_IREAD | S_IEXEC | S_IWRITE);
if (fd == -1)
return -1;
free_blocks[0] = 0;
free_block_count = 1;
for (int i = 28; i < 5000; i++) {
free_block_count = add_free_block(fd, i, free_blocks, free_block_count);
}
lseek(fd, 3127 * 512, SEEK_SET);
read(fd, &free_block_count, sizeof(uint16_t));
printf("%d\n", free_block_count);
for (int i = 0; i < free_block_count; i++) {
uint16_t block_number;
if (read(fd, &block_number, sizeof(uint16_t)) == sizeof(uint16_t)) {
printf("%d\n", block_number);
}
}
close(fd);
return 0;
}
uint16_t
add_free_block(int fd, int block_number, uint16_t *free_blocks, uint16_t free_block_count)
{
if (free_block_count == 100) {
lseek(fd, block_number * 512, SEEK_SET);
write(fd, &free_block_count, sizeof(uint16_t));
write(fd, free_blocks, free_block_count * sizeof(uint16_t));
free_block_count = 0;
}
free_blocks[free_block_count] = block_number;
return free_block_count + 1;
}
with 0 global variables (also, minor but important I closed the file descriptor).
You should also check other return values like write(), I didn't because I didn't want to do it all, I just wanted check what was wrong.
The real problem lies somewhere else in the rest of your program, not in this code. So please POST the real code and stop guessing what the problem is.
In general, these are my recommendations
DO NOT USE GLOBAL VARIABLES, unless you are very, very sure you MUST.
Add the function prototype.
DO NOT IGNORE compiler warnings.
ALWAYS check the return value of a function that does return, if you don't know that it does return, then 5.
READ carefully all the documentation for every function you use.

whats wrong with this code of reading with mmap?

I am trying to run this code, while I am ending with -
value: 1
value: 0.000000
My question is why the both results are different??
#include <stdio.h>
#include <stdlib.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <string.h>
#include <unistd.h>
int main ()
{
int fd;
struct stat mystat;
void *pmap;
int i,integer;
double *values;
int32_t *mapped_baseA;
int32_t fdA;
fd = open("test.txt",O_RDWR); // a text file containing- 1 2 3 4 5
if(fd==-1)
{
perror("open");
exit(1);
}
if(fstat(fd,&mystat)<0)
{
perror("fstat");
close(fd);
exit(1);
}
pmap = mmap(0,mystat.st_size,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);
if(pmap==MAP_FAILED)
{
perror("mmap failed");
close(fd);
exit(1);
}
//strncpy(pmap,"That is my name",15);
sscanf (pmap, " %d", &integer);
printf("value: %d \n", integer);
//printing the values after scanning from string.
values = (double *) mmap(0,mystat.st_size,PROT_READ | PROT_WRITE,MAP_SHARED,fd,0);
printf("value: %lf \n", values[1]);
//printing the values from pointer
munmap (pmap, mystat.st_size);
close(fd);
return 0;
}
Read carefully (and several times) mmap(2). Notice:
A file is mapped in multiples of the page size.
and in the ERRORS section
EINVAL We don't like addr, length, or offset (e.g., they are too
large, or not aligned on a page boundary).
Consider also using strace(1) on your executable.
Of course, a memory mapping is just giving a view (as raw sequence of bytes) of the mapped file into the process by modifying its virtual address space. It obviously won't do any conversion (you might use sscanf(3) or strtol(3) on parts of that view to make such a conversion from an UTF8 or ASCII string representation of a number into its machine representation).

UART compare charts. Beaglebone

I have a problem trying to compare the uart input data (from a GPS) with '$' in order to detect a new package. I am sure that the problem is in how I manipulate the charRead variable. I tried one thousand of things, but probably because of my inexperience I have not figured out what it is the problem.
The code compiles and the data is coming all the time, but once I load the code into the beaglebone, it gets stacked but and it doesn't enter in the "if (charRead =='$')".
Thank you in advance!
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <time.h>
#include <iostream>
#include <termios.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <limits.h>
#include "Payload.h"
#define SLOTS "/sys/devices/bone_capemgr.9/slots"
#define CR 0x0d
#define SPACE 0x20
#define COMMA 0x2C
#define MAXSIZE 100
unsigned long time_data;
unsigned int button = 45;
int i,z =0, j=0, value;
int rx_length;
int main()
{
//uart4 configuration using termios
int fd;
//unsigned char *mess;
unsigned int value = 0;
gpio_export(button);
//Wait until the button is pushed
while (value != 1){
if (z==0){
printf("waiting\n");}
z++;
gpio_get_value(button, &value);}
//OPEN THE UART
//open uart4 for tx/rx, not controlling device
if((fd = open("/dev/ttyO4", O_RDONLY | O_NOCTTY|O_NONBLOCK)) < 0){
printf("Unable to open uart4 access.\n");
}
termios uart4;
cfsetospeed(&uart4, B9600); //Set the speed
//set attributes of uart4
uart4.c_iflag = 0;
uart4.c_oflag = 0;
uart4.c_lflag = 0;
tcsetattr(fd, TCSANOW, &uart4);
//----- CHECK FOR ANY RX BYTES -----
// Read up to 100 characters from the port if they are there
unsigned char stringRead[MAXSIZE];
unsigned char charRead;
do{
if (rx_length = read(fd, (void*)charRead, MAXSIZE)>0){
if (charRead =='$'){
i=0;
stringRead[i] = charRead; //Store in the first position of the char --> $
do {
rx_length = read(fd, (void*)charRead, MAXSIZE); //Read the next bit
if( (charRead != '\0') ) {
i++;
stringRead[i] = charRead; //write into stringRead
}
} while(charRead != 'CR'); //ASCII Carriage Return
stringRead[i+1] = charRead;
printf("%s", stringRead);
}}
if (rx_length==0){
//No data
}
gpio_get_value(button, &value);
}while (value!=0);
gpio_unexport(button);
close(fd);
return 0;
}
You're passing a cast of the variable value of charRead rather than a pointer to a memory location as the function read() expects void *.
read(fd, (void*)charRead, MAXSIZE)
You need to either read one character at a time:
read(fd, &charRead, 1)
Or change your reading logic to maximize amount read and data processing. I also recommend adding a bounds check on accessing stringRead.
// The following should handle the reading of a GPS NMEA message and display it
// I have not run the program, but compiling it was successful
// note:
// 1) the handling of the 'i' variable
// 2) the calls to reading the GPS input
// 3) the handling of error conditions
// 4) the simple logic flow
#include <stdio.h>
#include <stdlib.h>
#include <stddef.h>
#include <time.h>
//#include <iostream> // this is not C++ so this line not needed
#include <termios.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/types.h>
#include <string.h>
#include <ctype.h>
#include <math.h>
#include <limits.h>
#include "Payload.h"
// #define SLOTS "/sys/devices/bone_capemgr.9/slots" // not used, raises compiler warning
#define CR (0x0D)
// #define SPACE (0x20) // not used, raises compiler warning
// #define COMMA (0x2C) // not used, raises compiler warning
#define MAXSIZE (100)
#define BUTTON_PORT (45)
// unsigned long time_data; // not used, raises compiler warning
// int j=0; // not used, raises compiler warning
// int value = 0; // not used, raises compiler warning about variable masking
int main()
{
int i;
int z = 0; // flag used to control execution flow
int rx_length; // return status value from read()
//uart4 configuration using termios
int fd; // file descriptor number
//unsigned char *mess; // not used, raises compiler warning
unsigned int value = 0;
gpio_export(BUTTON_PORT);
//Wait until the button is pushed
// burn mass CPU cycles, while waiting
while (0 == value)
{
if (z==0)
{
printf("waiting\n");
z++; // to stop re-entry to this 'if' block
}
// suggest using nsleep() to free up CPU
gpio_get_value(BUTTON_PORT, &value);
} // end while
//open uart4 for rx
if((fd = open("/dev/ttyO4", O_RDONLY | O_NOCTTY|O_NONBLOCK)) < 0)
{
perror("open failed for /dev/tty04");
exit(1);
}
// implied else, open successful
termios uart4;
cfsetospeed(&uart4, B9600); //Set the speed to match the GPS output
//set attributes of uart4
// Note: probably better to read the current termois values
// then modify them to the desired states
uart4.c_iflag = 0;
uart4.c_oflag = 0;
uart4.c_lflag = 0;
tcsetattr(fd, TCSANOW, &uart4);
//----- CHECK FOR ANY RX BYTES -----
// Read up to 100 characters from the port if they are there
unsigned char stringRead[MAXSIZE]; // will contain a GPS NMEA message
unsigned char charRead; // input buffer
do{
while(1)
{
rx_length = read(fd, &charRead, 1);
if( 0 == rx_length )
{ // this will execute a lot since fd set to non-blocking
; // do nothing, while hogging CPU cycles
// suggest using nsleep() to free CPU
}
else if( 0 > rx_length )
{
perror( "read failed" );
exit(1);
}
else if (charRead =='$')
{
stringRead[0] = charRead; //Store first char of NMEA GPS message
i=1; // index for second char of NMEA message from GPS
}
else
{
stringRead[i] = charRead; //Store char
i++; // index for next char into stringRead buffer
if( MAXSIZE <= i )
{ // then overrun input buffer
perror( "read- overrun input buffer, GPS message too long");
exit(2);
}
if( CR == charRead ) //ASCII Carriage Return - end of message
{ // then, got complete message
break; // exit read loop, so can process message
}
} // end if
} // end while
stringRead[i] = '\0'; // terminate string so it can be printed
printf("%s", stringRead);
// get button state via BUTTON_PORT(45)
gpio_get_value(BUTTON_PORT, &value);
} while (value!=0); // then read next gps message
gpio_unexport(BUTTON_PORT);
close(fd);
return 0;
}

Is there a way to mmap a stdin?

I have a following problem:
My job is to write a program that takes unsigned integer numbers that are passed to it through stdin and print out only the numbers that have more than 2 bits set to one. How should I do it efficiently? I did a version of a program where I read the numbers from a file using mmap, and it's quite quick. I read it like a very big *char buffer and using strtol I 'scrub' out each number and do my check and whatnot.
Is there a way to operate on a string passed through stdin the same way? I though about buffering using fread, but there is a problem, where the buffer cuts off the number (meaning if i pass "1024 35" and I have a 6 byte buffer I will get "1024 3"), and I shudder to think how to get around that.
Source:
#include <stdio.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <fcntl.h>
#include <unistd.h>
#include <sys/mman.h>
#include <sys/types.h>
#include <sys/stat.h>
#include <sys/mman.h> /* mmap() is defined in this header */
#include <fcntl.h>
#include<string.h>
#include"apue.h"
int main (int argc, char *argv[])
{
int fdin, fdout;
char *src, *dst;
struct stat statbuf;
/* open the input file */
if ((fdin = open (argv[1], O_RDONLY)) < 0)
{printf("can't open %s for reading", argv[1]);return 1;}
/* find size of input file */
if (fstat (fdin,&statbuf) < 0)
{printf("fstat error");return 1;}
/* mmap the input file */
if ((src = mmap (0, statbuf.st_size, PROT_READ, MAP_SHARED, fdin, 0))
== (caddr_t) -1)
{printf("mmap error for input");return 1;}
char* beg=src;
long x;
char* end=&src[statbuf.st_size-1];
while(src<end)
{
beg=src;
x = strtol (src,&src,10);
if(!((x != 0) && ((x & (~x + 1)) == x)))
fwrite(beg, 1, (int)(src-beg), stdout);
}
return 0;
}
http://pastebin.com/EVhG3x79
I think the expected solution is how to count the ones and not how to read from stdin.
int count_ones(int n);
means the question is how to implement the count_ones efficiently.
and your main just should look like this:
int main()
{
int x;
cin>>x;
if( count_ones(x)>2){
cout<<x<<endl;
}
return 0;
}
I think the expected answer is:
use array size 256
for each byte(=unsigned char) put in the array in its place the count of ones (can be: from 0 to 8)
split each number to its bytes and sum the ones on each of the bytes.
return the result

Writing struct to mapped memory file (mmap)

I have a problem to write struct into a mapped memory file.
I have two file namely mmap.write.c and mmap.read.c, and in these files, I'm writing an integer to a file and reading it from file.
When I want to write struct and read it, I could not think about that since in line 32 of mmap.write.c
sprintf((char*) file_memory, "%d\n", i);
and in line 25 of mmap.read.c
sscanf (file_memory, "%d", &integer);
There is no difference to write and read integer/double/float/char etc. since I can put pattern as second argument "%d" for integer. But what I will write here to indicate struct? That is my main problem.
The struct that I want to write and read:
#define CHANNELS 20
typedef dataholder struct {
int value[CHANNELS];
time_t time;
int hash;
}dataholder;
mmap.read.c
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <unistd.h>
#include "mmap.h"
#define FILE_LENGTH 0x10000
int main (int argc, char* const argv[])
{
int fd;
void* file_memory;
int integer;
/* Open the file. */
fd = open (argv[1], O_RDWR, S_IRUSR | S_IWUSR);
printf("file opened\n");
/* Create the memory mapping. */
file_memory = mmap (0, FILE_LENGTH, PROT_READ | PROT_WRITE,
MAP_SHARED, fd, 0);
printf("memfile opened\n");
close (fd);
printf("file closed\n");
/* Read the integer, print it out, and double it. */
while(1) {
sscanf (file_memory, "%d", &integer);
printf ("value: %d\n", integer);
usleep(100000);
}
//sprintf ((char*) file_memory, "%d\n", 2 * integer);
/* Release the memory (unnecessary because the program exits). */
munmap (file_memory, FILE_LENGTH);
return 0;
}
mmap.write.c
#include <stdlib.h>
#include <stdio.h>
#include <fcntl.h>
#include <sys/mman.h>
#include <sys/stat.h>
#include <time.h>
#include <unistd.h>
#include "mmap.h"
#define FILE_LENGTH 0x10000
/* Return a uniformly random number in the range [low,high]. */
int random_range (unsigned const low, unsigned const high)
{
unsigned const range = high - low + 1;
return low + (int) (((double) range) * rand () / (RAND_MAX + 1.0));
}
int main (int argc, char* const argv[])
{
int fd, i;
void* file_memory;
/* Seed the random number generator. */
srand (time (NULL));
/* Prepare a file large enough to hold an unsigned integer. */
fd = open (argv[1], O_RDWR | O_CREAT | O_APPEND, S_IRUSR | S_IWUSR);
//lseek (fd, FILE_LENGTH+1, SEEK_SET);
write (fd, "", 1);
//lseek (fd, 0, SEEK_SET);
/* Create the memory mapping. */
file_memory = mmap (0, FILE_LENGTH, PROT_WRITE, MAP_SHARED, fd, 0);
close (fd);
/* Write a random integer to memory-mapped area. */
for(i=0; i<10000; i++) {
sprintf((char*) file_memory, "%d\n", i);
//goto a;
usleep(100000);
}
a:
/* Release the memory (unnecessary because the program exits). */
munmap (file_memory, FILE_LENGTH);
return 0;
}
Thanks a lot in advance.
First of all you have to keep track of where in the memory you want to write, second you have to remember that the mapped memory is just like any other pointer to memory. The last bit is important, as this means you can use normal array indexing to access the memory, or use functions such as memcpy to copy into the memory.
To write a structure, you have three choices:
Write the structure as-is, like in a binary file. This will mean you have to memcpy the structure to a specified position.
Write the structure, field-by-field, as text using e.g. sprintf to the correct position.
Treat the memory as one large string, and do e.g. sprintf of each field into a temporary buffer, then strcat to add it to the memory.
The simplest way is to just use a pointer:
dataholder *dh = file_memory;
/* now you can access dh->value, dh->time, dh->hash */
Since this struct doesn't contain any pointers, if you need to copy it in or out, you can just assign it, like:
dataholder dh_other = *dh;
or
*dh = dh_other;

Resources