PIC USART second char always read 2 higher - c

I am using MPLAB XC8 and I try to use the USART module. But I have abnormal problem. Here is my code, I explain after this.
#include <xc.h>
#include "conbits.h"
#include <stdbool.h>
#include <stdint.h>
#include <string.h>
#include <stdio.h>
#define _XTAL_FREQ 8000000
void UART_RX_INIT(void);
void UART_TX(uint8_t *s);
void usart_send_str(uint8_t s[]);
uint8_t rx_buffer[];
uint8_t UART_Buffer = 0;
int rx_index=0;
bool rx_reg_ok = false;
uint8_t data;
void main(void) {
OSCCONbits.IRCF = 0X07;
OSCCONbits.SCS = 0X03;
while(OSCCONbits.HFIOFS !=1);
RCONbits.IPEN = 1;
ei();
UART_RX_INIT();
TRISD = 0X00;
LATD = 0X00;
while(1)
{
}
}
void UART_RX_INIT(){
TRISCbits.TRISC7 = 1;
TRISCbits.TRISC6 = 0;
SPBRG = 51;
RCSTAbits.CREN = 1;
RCSTAbits.SPEN = 1;
BAUDCON1bits.BRG16 = 0;
TXSTA1bits.SYNC = 0;
TXSTA1bits.BRGH = 1;
TXSTAbits.TXEN = 1;
IPR1bits.RCIP = 1;
PIE1bits.RCIE = 1;
IPR1bits.TXIP = 0;
PIE1bits.TXIE = 1;
}
void __interrupt(high_priority) ISR(void){
if(PIR1bits.RC1IF==1){
UART_Buffer = RCREG1;
if(UART_Buffer == 36 && rx_index==0)
{
memset(rx_buffer, 0, strlen(rx_buffer));
rx_buffer[0] = UART_Buffer;
rx_index++;
rx_reg_ok=true;
}
else if(rx_reg_ok && UART_Buffer != 36)
{
rx_buffer[rx_index] = UART_Buffer;
usart_send_str(rx_buffer);
usart_send_str("\r\n");
rx_index++;
}
else
{
usart_send_str("\r\nNot Registered\r\n");
}
if(UART_Buffer == 45)
{
usart_send_str("\r\n-----");
usart_send_str(rx_buffer);
usart_send_str("-----\r\n");
}
PIR1bits.RC1IF = 0;
}
}
void __interrupt(low_priority) low_isr(void){
INTCONbits.GIEH = 0;
if(PIR1bits.TXIF){
PIR1bits.TXIF=0;
}
INTCONbits.GIEH = 1;
}
///////////////////////////TRANSMIT
void UART_TX(uint8_t *s){
TXREG = *s;
while(TXSTA1bits.TRMT==0);
}
void usart_send_str(uint8_t s[]){
int i=0;
while(s[i]!='\0')
{
UART_TX(&s[i]);
i++;
}
}
Focus on inside the High Interrupt function block
First Unless I press '$' char send. PIC18 responses are just "Not Registered". After I press '$' char, It will add the next pressed chars to rx_buffer array.
My problem starts right there. Chars I pressed in order '1', '2' they send me 'Not Registered' and I press '$' they start adding to rx_buffer array and show me. Also for checking the buffer. If I send '-' char, It shows me rx_buffer. But If you look at the picture you can see. My problem after I press '$' second char is always 2 decimal higher. I press 'a' but it registered as 'c' to buffer. If I press '1' after '$', It register '3' this problem only happens after '$'. How can I fix this? Here is my simulation output.I press '1' - '2' - '$' - 'a' - 'b' - 'c' - '-'
I press '1' - '2' - '$' - 'a' - 'b' - 'c' - '-'
I press '1' - '2' - '$' - '1' - '2' - '3' - '-'

Related

7 Segment isn't working properly

I'm having some troubles about my 7 segment 2 digit counter. I'm using a PIC16F877A with 20Mhz crystal. I'm programming my pic using a replica PICKIT 3 and MPLAB IDE.
Circuit
When i write 02,03,04,04...06 segment displaying it like 88 but 2. Digit C and F segments are not bright as other segments.
02
When i write 01,07,10, everything is normal
My code:
#include <16F877A.h>
#use delay(clock=20m)
#define Dig2 PIN_A0
#define Dig1 PIN_A3
#define rfid PIN_A1
#define reset PIN_A2
#use fast_io(b)
#use fast_io(a)
#fuses HS,NOWDT,NOPROTECT,NOBROWNOUT,NOLVP,NOPUT,NOWRT,NODEBUG,NOCPD
//static const int digit[10]= { 0b0111111, 0b0000110, 0b1011011, 0b1001111,0b1100110,0b1101101, 0b1111101, 0b0000111, 0b1111111, 0b1101111 };// anode
static const int digit[10]= { 0b1000000, 0b1111001, 0b0100100, 0b0110000,0b0011001,0b0010010, 0b0000010, 0b1111000, 0b0000000, 0b0010000 };//cathode
//SECOND CODE
void display(unsigned char value)
{
int onlar = value / 10;
int birler = value % 10;
output_low(Dig2);
output_high(Dig1);
output_b(digit[onlar]);
delay_ms(5);
output_low(Dig1);
output_high(Dig2);
output_b(digit[birler]);
delay_ms(5);
}
/* FIRST CODE
// Written by Michaël Roy
void display(unsigned char value)
{
static char tens = 0;
char dig = (tens) ? (value / 10) : (value % 10);
dig = digit[dig];
output_high((tens) ? Dig1 : Dig2);
output_b(dig);
output_low((tens) ? Dig2 : Dig1);
tens = !tens;
} */
void main()
{
char sayi = 0;
set_tris_b(0b10000000);
set_tris_a(0b11111010);
while(1)
{
display(sayi);
if(input(rfid) == 0)
{
sayi++;
while(input(rfid) == 0)
{
display(sayi);
}
if (sayi == 100)
{
sayi = 0 ;
}
}
if(input(reset) == 0)
{
delay_ms(3000);
if(input(reset) == 0)
{
sayi = 0;
}
}
}
}
How can I solve this?

How often/when does C execute content within if/else statements?

I'm working on an embedded (avr) project, and basically I want to print out a few different things based on how long a pin has been pressed down. I can't figure out what happens as the value passes through and satisfies if statements along the way (button is still pressed so counter increments).
The setup is as follows:
if overflows is between 7-48 (button pressed for 30ms-200ms), print out a '.'
if overflows is greater than 48 (button pressed for greater than 200ms), print out a '-'
if overflows is greater than 97 (button has not been pressed in over 400ms), print out a ' '
My current code is as follows:
static inline void isr(char type) {
static unsigned int overflows = 0;
static unsigned char idx = 0;
if (type == 'e') { // edge captured
if (TCCR1B & 0x40) { // rising edge
if (overflows < 7) {
// do nothing
} else if (overflows < 49) {
buffer[idx++] = '.';
size++;
} else {
buffer[idx++] = '-';
size++;
}
}
overflows = 0; // restart counting overflows at each edge
} else { // overflow occured
overflows++;
if (buffer[idx-1] != ' ' && !(TCCR1B & 0x40) && overflows > 97) {
buffer[idx++] = ' ';
size++;
}
}
I'm not sure if this is correct though, since it would seem that there would always be a '.' preceding a '-', since as the overflow value is incremented, it satisfies the <49 condition.
Any thoughts?
if you want to count no.of times switch pressed, you can use while loop.
for example,
if(sw==0) //sw is switch connected with I/O pin
{
while(sw==0)
{
led=1; //LED is output
delay(); // use delay function
led=0;
delay();
count++;
}
}
by using while loop, you can avoid from getting multiple times switch pressed. if you make one on and off switch, the count will be increased by one.
I'm not sure if this is correct though, since it would seem that there would always be a '.' preceding a '-', since as the overflow
value is incremented, it satisfies the <49 condition.
But the tests are performed only on the rising edge - when both type == 'e' and (TCCR1B & 0x40) != 0. So the overflow count is evaluated only when the button is released, so you will not see the intermediate . before -.
So to answer your question, a conditional statement or block is executed when the condition is true. Here you have nested conditionals, so all preceding conditions must be true for the inner condition to be evaluated.
According to your description I assume you have a button on your pin, so in this case the first thing what I would recommend before doing anything is to implement a debounce for the button signal.
I would solve the problem something like this:
#define BUTTON_UNKNOWN 0
#define BUTTON_DOWN 1
#define BUTTON_UP 2
#define FALSE 0
#define TRUE 1
static inline unsigned char debounce( unsigned char current_state)
{
static unsigned char ret_value;
unsigned char state_changed = FALSE;
// Counter for number of equal states
static unsigned char count = 0;
// Keeps track of current (de-bounced) state
static unsigned char button_state = 0;
// Check if button is high or low for the moment
if (current_state != button_state)
{
// Button state is about to be changed, increase counter
count++;
if (count >= 3)
{
// The button have not bounced for four checks, change state
button_state = current_state;
// If the button was pressed (not released), tell main so
count = 0;
state_changed = TRUE;
}
}
else
{
state_changed = FALSE;
// Reset counter
count = 0;
}
//if butten press or release detected
if (state_changed == TRUE)
{
//check for the current state of the button
if (current_state != 0)
{
ret_value = BUTTON_DOWN;
}
else
{
ret_value = BUTTON_UP;
}
}
return ret_value;
}
int main(void)
{
//perform proper initialization of your pin
unsigned char button = BUTTON_UNKNOWN;
unsigned char cycle_count = 0;
unsigned char idx = 0;
unsigned char buffer[255];
unsigned char current_state;
unsigned char no_activity;
//unsigned char current_state = (~BUTTON_PIN & BUTTON_MASK) != 0;
while(1)
{
//read the button state
current_state = (~BUTTON_PIN & BUTTON_MASK) != 0;
// Update button_state
button = debounce(current_state);
// Check if the button is pressed.
if (button == BUTTON_DOWN)
{
//count cycles in which the button was pressed
//one cycle is 10 ms - see delay below
cycle_count++;
}
else
{
//check if the button was pressed before
if ((button != BUTTON_UNKNOWN) && (cycle_count != 0))
{
//if button was pressed for 200ms
if (cycle_count <= 20)
{
buffer[idx] = '.';
idx++;
}
else
{
//if the button was pressed between 200 and 400 ms
if ((cycle_count > 20) && (cycle_count <= 40))
{
buffer[idx] = '-';
idx++;
}
//the button was pressed for more than 400ms, uncomment if you need it
/*else
{
buffer[idx] = ' ';
idx++;
}*/
}
//reset counting mechanism
cycle_count = 0;
no_activity = 0;
}
else
{
no_activity++;
if (no_activity >= 40)
{
buffer[idx] = ' ';
idx++;
no_activity = 0;
}
}
}
// Delay for a while so we don’t check to button too often
_delay_ms(10);
}
}
You can adapt this code according to your needs:
change the line current_state = (~BUTTON_PIN & BUTTON_MASK) != 0; so that to read your pin state, and change the declaration of the buffer to suite your needs unsigned char buffer[255];
Please note that due to the debounce the time measured is not exactly 200ms ( it is 200ms + 2*debounce_time = 260ms (debounce time is 3 cycles, each cycle is 10ms, see delay at the end), but you may compensate these errors by reducing the contants in the cycle_count comparisons in the end.
Hope this helps!
If you really stick to your solution, then to avoid the problem what you experience is to not evaluate the overflow value continuously, do not try to determine the length of the button push on the fly, try instead to measure the length of the push and after that evaluate it and put the char in the buffer. You need to wait for the 'release button' and then evaluate how much time the button was pressed. Something like this:
static inline void isr(char type) {
static unsigned int overflows = 0;
static unsigned char idx = 0;
unsiged char button_status;
if (type == 'e') { // edge captured
if (TCCR1B & 0x40) { // rising edge
//perform a debounce otherwise wont be good
button_status = 1;
}
overflows = 0; // restart counting overflows at each edge
} else { // overflow occured
overflows++;
//if button was pressed and its now released evaluate result
if (!(TCCR1B & 0x40) && (button_status == 1))
{
if (overflows < 7) {
// do nothing
} else if (overflows < 49) {
buffer[idx++] = '.';
size++;
} else {
buffer[idx++] = '-';
size++;
}
button_status = 0;
}
if (buffer[idx-1] != ' ' && !(TCCR1B & 0x40) && overflows > 97) {
buffer[idx++] = ' ';
size++;
}
}

C: Segmentation error

I'm implementing in c the vigenère algorithme.
Unfortunately when testing the program I'm experiencing a segmentation error. I'm compiling with clang on mac.
How could I avoid that error ?
Source Code:
#include <ctype.h>
#include <stdio.h>
#include <string.h>
/**
* Function: invalidUsage
* --------------------
* Shows usage information and returns 1
*/
int
invalidUsage();
/**
* Function: cryptCaesar
* --------------------
* Returns encrypted char using caesar cipher
*/
char
cryptCaesar(const char plain, const int key);
/**
* Function: parseAlphaKey
* --------------------
* Converts an alpha string to a usable key (array of char from 0 to 25)
* Returns true if conversion successful, false if not
*/
bool
parseAlphaKey(const char* input_string, char** output_key);
// === Main ===
int main(int argc, const char *argv[])
{
// === Argument validation ===
char *output_key;
if (argc != 2
|| !parseAlphaKey(argv[1], &output_key))
return invalidUsage();
// === Read plain text ===
// === Output cipher text ===
//printf("%s\n", key);
return 0;
}
int
invalidUsage()
{
printf("Usage : vigenere <key>\n\n");
printf("KEY:\n");
printf(" Must be a string of alpha characters\n");
return 1;
}
char
cryptCaesar(const char plain, const int key)
{
char cipher;
if (islower(plain)) {
cipher = (plain - 'a' + key) % 26 + 'a';
} else if (isupper(plain)) {
cipher = (plain - 'A' + key) % 26 + 'A';
} else {
cipher = plain;
}
return cipher;
}
bool
parseAlphaKey(const char* input_string, char** output_key)
{
//output_key = NULL;
*output_key = malloc(strlen(input_string) * sizeof(char));
for (int i = 0, n = strlen(input_string); i < n; ++i) {
if (isupper(input_string[i]))
*output_key[i] = input_string[i] - 'A';
else if (islower(input_string[i]))
*output_key[i] = input_string[i] - 'a';
else {
//free(*output_key);
return false;
}
}
return true;
}
Debug output:
$ lldb vigenere -- test
Current executable set to 'vigenere' (x86_64).
(lldb) run
Process 48854 launched: '/Users/.../vigenere' (x86_64)
Process 48854 stopped
* thread #1: tid = 0x549580, 0x0000000100000d9f vigenere`parseAlphaKey(input_string=0x00007fff5fbff941, output_key=0x00007fff5fbff6a8) + 207 at vigenere.c:87, queue = 'com.apple.main-thread, stop reason = EXC_BAD_ACCESS (code=1, address=0x2)
frame #0: 0x0000000100000d9f vigenere`parseAlphaKey(input_string=0x00007fff5fbff941, output_key=0x00007fff5fbff6a8) + 207 at vigenere.c:87
84 if (isupper(input_string[i]))
85 *output_key[i] = input_string[i] - 'A';
86 else if (islower(input_string[i]))
-> 87 *output_key[i] = input_string[i] - 'a';
88 else {
89 //free(*output_key);
90 return false;
(lldb) kill
Process 48854 exited with status = -1 (0xffffffff) SIGKILL
(lldb) exit
Regards
Two problems:
1) you're not terminating your output string - change:
*output_key = malloc(strlen(input_string) * sizeof(char));
to:
*output_key = malloc(strlen(input_string) + 1);
and make sure you add a '\0' terminator, e.g. in parseAlphaKey add a line:
(*output_key)[n] = '\0';
after the loop.
2) you're getting bitten by operator precedence - change, e.g.
*output_key[i] = input_string[i] - 'A';
to:
(*output_key)[i] = input_string[i] - 'A';

atoi implementation in C

I can't understand the following atoi implementation code, specifically this line:
k = (k << 3) + (k << 1) + (*p) - '0';
Here is the code:
int my_atoi(char *p) {
int k = 0;
while (*p) {
k = (k << 3) + (k << 1) + (*p) - '0';
p++;
}
return k;
}
Can someone explain it to me ?
Another question: what should be the algorithm of atof implementation ?
<< is bit shift, (k<<3)+(k<<1) is k*10, written by someone who thought he was more clever than a compiler (well, he was wrong...)
(*p) - '0' is subtracting the value of character 0 from the character pointed by p, effectively converting the character to a number.
I hope you can figure out the rest... just remember how the decimal system works.
Here is a specification for the standard function atoi. Sorry for not quoting the standard, but this will work just as fine (from: http://www.cplusplus.com/reference/clibrary/cstdlib/atoi/ )
The function first discards as many whitespace characters (as in
isspace) as necessary until the first non-whitespace character is
found. Then, starting from this character, takes an optional initial
plus or minus sign followed by as many base-10 digits as possible, and
interprets them as a numerical value.
The string can contain additional characters after those that form the
integral number, which are ignored and have no effect on the behavior
of this function.
If the first sequence of non-whitespace characters in str is not a
valid integral number, or if no such sequence exists because either
str is empty or it contains only whitespace characters, no conversion
is performed and zero is returned.
k = (k << 3) + (k << 1);
means
k = k * 2³ + k * 2¹ = k * 8 + k * 2 = k * 10
Does that help?
The *p - '0' term adds the value of the next digit; this works because C requires that the digit characters have consecutive values, so that '1' == '0' + 1, '2' == '0' + 2, etc.
As for your second question (atof), that should be its own question, and it's the subject for a thesis, not something simple to answer...
#include <stdio.h>
#include <errno.h>
#include <limits.h>
double atof(const char *string);
int debug=1;
int main(int argc, char **argv)
{
char *str1="3.14159",*str2="3",*str3="0.707106",*str4="-5.2";
double f1,f2,f3,f4;
if (debug) printf("convert %s, %s, %s, %s\n",str1,str2,str3,str4);
f1=atof(str1);
f2=atof(str2);
f3=atof(str3);
f4=atof(str4);
if (debug) printf("converted values=%f, %f, %f, %f\n",f1,f2,f3,f4);
if (argc > 1)
{
printf("string %s is floating point %f\n",argv[1],atof(argv[1]));
}
}
double atof(const char *string)
{
double result=0.0;
double multiplier=1;
double divisor=1.0;
int integer_portion=0;
if (!string) return result;
integer_portion=atoi(string);
result = (double)integer_portion;
if (debug) printf("so far %s looks like %f\n",string,result);
/* capture whether string is negative, don't use "result" as it could be 0 */
if (*string == '-')
{
result *= -1; /* won't care if it was 0 in integer portion */
multiplier = -1;
}
while (*string && (*string != '.'))
{
string++;
}
if (debug) printf("fractional part=%s\n",string);
// if we haven't hit end of string, go past the decimal point
if (*string)
{
string++;
if (debug) printf("first char after decimal=%c\n",*string);
}
while (*string)
{
if (*string < '0' || *string > '9') return result;
divisor *= 10.0;
result += (double)(*string - '0')/divisor;
if (debug) printf("result so far=%f\n",result);
string++;
}
return result*multiplier;
}
Interestingly, the man page for atoi doesn't indicate setting of errno so if you're talking any number > (2^31)-1, you're out of luck and similarly for numbers less than -2^31 (assuming 32-bit int). You'll get back an answer but it won't be what you want. Here's one that could take a range of -((2^31)-1) to (2^31)-1, and return INT_MIN (-(2^31)) if in error. errno could then be checked to see if it overflowed.
#include <stdio.h>
#include <errno.h> /* for errno */
#include <limits.h> /* for INT_MIN */
#include <string.h> /* for strerror */
extern int errno;
int debug=0;
int atoi(const char *c)
{
int previous_result=0, result=0;
int multiplier=1;
if (debug) printf("converting %s to integer\n",c?c:"");
if (c && *c == '-')
{
multiplier = -1;
c++;
}
else
{
multiplier = 1;
}
if (debug) printf("multiplier = %d\n",multiplier);
while (*c)
{
if (*c < '0' || *c > '9')
{
return result * multiplier;
}
result *= 10;
if (result < previous_result)
{
if (debug) printf("number overflowed - return INT_MIN, errno=%d\n",errno);
errno = EOVERFLOW;
return(INT_MIN);
}
else
{
previous_result *= 10;
}
if (debug) printf("%c\n",*c);
result += *c - '0';
if (result < previous_result)
{
if (debug) printf("number overflowed - return MIN_INT\n");
errno = EOVERFLOW;
return(INT_MIN);
}
else
{
previous_result += *c - '0';
}
c++;
}
return(result * multiplier);
}
int main(int argc,char **argv)
{
int result;
printf("INT_MIN=%d will be output when number too high or too low, and errno set\n",INT_MIN);
printf("string=%s, int=%d\n","563",atoi("563"));
printf("string=%s, int=%d\n","-563",atoi("-563"));
printf("string=%s, int=%d\n","-5a3",atoi("-5a3"));
if (argc > 1)
{
result=atoi(argv[1]);
printf("atoi(%s)=%d %s",argv[1],result,(result==INT_MIN)?", errno=":"",errno,strerror(errno));
if (errno) printf("%d - %s\n",errno,strerror(errno));
else printf("\n");
}
return(errno);
}
Here is my implementation(tested successfully with cases containing and starting with letters, +, - and zero's).
I tried to reverse-engineer atoi function in Visual Studio. If the input string only contained numerical characters, it could be implemented in one loop. but it gets complicated because you should take care of -,+ and letters.
int atoi(char *s)
{
int c=1, a=0, sign, start, end, base=1;
//Determine if the number is negative or positive
if (s[0] == '-')
sign = -1;
else if (s[0] <= '9' && s[0] >= '0')
sign = 1;
else if (s[0] == '+')
sign = 2;
//No further processing if it starts with a letter
else
return 0;
//Scanning the string to find the position of the last consecutive number
while (s[c] != '\n' && s[c] <= '9' && s[c] >= '0')
c++;
//Index of the last consecutive number from beginning
start = c - 1;
//Based on sign, index of the 1st number is set
if (sign==-1)
end = 1;
else if (sign==1)
end = 0;
//When it starts with +, it is actually positive but with a different index
//for the 1st number
else
{
end = 1;
sign = 1;
}
//This the main loop of algorithm which generates the absolute value of the
//number from consecutive numerical characters.
for (int i = start; i >=end ; i--)
{
a += (s[i]-'0') * base;
base *= 10;
}
//The correct sign of generated absolute value is applied
return sign*a;
}
about atoi() hint code from here:
and based on the atoi(), my implementation of atof():
[have same limitation of original code, doesn't check length, etc]
double atof(const char* s)
{
double value_h = 0;
double value_l = 0;
double sign = 1;
if (*s == '+' || *s == '-')
{
if (*s == '-') sign = -1;
++s;
}
while (*s >= 0x30 && *s <= 0x39)
{
value_h *= 10;
value_h += (double)(*s - 0x30);
++s;
}
// 0x2E == '.'
if (*s == 0x2E)
{
double divider = 1;
++s;
while (*s >= 0x30 && *s <= 0x39)
{
divider *= 10;
value_l *= 10;
value_l += (double)(*s - 0x30);
++s;
}
return (value_h + value_l/divider) * sign;
}
else
{
return value_h * sign;
}
}

Reading an integer and / or character without an array

I need to read an integer one by one until i read a '$', and then to determine the largest, smallest and so on. I could use a character variable and do it, but it works for numbers from 0 to 9. But how do I read integers of two or more digits and at the same time, detect a '$' - I used a char *, but I guess it is equivalent to an array, which I should not use here. Also, char holds a single number / char, hence not suitable for larger numbers. What should I do?
No arrays, no pointers, no tricky char-by-char read & convert. Just plain scanf and getchar.
#include <stdio.h>
int main()
{
int newValue=0; /* value being acquired */
int max; /* current maximum value */
int min; /* current minimum value */
int firstAcquired=0; /* boolean flag set to 1 after first acquisition */
int ch; /* used as temporary storage for the getchar() */
for(;;)
{
/* scanf returns the number of successfully acquired fields; here if it
returns 0 means that the value couldn't be acquired */
if(scanf("%d",&newValue)==0)
{
/* scanf failed, but it's guaranteed it put the offending character
back into the stream, from where we can get it */
ch=getchar();
if(ch=='$' || ch==EOF)
break;
else
/* from here to the break it's just to handle invalid input and EOF
gracefully; if you are not interested you can replace this stuff
with a random curse to the user */
{
puts("Invalid input, retry.");
/* Empty the buffer */
while((ch=getchar())!='\n' && ch!=EOF)
;
}
/* if it's EOF we exit */
if(ch==EOF)
break;
}
else
{
/* Everything went better than expected */
if(!firstAcquired || newValue>max)
max=newValue;
if(!firstAcquired || newValue<min)
min=newValue;
firstAcquired=1;
}
}
if(firstAcquired)
{
printf("The maximum value was %d\n", max);
printf("The minimum value was %d\n", min);
}
return 0;
}
In the interest of spoiling all the fun, showing off, outright overkill and darn tooting fun:
#include <boost/spirit/include/qi.hpp>
#include <boost/spirit/include/karma.hpp>
#include <boost/spirit/include/support_istream_iterator.hpp>
namespace qi = boost::spirit::qi;
template <typename V>
void show_statistics(const V& data)
{
using namespace boost::spirit::karma;
std::cout << "data:\t"<< format('{' << auto_ % ", " << '}', data) << std::endl;
std::cout << "min:\t" << *std::min_element(data.begin(), data.end()) << std::endl;
std::cout << "max:\t" << *std::max_element(data.begin(), data.end()) << std::endl;
auto sum = std::accumulate(data.begin(), data.end(), 0);
std::cout << "sum:\t" << sum << std::endl;
std::cout << "avg:\t" << (1.0*sum) / data.size() << std::endl;
}
void dostats(const std::vector<int>& data) { show_statistics(data); }
int main()
{
std::cin.unsetf(std::ios::skipws);
auto f = boost::spirit::istream_iterator(std::cin);
decltype(f) l;
bool ok = qi::phrase_parse(f, l, +(+qi::int_ > "$") [ dostats ], qi::space);
if (f!=l)
std::cout << "Remaining input unparsed: " << std::string(f,l) << std::endl;
return ok? 0:255;
}
Demo:
Sample run:
sehe#natty:/tmp$ ./test2 <<< "1 2 3 4 5 $ 3 -9 0 0 0 $ 900 9000 $ unparsed trailing text"
data: {1, 2, 3, 4, 5}
min: 1
max: 5
sum: 15
avg: 3
data: {3, -9, 0, 0, 0}
min: -9
max: 3
sum: -6
avg: -1.2
data: {900, 9000}
min: 900
max: 9000
sum: 9900
avg: 4950
Remaining input unparsed: unparsed trailing text
You can use 'scanf("%s")' to read a group of characters. You can then check if the first character is a '%' and terminate if so. Otherwise, call atoi to convert to an integer. Store the largest and smallest in integer types, not character types.
Basically, the only time you have to deal with characters is when you read them in and check if it's a '$'. Otherwise, use integers all the way through.
If I'm getting what you want correctly it should be something like this:
int i = 0;
char c = getchar();
while (c != '$')
{
i = i * 10 + (c - '0');
c = getchar();
}
Hope it helped.
You can read char by char in a loop, check values and so on...
int i = 0;
char c = 0;
int size = 10;
int currentIndex = 0;
int* integers = malloc(sizeof(int) * size);
int counter = 0;
do
{
scanf("%c", &c);
if (c == ' ') // Match space, used a number separator
{
if (counter != 0 && i != 0)
{
if (currentIndex >= size)
{
size += 5;
integers = realloc(integers, size);
}
integers[currentIndex] = i;
currentIndex++;
}
counter = 0;
i = 0;
}
else if (c >= '0' && c <= '9')
{
i = (i * counter * 10) + (c - '0');
counter++;
}
}
while(c != '$');
Don't forget to free integers in the end!
#include <stdio.h>
#include <stdlib.h>
#include <ctype.h>
#define BUFF_SIZE 16
#define DATA_MAX_SIZE 64
int main(){
char buff[BUFF_SIZE];
int data[DATA_MAX_SIZE];
int i,value,counter = 0;
char *buffp,*p;
while(NULL!=fgets(buff,BUFF_SIZE,stdin)){
buff[BUFF_SIZE - 1]='\0';
buffp = buff;
next: while(isspace(*buffp))
++buffp;
if(*buffp == '\0')
continue;
value = strtol(buffp, &p, 0);
if(counter == DATA_MAX_SIZE){
printf("over data max size!\n");
break;
} else if(p != buffp){
data[counter++]=value;
if(*p == '\0' || *p == '\r'|| *p == '\n')
continue;
buffp = p;
goto next;
} else {
if(*p == '$')
break;
printf("format error\n");
break;
}
}
//check code
for(i=0;i<counter;++i){
printf("data[%d]=%d\n",i, data[i]);
}
return 0;
}
OUTPUT:
1 2 3
123
456
99 $
data[0]=1
data[1]=2
data[2]=3
data[3]=123
data[4]=456
data[5]=99
12345
4
$
data[0]=12345
data[1]=4

Resources