The program I am writing to take a number and display that number as a calculator would display it (shown below) is compiling with no issues, but when I try to run it, I am able to input my number, but nothing happens. It seems like it is "hanging", since no further output is shown as I would have expected. Might anyone know what the problem is?
#include <stdio.h>
#define MAX_DIGITS 20
char segments[10][7] = /* seven segment array */
{{'1','1','1','1','1','1','0'}, /* zero */
{'0','1','1','0','0','0','0'}, /* one */
{'1','1','0','1','1','0','1'}, /* two */
{'1','1','1','1','0','0','1'}, /* three */
{'0','1','1','0','0','1','1'}, /* four */
{'1','0','1','1','0','1','1'}, /* five */
{'1','0','1','1','1','1','1'}, /* six */
{'1','1','1','0','0','0','0'}, /* seven */
{'1','1','1','1','1','1','1'}, /* eight */
{'1','1','1','0','0','1','1'}};/* nine */
char digits[3][MAX_DIGITS * 4]; /* digits array */
int i, j; /* count variables */
int adjust; /* output formatting */
int main(void) {
clear_digits_array();
int digit[20];
for (i = 0; i < 20; i++) {
digit[i] = 0;
}
int count = 20;
int position = 0;
printf("Enter a number: ");
int number = scanf("%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d",
&digit[0],
&digit[1],
&digit[2],
&digit[3],
&digit[4],
&digit[5],
&digit[6],
&digit[7],
&digit[8],
&digit[9],
&digit[10],
&digit[11],
&digit[12],
&digit[13],
&digit[14],
&digit[15],
&digit[16],
&digit[17],
&digit[18],
&digit[19]); //NOTHING HAPPENS AFTER HERE
printf("Got input, number is %d", number);
while (count > 0) {
printf("Reading digits, count is %d", count);
process_digit(digit[20 - count], position);
position++;
count--;
}
print_digits_array();
printf("\n");
return 0;
}
void clear_digits_array(void) {
/* fill all positions in digits array with blank spaces */
for (i = 0; i < 3; i++) {
for (j = 0; j < (MAX_DIGITS * 4); j++) {
digits[i][j] = ' ';
}
}
}
void process_digit(int digit, int position) {
/* check each segment to see if segment should be filled in for given digit */
for (i = 0; i < 7; i++) {
printf("Processing digit %d at position %d, i is %d", digit, position, i);
if (segments[digit][i] == 1) {
switch (i) {
case 0: digits[0][(position * 4) + 1] = '_';
break;
case 1: digits[1][(position * 4) + 2] = '|';
break;
case 2: digits[2][(position * 4) + 2] = '|';
break;
case 3: digits[2][(position * 4) + 1] = '_';
break;
case 4: digits[2][(position * 4) + 0] = '|';
break;
case 5: digits[1][(position * 4) + 0] = '|';
break;
case 6: digits[1][(position * 4) + 1] = '_';
break;
}
}
}
}
void print_digits_array(void) {
/* print each character in digits array */
for (i = 0; i < 3; i++) {
for (j = 0; j < (MAX_DIGITS * 4); j++) {
printf("%c", digits[i][j]);
}
printf("/n");
}
}
Your code includes:
printf("Enter a number: ");
int number = scanf("%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d",
&digit[0],
&digit[1],
&digit[2],
&digit[3],
&digit[4],
&digit[5],
&digit[6],
&digit[7],
&digit[8],
&digit[9],
&digit[10],
&digit[11],
&digit[12],
&digit[13],
&digit[14],
&digit[15],
&digit[16],
&digit[17],
&digit[18],
&digit[19]); //NOTHING HAPPENS AFTER HERE
Have you entered twenty separate digits? If not, scanf() is waiting for you to type some more numbers.
Note that the return value from scanf() is the number of successfully converted numbers (0..20 in the example), not the value you entered.
Is that the issue? I tried to make it such that the maximum amount of numbers the user could enter was 20, and if any more were entered they would be ignored, or if fewer were entered, it would only consider those (say, 5 were entered, then only the 5 would be used). Is there an easier way to do this sort of thing then?
Yes, I think that's the issue.
There are probably several easier ways to do it. I'd be tempted to use:
char buffer[22]; // 20 digits, newline, null
if (fgets(buffer, sizeof(buffer), stdin) != EOF)
{
size_t len = strlen(buffer);
if (len >= sizeof(buffer) - 1)
{
fprintf(stderr, "You entered too long a string (maximum 20 digits)\n");
exit(EXIT_FAILURE);
}
if (len > 0)
buffer[--len] = '\0'; // Zap newline — carefully
for (int i = 0; i < len; i++)
{
if (!isdigit(buffer[i]))
{
fprintf(stderr, "Non-digit %c found\n", buffer[i]);
exit(EXIT_FAILURE);
}
}
...and from here, process the digits in buffer, one at a time...
...Use buffer[i] - '0' to get a number 0..9 from the character in buffer...
}
Another option is to use a long long number, but that only gives you up to 18 digits (signed) or 19 digits (unsigned), with some values of 19 or 20 also within range. You'd then strip the digits out of the number using division and modulus operations.
long long value;
if (scanf("%lld", &value) == 1)
{
if (value < 0)
...error processing...
do
{
int digit = value % 10;
value /= 10;
...process digit...
} while (value > 0);
}
This has some merits, but in practice, I'd be tempted to use fgets() to read a line of input, and either sscanf() or strtoll() to convert and validate the number. That isn't as simple as it looks; the error returns from strtoll(), in particular, are many and subtle, and none of the scanf() family handle overflowing numbers gracefully. You could constrain the scanf() though with %18lld so that no more than 18 digits are read, but that would mean that if the user typed 19 or more digits, you'd get the leftovers on the next attempt to read with scanf(). So, handling scanf() is not simple either, especially if you need to convert multiple numbers in a single run of the program.
With those caveats out of the way, you can usually do a 'good enough' job with a sensible person providing the input. It is the process of making a program bomb-proof (foolproof — as in, proof against fools) that is hard. I find meaningful error reporting easier when I can report the whole string that was read in (as with fgets()); with scanf(), you can't see the characters that were entered and consumed before something went wrong.
use GDB, here is introduction for it http://www.gnu.org/software/gdb/
look into this tutorial too http://www.cs.cmu.edu/~gilpin/tutorial/
int number = scanf("%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d%d",
&digit[0],
&digit[1],
&digit[2],
&digit[3],
&digit[4],
&digit[5],
&digit[6],
&digit[7],
&digit[8],
&digit[9],
&digit[10],
&digit[11],
&digit[12],
&digit[13],
&digit[14],
&digit[15],
&digit[16],
&digit[17],
&digit[18],
&digit[19]);
I don't think this is a good idea use loop here
for (i = 0; i < 20; i++)
scanf("%d",&digit[i]);
And if you need the number
then do like this
int number = i; when loop finishes.
You can also try this
char buf[12];
while((c=getchar())!=EOF && i < 20)
{
buf[j++] =c;
if((c == '\n' || c == ' ' || c == '\t') && (sscanf(buf,"%d",&digit[i])) == 1)
{
i++;
j = 0;
}
}
For EOF you will have to press CTRL+D
In this way you can take 20 or less integers
Related
A given string is palindrome, you need to state that it is even palindrome (palindrome with even length) or odd palindrome (palindrome with odd length) otherwise return No.
This code i write but not get true output
#include<string.h>
#include <stdio.h>
int main(){
int n ;
char s[100000],b[100000];
int count=0,d,h,i,t,j;
if(count<1)
{
scanf("%d", &n);
if(n<=50)
{
for(t=1;t<=n;t++)
{
i=0,j=0,h=0;
scanf("%s", s);
h=strlen(s)-1;
if(h>=1&&h<=100000)
{
for(i=0,j=h;i<=h&&j>=0; j--,i++)
{
b[i]=s[j];
}
if(strcmp(s,b)==0)
{
if(h%2==0)
{
printf("YES EVEN");
printf("\n");
}
else
{
printf("YES ODD");
printf("\n");
}
}
else{
printf("NO");
printf("\n");
}
}
}
}
count++;
}
return 0;
}
#include<string.h>
#include <stdio.h>
int main(){
int n ;
char s[100000],b[100000];
int count=0,d,h,i,t,j;
if(count<1)
{
scanf("%d", &n);
if(n<=50)
{
for(t=1;t<=n;t++)
{
i=0,j=0,h=0;
scanf("%s", s);
h=strlen(s)-1;
if(h>=1&&h<=100000)
{
for(i=0,j=h;i<=h&&j>=0; j--,i++)
{
b[i]=s[j];
}
if(strcmp(s,b)==0)
{
if(h%2==0)
{
printf("YES EVEN");
printf("\n");
}
else
{
printf("YES ODD");
printf("\n");
}
}
else{
printf("NO");
printf("\n");
}
}
}
}
count++;
}
return 0;
}
Forget about syntax error only find logical error.
I expect the output is
Input
3
abc
abba
aba
Your Code's Output
NO
YESODD
NO
Expected Correct Output
NO
YESEVEN
YESODD
I get true result when i provide one string not more than that
but where is error.
When creating the string b you forget to add the terminating character \0
While checking for even you use h%2. But h is strlen(s)-1. So you need to set odd if h%2 == 0
Relevant changes are shown below
for(i=0,j=h;i<=h&&j>=0; j--,i++)
{
b[i]=s[j];
}
b[h+1] = '\0';
if(strcmp(s,b)==0)
{
if(h%2!=0)
{
printf("YES EVEN");
printf("\n");
}
else
{
printf("YES ODD");
printf("\n");
}
}
Forget about syntax error only find logical error.
I find this sort of statement very wrong. Unless you fix the syntax, you cannot look at it logically. Also proper indentation really helps in debugging the code and finding errors on your own.
You have a number of problems, but your primary problem is in your reversal. You attempt to reverse with:
h=strlen(s)-1;
if(h>=1&&h<=100000){
for(i=0,j=h;i<=h&&j>=0; j--,i++) {
b[i]=s[j];
}
This will fail for strlen(s) == 1, does not ensure nul-termination and because you use h=strlen(s)-1;, your h in if (h % 2 == 0) results in the opposite determination of EVEN and ODD. Instead you need:
#define MAXC 100000 /* if you need a constant, #define one (or more) */
...
h = strlen (s); /* h must be strlen(s) - not - 1 */
if (h >= 1 && h < MAXC) { /* now loop j=h-1; j < h times */
for (i = 0, j = h-1; i < h && j >= 0; j--,i++)
b[i] = s[j];
b[i] = 0; /* and ensure b is nul-terminated */
(note: adequately spaced code is much easier to read and debug)
Next, you fail to validate the return of every call to scanf, instead, blindly using the variables without any indication of whether your input succeeded -- a recipe for Undefined Behavior. You must validate EVERY user input, e.g.
if (scanf ("%d", &n) != 1 || n > 50) {
fputs ("error: invalid integer or out-of-range.\n", stderr);
return 1;
}
while (n-- && scanf ("%s", s) == 1) {
Simply choosing a logical factoring of your code eliminates the need altogether for variables t and d. Note, your conditions on n are (1) it's valid, and (2) it's 50 or less. Those can be combined into a single check. The same goes for looping n times while reading words into s.
Making those changes, your code simplifies to:
#include <stdio.h>
#define MAXC 100000 /* if you need a constant, #define one (or more) */
int main (void)
{
char s[MAXC];
int n;
if (scanf ("%d", &n) != 1 || n > 50) {
fputs ("error: invalid integer or out-of-range.\n", stderr);
return 1;
}
while (n-- && scanf ("%s", s) == 1) {
char b[MAXC]; /* b is only needed within loop */
int h = strlen (s), i = 0, j; /* as are h, i, j, no - 1 for h */
if (h >= 1 && h < MAXC) { /* now loop j=h-1; j < h times */
for (i = 0, j = h-1; i < h && j >= 0; j--,i++)
b[i] = s[j];
b[i] = 0; /* and ensure b is nul-terminated */
if (strcmp (s, b) == 0) {
if (h % 2 == 0)
printf ("YES EVEN\n");
else
printf ("YES ODD\n");
}
else
printf ("NO\n");
}
}
return 0;
}
Which now provides the palindrome check and ODD or EVEN length output you were looking for, e.g.
Example Use/Output
$ echo "5 abcba abccba abcdba a aa" | ./bin/pdromerefmt
YES ODD
YES EVEN
NO
YES ODD
YES EVEN
You should further protect the array bounds of s by including the field-width modifier for the "%s" conversion, e.g. "%99999s" which eliminates the need to check h <= 100000 (which would have already invoked Undefined Behavior if input was 100000 characters or greater). There is no need to check h >= 1 as the loop limits do nothing with h = 0 -- but do ensure an empty-string.
With the further tweaks and array bounds protections, your loop simplifies to:
while (n-- && scanf ("%99999s", s) == 1) {
char b[MAXC]; /* b is only needed within loop */
int h = strlen(s), i = 0, j = h;/* as are h, i, j, no -1 for h */
while (j--) /* must loop j times, regardless */
b[i++] = s[j]; /* reversing characters in s in b */
b[i] = 0; /* and ensure b is nul-terminated */
if (strcmp (s, b) == 0) {
if (h % 2 == 0)
printf ("YES EVEN\n");
else
printf ("YES ODD\n");
}
else
printf ("NO\n");
}
Forget about syntax error only find logical error.
That's what pencils and papers (or your rubber duck, maybe) are for, to figure out an algorithm and logically follow its steps. You have a complete program, though, and a large number of tests to try it. Now it's time to eradicate every single bug you can find, starting from syntax errors, which are "easily" detectable at compile time.
There are already enough answers about the flaws in the posted code, but there is at least one thing not yet covered, which isn't really a bug or a logic mistake, though.
The posted algorithm, for every test case, does the following:
Read a word (with scanf).
Find it size (with strlen).
Create a reversed copy of it (using a for loop).
Compare the copy with the original to check the palindromicity (with strcmp).
Why all those copies and array traversals? Once you know the length of the word you can just compare the left side of the string with the right side.
#include <stdio.h>
#include <stdbool.h>
#include <assert.h>
#define MAX_CHARS_IN_STR 100000
#define MAX_N_TESTS 50
// Performs the check without copying the the string
// length: size of the word
bool is_palindrome(size_t length, const char *str);
#define STRINGIFY_IMPL(x) #x
#define STRINGIFY(x) STRINGIFY_IMPL(x)
#define STR_WIDTH_FMT(x) "%" STRINGIFY(x) "s"
int main(void)
{
int n_words;
if ( scanf("%d", &n_words) != 1 || n_words < 1 || n_words > MAX_N_TESTS)
{
fprintf(stderr, "Error: the input is not a valid integer between 1 and %d.",
MAX_N_TESTS);
return 1;
}
int n_chars;
// Allocates an array big enough (including the null-terminator)
char word[MAX_CHARS_IN_STR + 1];
// It will use an array of two pointers instead of another if-else
const char *even_or_odd_str[] = { "IS EVEN", "IS ODD" };
while ( n_words-- )
{
// consume whitespace characters left in the input
scanf(" ");
// reads the string up to its maximum width or until the first whitespace.
// The macro expands to "%100000s" and that literal will be concatenated to "%n",
// which returns the number of characters read.
if ( scanf(STR_WIDTH_FMT(MAX_CHARS_IN_STR) "%n", word, &n_chars) != 1 )
{
fputs("Error: unable to read word.", stderr);
break;
}
if ( is_palindrome(n_chars, word) )
puts(even_or_odd_str[n_chars % 2]);
else
puts("NO");
}
}
bool is_palindrome(size_t n, const char *str)
{
assert(n && str);
size_t i = 0, j = n - 1;
while ( i < j && str[i] == str[j] )
{
++i;
--j;
}
// It's a palindrome only if the two indices met halfway
return i >= j;
}
I'm crazy about this problem (Uva 455):
A character string is said to have period k if it can be formed by
concatenating one or more repetitions of another string of length k.
For example, the string ”abcabcabcabc” has period 3, since it is
formed by 4 repetitions of the string ”abc”. It also has periods 6
(two repetitions of ”abcabc”) and 12 (one repetition of
”abcabcabcabc”).
Write a program to read a character string and
determine its smallest period.
Input
The first line oif the input file
will contain a single integer N indicating how many test case that
your program will test followed by a blank line. Each test case will
contain a single character string of up to 80 non-blank characters.
Two consecutive input will separated by a blank line.
Output
An
integer denoting the smallest period of the input string for each
input. Two consecutive output are separated by a blank line.
Sample Input
1
HoHoHo
Sample Output
2
I've checked all test cases I could imagine and all of them returned correct result, but I still get Wrong Answer on the online judge. Where did I go wrong?
(English is not my native language; please excuse typing or syntax errors.)
#include <stdio.h>
#include <string.h>
#define maxn 85
int check(char* s, int per){
for(int i = 0; i < strlen(s) - per; i++){
if(s[i + per] != s[i]) return 0;
}
return 1;
}
int main(){
int T;
scanf("%d", &T);
char s[maxn];
while(T--){
scanf("%s", s);
int len = strlen(s);
bool OK = false;
for(int i = 1; i <= len/2 && (len % i == 0); i++){//That's wrong.
if(check(s, i)){
printf("%d\n", i);
OK = true;
break;
}
}
if(!OK) printf("%d\n", len);
if(T) printf("\n");
}
return 0;
}
The problem is in for(int i = 1; i <= len/2 && (len % i == 0); i++). You are stopping as soon as you encounter an i that doesn't divide len, instead of skipping it.
Write the loop as:
for (int i = 1; i <= len/2; i++) {
if (len % i != 0) continue;
...
}
Let's say I am creating a 3*4 matrix (or a 2D array of 12 elements). So I want user to enter values of elements one by one as a sequence, divided by either spaces/tabs or enter-key. Also, if a value in a sequence is bad (in my case, any non-integer values are bad), I want to ignore it and read next values until I have all 12 of them.
int fill(Matrix * mtx)
{
puts("Start entering numbers. Please note that only integer values will be recorded.");
int temp = 0;
for (int i = 1; i <= mtx -> rows; i++)
{
for (int j = 1; j <= mtx -> cols; j++)
{
scanf(" %d", &temp);
setElement(mtx, i, j, temp);
}
}
return 0;
}
This is my most basic vision of the algorithm; I was wondering about the implementation of this "skip input if bad" condition.
Just started learning C btw, so any kind of advice is hugely appreciated!
You have to check the return value of scanf to be sure whether it scanned the integer input correctly or not. In case it fails due to some bad input - scanf can't take that as input and then you have to make sure that you clear the stdin so that the next calls of scanf don't fail. What you can do is, when scanf returns 0 - consume all characters (using getchar or similar) and do this until you get \n (Considering that user inputs the number each in a line). Illustration would be:
int n; //total number inputs to take.
n = 10;
int num, num_inputs = 0;
while( 1 )
{
while(scanf("%d", &num) != 1)
{
int c;
while ((c = getchar()) != EOF && c != '\n')
;
if(c == EOF){ fprintf(stderr,"Error in input\n"); exit(1)}
}
num_inputs++; // one more int correctly input.
...
if( num_inputs == n )
break;
}
An alternative and better way would be to use strto* functions and then considering the return value of it to understand whether there is any error or not. Illustration would be: (Here we have shown just the case where there is single int input in each line - this can be extended to process multiple int inputs in a line).
char buf[MAXLEN];
int num_inputs = 0;
while(fgets(buf,MAXLEN,stdin)){
char *en;
errno = 0;
long n = strtol(line, &en, 10);
if (errno == 0 && *en== '\0' && n >= INT_MIN && n < INT_MAX)
{
// n is an correctly inputted int
num_inputs++;
}
}
Check the man page for strtol - there is a detailed listing of the erros one might get. Check it.
Check what scanf returns. If not 1 means entered value is not a digit in this case. So discard the data from the stream first before entering next data.
int fill(Matrix * mtx) {
puts("Start entering numbers. Please note that only integer values will be recorded.");
int temp = 0, v;
for (int i = 1; i <= mtx->rows; i++) {
for (int j = 1; j <= mtx->cols; j++) {
v = scanf(" %d", &temp);
if (v != 1) { //if invalid input.
while ( (v = getchar()) != EOF && v != '\n' ); // discard invalid input.
j--; //don't forget to `j--` or else you will skip one position.
}
else { // if correct input.
setElement(mtx, i, j, temp);
}
}
}
return 0;
}
Solution
#include <stdio.h>
#include <string.h>
int main()
{
char value[50];
char *end;
int sum = 0;
long conv;
while(conv != 0 )
{
printf("Enter a measurement and unit(Ex: 4' or 3\";0' or 0\" when done): ");
fgets(value, 50, stdin);
conv = strtol(value, &end, 10);
if(strstr(value, "\'") != NULL)
{
conv = strtol(value, &end, 10);
sum = sum + (conv*12);
}
else if(strstr(value, "\"") != NULL)
{
conv = strtol(value, &end, 10);
sum = sum + conv;
}
}
printf("Total: %d, %s\n", sum, "inches" );
return 0;
}
UPDATE Still having problems with new program..unsure where to go from here. It is accepting numbers and quotes, but it keeps multiplying any number I type in by 12 when it should only do that if I enter a single quote to specify feet.
UPDATE2 Here are the functions for Assembly that we should keep in mind for writing the C program:
void printStr(char *)
Arguments:
edi = address of null-terminated string to print
Returns:
Nothing
void printUInt(unsigned)
Arguments:
edi = Unsigned integer to print
Returns:
Nothing
char getchar()
Arguments:
None
Returns:
eax = the next character
uinsigned readUInt()
Arguments:
None
Returns:
eax = an unsigned int read from stdin.
(eax is 0 on error)
I must write a C program which prompts the user to enter a measurement(number) and unit( ' or ", which represent feet or inches) and then prints out the Total length in inches AFTER the user enters a length of '0' which acts as a sentinel value.
This program is only needed to act as a way for me to then build an Assembly program with a similar structure. The thing is, it must be built around 4 functions that would be called to help perform some of the operations.
So my C program should be built similarly with those functions in mind. Here's what I have:
Here is my program:
UPDATED:
int main()
{
char value[50];
char *end;
int sum = 0;
long conv;
while(conv != 0)
{
printf("Enter a measurement and unit: ");
fgets(value, 50, stdin);
conv = strtol(value, &end, 10);
if(value[1]='\'')
{
sum = sum + (conv*12);
}
if(value[1]='\"')
{
sum = sum + conv;
}
}
printf("Total: %d\n", sum);
return 0;
}
OLD:
int main()
{
int sum = 0;
int value;
char symbol;
while(value != 1)
{
printf("Enter measurement and unit: ");
scanf("%d,%d", &value, &symbol);
if(symbol == "'")
{
sum = sum + value*12;
}
else if(symbol == ''' )
{
sum = sum + value;
}
sum = sum + value;
}
printf("Total: %d", sum);
return 0;
}
I hope I have enough information here for someone to help me even though I know we're missing the complete functions for time being. And I know the IA32 assembly conversion is not my main question and I think I will save that for another if I get stuck, but I hope getting this High-Level language program corrected will get me going in the right direction. Thanks in advance!
Get the character using %c not %d. Change the line into like this.
if ( scanf("%d,%c", &value, &symbol) != 2 )
continue;
While comparing you have to do like this,
if(symbol == '\"')
{
sum = sum + value*12;
}
else if(symbol == '\'' )
{
sum = sum + value;
}
Output after this,
Enter measurement and unit: 2,"
Enter measurement and unit: 3,'
Enter measurement and unit: 1,"
Total: 45
When you think about writing a program that will be translated to assembly, you want to limit yourself to using calls that have a 1-to-1 correlation to the system calls available in assembly. That means leaving the high-level world of buffered input/output and using the unbuffered low-level input/output methods where you are responsible for counting each byte that goes in or out of the program. Even the low-level routines of read and write in C, provide quite a few features that you will have to handle by hand in assembly.
In order to provide a reasonable example of this low-level I/O, I've written a short example to take your input measurements in either feet or inches and keep a running total of the feet and inches entered. The code also converts any inches over 12 into feet accordingly. This example provides a good approximation of the approach you will take in assembly to do the same thing. Take time to understand what each part does, and let me know if you have questions. The lower-level code you write, the longer it becomes to accomplish seemingly simple tasks. Your assembly will probably be 3-times longer.
The program expects input of the form numfeet' or numinches". So to enter 10 feet, enter 10', for 10 inches, enter 10":
#include <stdio.h>
#include <unistd.h>
#define STDINFD 0
#define STDOUTFD 1
#define newline write (STDOUTFD, "\n", 1)
#define MAXS 32
int main (void) {
ssize_t n = 0; /* number of characters read */
size_t i = 0; /* general iteration variable */
size_t digits = 0; /* digit counter */
char buf[MAXS] = {0}; /* buffer to hold input */
char *bp = buf; /* pointer to input buffer */
char length[MAXS] = {0}; /* buffer to hold measurement */
char *p = length; /* pointer to measurement */
char fbuf[MAXS] = {0}; /* buffer to hold feet */
char *fp = fbuf; /* pointer to feet */
char ibuf[MAXS] = {0}; /* buffer to hold inches */
char *ip = ibuf; /* pointer to inches */
unsigned feet = 0; /* total feet entered */
unsigned inches = 0; /* total inches entered */
unsigned num = 0; /* general unsigned value */
unsigned mlt = 1; /* place multiplier value */
unsigned incvt = 0; /* inches to feet conversion */
char unit = 0; /* buffer for ''' or '"' */
char const digit[] = "0123456789"; /* conversion string */
/* input prompt and labels */
char prompt[] = "\n Enter measurement with units [feet' or inches\"]: ";
char nlabel[] = "\n number : ";
char ulabel[] = "\n unit : ";
char flabel[] = "\n feet : ";
char ilabel[] = "\n inches : ";
/* write prompt to stdout */
write (STDOUTFD, prompt, sizeof prompt);
/* read length and unit until [CTRL+D] entered */
while ((n = read (STDINFD, bp, 32)) != 0)
{
/* re-initialize values for each loop */
bp = buf;
p = length;
fp = fbuf;
ip = ibuf;
i = 0;
num = 0;
incvt = 0;
mlt = 1;
unit = 0;
/* parse each character read into buf */
while (bp[i] != '\n')
{
if (bp[i] >= '0' && bp[i] <= '9') /* is a digit */
*p++ = bp[i];
if (bp[i] == 0x27) /* is a ' */
unit = bp[i];
if (bp[i] == '"') /* is a " */
unit = bp[i];
i++;
}
/* null-terminate / decrement length pointer */
*p = 0;
p--;
/* write length and unit to stdout */
write (STDOUTFD, nlabel, sizeof nlabel);
write (STDOUTFD, length, p - length + 1);
write (STDOUTFD, ulabel, sizeof ulabel);
write (STDOUTFD, &unit, sizeof unit);
newline;
/* convert characters in length to number */
for (i = p - length; p >= length; p--)
{
num += (*p - '0') * mlt;
mlt *= 10;
}
/* test unit and add to feet or inches */
if (unit == '"')
inches += num;
if (unit == 0x27)
feet += num;
/* convert inches > 12 to feet */
if (inches > 12)
{
incvt = inches / 12;
inches -= incvt * 12;
feet += incvt;
}
/* write label for total feet to stdout */
write (STDOUTFD, flabel, sizeof flabel);
/* determine number of digits in feet */
i = 1;
digits = 0;
while (feet >= i && (1UL << 32))
{
digits++;
i *= 10;
}
/* convert number to characters in feet buffer */
num = feet;
fp += digits - 1;
while (fp >= fbuf)
{
*fp-- = digit [num % 10];
num /= 10;
}
/* write the number of feet and label for inches to stdout */
write (STDOUTFD, fbuf, digits);
write (STDOUTFD, ilabel, sizeof flabel);
/* determine number of digits in inches */
i = 1;
digits = 0;
while (inches >= i && (1UL << 32))
{
digits++;
i *= 10;
}
/* convert number to characters in inches buffer */
num = inches;
ip += digits - 1;
while (ip >= ibuf)
{
*ip-- = digit [num % 10];
num /= 10;
}
/* write the number of inches and newline to stdout */
write (STDOUTFD, ibuf, digits);
newline;
/* zero all buffers */
for (i = 0; i < MAXS; i++)
buf[i] = length[i] = fbuf[i] = ibuf[i] = 0;
/* prompt for next input ([CTRL+D] to quit) */
write (STDOUTFD, prompt, sizeof prompt);
}
newline;
return 0;
}
Example / Output
$ ./bin/read_measurement
Enter measurement with units [feet' or inches"]: 10"
number : 10
unit : "
feet :
inches : 10
Enter measurement with units [feet' or inches"]: 10'
number : 10
unit : '
feet : 10
inches : 10
Enter measurement with units [feet' or inches"]: 4"
number : 4
unit : "
feet : 11
inches : 2
Enter measurement with units [feet' or inches"]:
Update to your high-level code
If you are going to continue to use the high-level functions, then make use of the fact that end already points to the next character following the number after you call strtol. e.g.:
while (printf ("\nEnter a measurement and unit: ") && fgets (value, 50 - 1, stdin))
{
errno = 0;
conv = strtol (value, &end, 10);
if (errno == 0 && value != end)
{
if (*end == '\'')
sum = sum + (conv*12);
else if (*end == '\"')
sum = sum + conv;
else
printf ("error: no unit following number.\n");
}
else
printf ("error: no value read.\n");
}
I see several bugs in your "updated" code: one on nearly every line.
int main()
Header files missing. (It's much easier for us to help you if you give us a complete program that can be compiled and tested without modification.)
Should be int main(void); empty argument parentheses are poor style.
{
char value[50];
char *end;
int sum = 0;
This is fine.
long conv;
while(conv != 0)
Use of uninitialized variable. I would write a do-while loop instead.
{
printf("Enter a measurement and unit: ");
Unnecessary use of printf (better fputs since no formatting is required).
fgets(value, 50, stdin);
If you have getline, use it.
conv = strtol(value, &end, 10);
It is necessary to set errno to zero manually before any use of the strto* functions, because some errors are only visible that way.
if(value[1]='\'')
Your immediate problem is here. There are three bugs on this line:
You haven't checked whether strtol returned an error.
value[1] is the second character read by fgets, not the character immediately after the number. The character immediately after the number is end[0].
Comparison uses ==, not =; this condition is assigning '\'' to value[1] and then testing whether '\'' is nonzero; since '\'' has to be nonzero, the body of the if-statement always executes, which is why you are seeing it always multiply by 12. This would have been more obvious if you had put spaces around the =. If you had run the compiler with warnings enabled, it would have told you about this mistake.
{
sum = sum + (conv*12);
}
ok
if(value[1]='\"')
Same problems as the earlier if-statement; should be else if.
{
sum = sum + conv;
}
Missing else clause here in which you report an error because the character after the number was neither ' nor ".
Missing check for junk input after the number and unit specifier.
}
printf("Total: %d\n", sum);
return 0;
}
the rest is fine
You probably could also use a primer on how to check whether strtol returned an error. This is a little finicky, because strtol has no special return value that indicates an error; if an error happened, it will either set errno, or not consume any characters. Unfortunately, when an error did not happen, it does not necessarily clear errno, so you have to do it yourself:
errno = 0;
conv = strtol(value, &end, 0);
if (end == value || errno) {
fputs("Invalid number, or no number entered\n", stderr);
continue;
}
I've been having some problems with this code below...
The main idea of the code is to read line by line and convert chars strings into floats and save the floats in a array called nfloat.
The input is a .txt containing this: n = the number of strings, in this case n = 3
3
[9.3,1.2,87.9]
[1.0,1.0]
[0.0,0.0,1.0]
The first number, 3 is the number of vectors as we can see in the image, but that number isn't static, the input can be 5 or 7, etc instead of 3.
So far, I've started doing the following, (for only 1 vector case) but the code has some memory errors I think:
int main(){
int n; //number of string, comes in the input
scanf("%d\n", &n);
char *line = NULL;
size_t len = 0;
ssize_t read;
read = getline(&line,&len,stdin); //here the program assigns memory for the 1st string
int numsvector = NumsVector(line, read);//calculate the amount of numbers in the strng
float nfloat[numsvector];
int i;
for (i = 0; i < numsvector; ++i)
{
if(numsvector == 1){
sscanf(line, "[%f]", &nfloat[i]);
}
else if(numsvector == 2){
if(i == 0) {
sscanf(line, "[%f,", &nfloat[i]);
printf("%f ", nfloat[i]);
}
else if(i == (numsvector-1)){
sscanf((line+1), "%f]", &nfloat[i]);
printf("%f\n", nfloat[i]);
}
}
else { //Here is where I think the problems are
if(i == 0) {
sscanf(line, "[%f,", &nfloat[i]);
printf("%f\n", nfloat[i]);
}
else if(i == (numsvector-1)) {
sscanf((line+1+(4*i)), "%f]", &nfloat[i]);
printf("%f\n", nfloat[i]);
}
else {
sscanf((line+1+(4*i)), "%f,", &nfloat[i]);
printf("%f\n", nfloat[i]);
}
}
}
Well, the problems come with the sscanf instructions I think, in the case of a string with two floats or one, the code works fine but in the case of 3 or more floats, the code doesn't work well and I can't understand why...
Here I attach the function too, but It seems to be correct... the focus of the problem remains on the main.
int NumsVector(char *linea, ssize_t size){
int numsvector = 1; //minimum value = 1
int n;
for(n = 2; n<= size; n++){
if (linea[n] != '[' && linea[n] != ']'){
if(linea[n] == 44){
numsvector = numsvector + 1;
}
}
}
return numsvector;
}
Please could someone help me understand where is the problem?
Ok - if you replace your current for loop with this, your nfloat array should end up with the right numbers in it.
/* Replaces the end ] with a , */
line[strlen(line) - 1] = ',';
/* creates a new pointer, pointing after the first [ in the original string */
char *p = line + 1;
do
{
/* grabs up to the next comma as a float */
sscanf(p, "%f,", &nfloat[i]);
/* prints the float it's just grabbed to 2 dp */
printf("%.2f\n",nfloat[i]);
/* moves pointer forward to next comma */
while (*(p++) != ',');
}
while (++i < numsvector); /* stops when you've got the expected number */