I am working on making a program that will take in an input parameter 'N' using argv. The value N will then allow the user to enter in N value of lines about a chemical element. For example, one line would look like
1 Hydrogen H other_nonmetals 1.008 1 0 0 0 0 0 0
and using a struct, I will scan and print the input in an organized matter.
I am having two main problems currently. The first problem is scanning in the electron values. In the Hydrogen example above, I would need to scan in 1 0 0 0 0 0 0 and reprint it out in my function print_element. When I do so, only the value 1 is stored. I want all the zeros to be omitted, but if the electron values were 1 0 0 0 0 0 1, then only the 1 would be printed in my function.
The next problem I am having is in my for loops. While looping the function print_element, an extra element with no values will be printed. For example, if the user inputs values for Hydrogen and then Barium, it will print Hydrogen then a completely blank element with all zeros, and then Barium. I cannot figure out how to get rid of the blank element.
#include <stdio.h>
#include <stdlib.h>
#define MAX_ELEMENTS 20
typedef struct{
int num;
char name[MAX_ELEMENTS];
char symbol[MAX_ELEMENTS];
char class[MAX_ELEMENTS];
double weight;
char electrons[MAX_ELEMENTS];
} element_t;
void scan_element(element_t *uno){
scanf("%d %s %s %s %lf %20s", &uno->num, uno->name, uno->symbol, uno->class, &uno->weight, uno->electrons);
}
void print_element(element_t uno){
printf("---------------\n| %d\t%.4f\n| %s\t%s\n| %s\n---------------\n", uno.num, uno.weight, uno.symbol, uno.name, uno.electrons);
}
int main (int argc, char *argv[]){
int i;
if (argc != 2){
printf("ERROR: You must provide exactly one argument to this program.\n");
return 0; }
int N = (int)strtol(argv[1], NULL, 10);
if(N <= 0){
printf("ERROR: Your must provide an integer greater than 0 and less than or equal to 20.\n");
return 0; }
element_t uno[MAX_ELEMENTS];
for(i=0; i<=argc; i++){
scan_element(&uno[i]); }
printf("%d total elements.\n", N);
printf(" had the smallest atomic number.\n");
printf(" had the largest atomic number.\n");
for(i=0; i<=argc; i++){
print_element(uno[i]); }
return 0;
}
Replace for(i=0; i<=argc; i++) with for(i=0;i<N;i++).
To omit the first 0 and everything after it in electrons, add
char*tmp;
if(tmp=strstr(uno->electrons," 0"))
*tmp=0;
to scan_element.
It is faster if you only pass the pointer in print_element, because 4 or 8 bytes will be copied instead of 92.
It is not good to use your current way to get string from input. See How to prevent scanf causing a buffer overflow in C?.
Related
I have this c program where I am inputing a number N followed by N more numbers. For example, I'll enter 100 followed by 100 more numbers. For some reason, after so many inputs the scanf function will stop working properly. It's as if it has stopped taking input and will just continue one with whatever value is in size.
The use case I came up with is 100 1 2 3 4 5 6 7 8 9 10... (repeated ten times). then after three or four times of that I'll type in 100 10 9 8 7 6 5 4 3 2 1... (repeated ten times) and then there will be an infinite loop of print statements.
int main(int argc, const char * argv[]) {
int histogram[10000];
int i;
while (1) {
int *rectPtr = histogram;
int size;
scanf("%d", &size);
if (!size) return 0;
for (i = 0; i < size; ++i) {
scanf("%d", rectPtr);
rectPtr++;
}
printf("%d", 1);
printf("\n");
}
return 0;
}
Distrust infinite loops.
In a series of comments, I said:
You're not testing the return value from scanf(), so you don't know whether it is working. The pair of printf() statements is odd; why not write printf("%d\n", 1); or even puts("1");?
Your code does not test or capture the return value from scanf(), so you do not know whether scanf() is reporting a problem. As a general rule, test the return value of input functions to make sure what you thought happened did in fact happen. You could also print out the values read just after you read them:
if (scanf("%d", rectPtr) != 1)
{
fprintf(stderr, "scanf() failed\n");
return 1;
}
printf("--> %d\n", *rectPtr);
rectPtr++;
Similarly when inputting size. Also consider if (size <= 0) return 0;. And using fgets() plus `sscanf() can make reporting errors easier.
j.will commented:
It is great to know if scanf fails, but I want to know why it fails and prevent it from failing. How do I do that?
I responded:
I understand you'd like to know. With scanf(), the best you can do after a failure is usually to read all the characters that follow up to a newline or EOF, and if you want to know what went wrong, then you print those characters too, because scanf() leaves the last character that it read in the input buffer ready for the next input operation.
void gobble(void)
{
printf("Error at: <<");
int c;
while ((c = getchar()) != EOF && c != '\n')
putchar(c);
puts(">>");
if (c == EOF)
puts("<<EOF>>");
}
The first character in the output is what caused the failure.
See also How to use sscanf() in loops?
Hacking your code to match this:
#include <stdio.h>
static void gobble(void)
{
printf("Error at: <<");
int c;
while ((c = getchar()) != EOF && c != '\n')
putchar(c);
puts(">>");
if (c == EOF)
puts("<<EOF>>");
}
int main(void)
{
enum { MAX_VALUES = 10000 };
int histogram[MAX_VALUES];
int size;
while (printf("Number of items: ") > 0 && scanf("%d", &size) == 1 &&
size > 0 && size <= MAX_VALUES)
{
int *rectPtr = histogram;
for (int i = 0; i < size; ++i)
{
if (scanf("%d", rectPtr) != 1)
{
gobble();
return 1;
}
rectPtr++;
}
printf("size %d items read\n", size);
}
return 0;
}
IMO, you need to check the return value of scanf() for proper operation. Please check the below code. I have added some modifications.
To exit from the program, you need to press CTRL+ D which will generate the EOF. Alternatively, upon entering some invalid input [like a char instead of int] wiil also cause the program to beak out of while() llop and terminate.
I have put the sequence to check first scanf(). All others need to be checked, too.
#include <stdio.h>
#include <stdlib.h>
int main(int argc, const char * argv[]) {
int histogram[10000] = {0};
int i;
int *rectPtr = histogram;
int size = 0;
int retval = 0;
printf("Enter the number of elements \n");
while ( (retval = scanf("%d", &size)) != EOF && (retval == 1)) {
rectPtr = histogram;
if (!size) return 0;
printf("Enter %d elements\n", size);
for (i = 0; i < size; ++i) {
scanf("%d", rectPtr); //check in a simmilar way to above
rectPtr++;
}
printf("%d\n", 1111111);
printf("Enter the number of elements: \n");
}
return 0;
}
The output of a sample run
[sourav#broadsword temp]$ ./a.out
Enter the number of elements: 2
Enter 2 elements
1
2
1111111
Enter the number of elements: 3
Enter 3 elements
1
2
3
1111111
Enter the number of elements: 9
Enter 9 elements
0
9
8
7
6
5
4
3
2
1111111
Enter the number of elements: r
[sourav#broadsword temp]$
histogram is declared to have size 10000. You say you do 100 1 2 3 ... repeated 10 times. If I correctly understand that uses 1000 slots in histogram.
If you repeat the test more than 10 times, you exhaust histogram and begin to write past the end of array causing undefined behaviour.
So you must either :
reset recPtr = histogram at each iteration
control recPtr - histogram + size <= sizeof(histogram) after reading size (IMHO better)
And as other said, you should always control input operations : anything can happen outside of your program ...
I'm trying to create a program that will take inputs into an array, and then print them all when input is terminated. My understanding was that when you declare a variable outside of the loop, it keeps the values, but I can't get this to work out. I know there's a way to do this somehow, but I'm drawing a blank.
#include <stdio.h>
int main(){
int i=0;
int n=0;
int size=0;
int numbers[i];
scanf("%d", &numbers[i]);
while ((i = 1 && numbers[i-1] != 42)){
scanf("%d", &numbers[i]);
i++;
size++;
//printf("%d",numbers[i]);
}
printf ("%d", sizeof(numbers));
while ((n = 0 && n < sizeof(numbers))){
printf("%d", numbers[i]);
printf("\n");
++i;
++n;
}
}
Your while condition:
(i = 1 && numbers[i-1] != 42)
has two problems:
i = ... actually assigns a value to i. In cas of unexpected looping, allways check if there's a =instead of an == in the condition
due to operator precedence, you assign 1 && to i. That's true value (i.e. 1) as long as you're in the loop, and as soon as numbers[i-1] is 42, i turns to 0 (because numbers[i-1]!=42 is false and 1 && false is false i.e. 0 ). This gives you impression that it didn't keep the value.
Edit: Of course, it's the same principle for n in the second loop ;-)
3 things in your code:
int numbers[i]; is trying to declare a zero element array, which accounts to undefined behavior.(although there's no bound/range checking in C)
scanf("%d", &numbers[i]), when i>=1 where is the storage allocated for this? mostly would end up in an undefined area/ over writing an existing value.
Refer the following links for more information:
Declaring an array with 0 number of elements can still store values
Why does C not define minimum size for an array?
that said you could either declare an array of fixed size or declare the size dynamically using malloc, then loop through the elements , assign and print them.
-the while loop: evaluation and priority of operators:
you could re-write your program as:
#include <stdio.h>
int main(){
int i=0;
int n=0;
int size=0;
int numbers[42];
scanf("%d", &numbers[i++]);
while (((numbers[i-1] != 42)))
scanf("%d", &numbers[i++]);
size=sizeof(numbers)/sizeof(int); /* Not necessary as array size pre-defined*/
printf("\nsize:%d\n",size);
while(n < size)
printf("%d\n", numbers[n++]);
printf("\n");
}
Note: you can change the size of the array, do keep in mind that it's an automatic variable and those array elements which haven't been explicitly initialized would be filled with junk values.
There are a lots of mistakes in your code.They are as follow-
1.int i=0;
int number[i]; which makes no sense. because you are creating an array of size 0
while ((i = 1 && numbers[i-1] != 42))
every time you while loop iterates it sets the value of i to 1 and compares numbers[0]!=42 which also makes no sense.
while ((n = 0 && n < sizeof(numbers)))
again you are assigning n to 0 and checking if n is less than sizeof(numbers) which is always true.
Although you did not specify your problem correctly I am assuming that you want to scan number till you get 42. And after that you want to print the size of the array and the numbers too.
Here is your working code.
#include <stdio.h>
int main(){
int i=0;
int n=0;
int size=1;
int numbers[10000];//I am assuming maximum input to be 10000
scanf("%d", &numbers[0]);
i=1;
while (( numbers[i-1] != 42)){
scanf("%d", &numbers[i]);
i++;
size++;
//printf("%d",numbers[i]);
}
printf ("size=%d\n", size);
while ( n < size){
printf("%d", numbers[n]);
printf("\n");
//++i;
++n;
}
}
It seems my implementation of fgets() is incorrect here, would very much appreciate some extra eyes to look over what I've done!
Here's the code
int main(int argc, const char* argv[]){
int numIntegers;
char buffer[20];
int intArray[10];
//if no argument is passed in, terminate
if (argc == 1){
printf("no argument given, terminating..\n");
return EXIT_FAILURE;
}
else{
numIntegers = atoi(argv[1]);
//we only want numbers greater than 0
if (numIntegers <= 0){
printf("# must be greater than 0\n");
return EXIT_FAILURE;
}
else{
printf("Enter %d integer values to place in array: \n", numIntegers);
for (int i = 0; i < numIntegers; i++){
fgets(buffer, numIntegers, stdin);
intArray[i] = atoi(buffer);
printf("Index is = %d \n", i);
}
}
}
//for (int i =0; i < numIntegers; i++){
// printf("Index[%d] = %d \n", i, intArray[i]);
//}
}
Here's the output, the line with no other text besides an integer is user input. Notice how the value of i resets. The issue only occurs when I give an initial argument of anything more than 10. It turns the for loop into an endless loop, for whatever reason.
$ ./a.out 11
Enter 11 integer values to place in array:
5
Index is = 0
2
Index is = 1
1
Index is = 2
2
Index is = 3
3
Index is = 4
4
Index is = 5
123
Index is = 6
123
Index is = 7
123
Index is = 8
1
Index is = 9
2
Index is = 2
2
Index is = 3
3
Index is = 4
5
Index is = 5
1
Index is = 6
12
Index is = 7
You are using
fgets(buffer, numIntegers, stdin);
The second parameter should be the size of the buffer - in your case, 20. That is at least one obvious problem...
The next problem: you are allowing numIntegers to be greater than 10 - so you will be writing values beyond the end of your intArray. Need to fix that too...
if(numIntegers > 10) {
printf("cannot have number greater than 10!\n");
// abort, retry, ignore...
}
In fact - here is your code, with the bugs ironed out: note the use of defined sizes for BUFSIZE and MAXNUM just so you don't have to change it in multiple places if you change your mind...
#include <stdio.h>
#define BUFSIZE 20
#define MAXNUM 10
#define EXIT_FAILURE 0
int main(int argc, const char* argv[]){
int i, numIntegers;
char buffer[BUFSIZE];
int intArray[MAXNUM];
//if no argument is passed in, terminate
if (argc == 1){
printf("no argument given, terminating..\n");
return EXIT_FAILURE;
}
else{
numIntegers = atoi(argv[1]);
//we only want numbers greater than 0
if (numIntegers <= 0 || numIntegers > MAXNUM){
printf("# must be greater than 0 and less than %d!\n", MAXNUM);
return EXIT_FAILURE;
}
else{
printf("Enter %d integer values to place in array: \n", numIntegers);
for (i = 0; i < numIntegers; i++){
fgets(buffer, BUFSIZE, stdin);
intArray[i] = atoi(buffer);
printf("Index is = %d \n", i);
}
}
}
}
Finally - you may wonder why your integer counter seems to "reset"? Well - your intArray is a block of 10 integers on the stack; and when you declare loop variable i, it occupies the next place in memory (as int intArray[10]; was the last time a variable was declared before you got to the for loop) - which you happen to get to when you "index" to intArray[10] (a memory location you are not allowed to access, but you did anyway). You happened to enter the value 2 - and thus, i was reset to 2...
If you had declared i at the start of the program (as I did, since my compiler doesn't "do" C99 by default - I'm that old!), the problem would have shown up differently - or not at all.
I'm trying to get user input using fgets and some funky (not correct) things are happening and I can't seem to understand why.
The program is run with an argument that indicates how many values the user is to input.
Here is how the program is supposed to run:
./a.out 6
Enter 6 integer values to place in tree:
5
4
3
2
1
6
Input values:
5
4
3
2
1
6
If I have 1 as the argument, it doesn't even allow me to enter an input, and where did the 0 come from?
./a.out 1
Enter 1 integer values to place in tree:
Input values:
0
If I have 2 as the argument, it only allows me to enter 1 input and the phantom 0 appears again.
./a.out 2
Enter 2 integer values to place in tree:
1
Input values:
1
0
If I have 3 or more arguments, it functions correctly.
Here's the source:
int main (int argc, const char* argv[]){
int numIntegers;
char buffer[20];
if (argc == 1){
printf("Usage: a.out #\n");
return EXIT_FAILURE;
}
else{
numIntegers = atoi(argv[1]);
if (numIntegers <= 0){
printf("# must be greater than 0\n");
return EXIT_FAILURE;
}
else{
int intArray[numIntegers];
printf("Enter %d integer values to place in tree: \n", numIntegers);
for (int i = 0; i < numIntegers; i++){
fgets(buffer, numIntegers, stdin);
intArray[i] = atoi(buffer);
}
printf("Input values:\n");
for (int i = 0; i < numIntegers; i++){
printf(%d\n", intArray[i]);
}
}
}
}//end main
The size argument to fgets() refers to the size of buffer, which should be 20 in your case.
fgets(buffer, sizeof(buffer), stdin);
By the way, your code won't actually compile.
printf(%d\n", intArray[i]); // missing a quotation mark
So I am trying to make a smaller simple program to solve a problem. For this, I am trying to check to make sure the user inputs a number containing ONLY 1s and 0s and then I will use this number to perform a division. For example the number 11010 or 10111. Now my problem is, if I declare an integer to store this number (as follows) there wouldn't be a way to check all the digits are 1s or 0s right?
int userInput;
Now, I can use an array for this. (I know how to do this BUT this leads to my second problem.). Like so:
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int main (int argc, char *argv[]){
int myArray[20];
int i, input, length;
printf("Please enter how long your number is: \n");
scanf("%d", &length);
for (i = 0; i < length; i++){
printf("Please enter digit %d of your array\n", i+1);
scanf("%d", &input);
assert ((input == 1) || (input ==0));
}
For example, for the first digit the user enters a '1', the second digit the user enters a '0', then the third digit the user enters '0'. I need to "grab" this number though. How would I grab this number "100" and perform arithmetic operations on it. I hope this makes sense, if not moderators please give me a chance to clear it up.
EDIT: Many have suggested the modulo approach. BUT I still want to know if I can do this with an array. That is creating a integer variable and set that equal to each element the user has entered in the array.
I think this could be more simple:
bool is_zeros_and_ones(int n) {
for (; n != 0; n /= 10) {
int mod = n % 10;
if (0 != mod && 1 != mod) {
return false;
}
return true;
}
So you can input whole number and test it without arrays.
You don't really need to get the number one digit at a time.
It is easy to extract the digits of an int. Notice that a number such as 12345 is actually
5 * 10^0 + 4 * 10^1 + 3 * 10^2 + 2 * 10^3 + 1 * 10^4.
To get the lowest digit you can just take the remainder of the number when divided by 10 (i.e. mod it by 10 using the % operator). So, 12345 % 10 is 5. To get the next digit, you can divide the number by 10 (getting 1234) and then mod by ten again - giving you 4. Keep doing this as long as you have digits left in the number (i.e. the number is > 0).
#include <stdio.h>
int is_valid(int number) {
if (number == 0) return 1; // its a 0.
while (number != 0) {
int digit = number % 10;
if (digit != 1 && digit != 0) return 0;
number = number / 10;
}
return 1; // no other digits were found.
}
int main() {
int n;
scanf("%d", &n);
if (is_valid(n)) printf("valid\n");
else printf("not valid\n");
return 0;
}
Here's another idea:
Just write the number again into a string. Then iterate over the string checking each character. This is somewhat less efficient, but simpler to understand/code.
#include <stdio.h>
int is_valid(int n) {
char buffer[20];
char *c;
sprintf(buffer, "%d", n);
for(c = buffer; *c != '\0'; c++) {
if (*c != '0' && *c != '1') return 0;
}
return 1;
}
int main() {
int n;
scanf("%d", &n);
if (is_valid(n)) printf("valid\n");
else printf("not valid\n");
return 0;
}
EDIT:
Since you mentioned in your edit that you are not interested in alternate approaches and just need a way to "grab" the digits as they are fed in, I'm adding this to my answer.
Keep a variable initially set to 0. Now as each digit comes in, (I am assuming the user enters higher digits before lower ones), we multiply our variable by 10 and add the new digit to it. Thus, if the user enters 1, 0, 0, our variable is initially 0, the its 1 (0 * 10 + 1), then its 10 (1*10 + 0) and finally 100 (10 * 10 + 0), which is what we needed.
Maybe something like this would be enough
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int main (int argc, char *argv[]){
int myArray[21];
printf("Please enter your number (max 20 digits)\n");
scanf("%s", myArray);
for (i = 0; i < strlen(myArray); i++){
assert ((myArray[i] == 1) || (myArray[i] == 0));
}
You don't need an array to store all the digits.
Keep dividing by 10 & taking modulo to get each digit & keep a single flag to mark if all digits are 1 or 0.
Of course works only for max word size of the integer...
Something like:
char isBinary = 1;
int copyInput = +input;
while(copyInput && (isBinary=copyInput%10<=1)) copyInput/=10;
You could cheat your way by making sure the program always deals with ints. Your array basically holds the binary representation of a base 10 number. Why not use it convert to an int. Then you can apply all operations to that number just as you would operate on ints.
Here is what i mean
#include <stdio.h>
#include <stdlib.h>
#include <assert.h>
int main (int argc, char *argv[]){
int i, input, length;
int num = 0; /* holds the actual number */
printf("Please enter how long your number is <= %d: \n", 8 * sizeof(num) - 1);
scanf("%d", &length);
for (i = 0; i < length; i++){
printf("Please enter digit %d of your array\n", i+1);
scanf("%d", &input);
assert ((input == 1) || (input ==0));
/* humans enter numbers L TO R */
/* set that bit if it is one */
num |= (input << (length - i - 1)) ;
}
printf("Your number in base 10 is %d\n",num);
/* Now you do normal multiplications, additions, divisions */
/* The only thing remaining now is to convert from base 10 to base 2. */
}
Sample run
Please enter how long your number is <= 31:
5
Please enter digit 1 of your array
1
Please enter digit 2 of your array
1
Please enter digit 3 of your array
1
Please enter digit 4 of your array
1
Please enter digit 5 of your array
0
Your number in base 10 is 30
This solution is only for the second part of the problem. You can take the input as characters and use atoi to convert them to integer.
char arrayOfNumbers[MAX_LENGTH];
char tmpChar;
int number;
for (i = 0; i < length; i++){
printf("Please enter digit %d of your array\n", i+1);
scanf("%c", &tmpChar);
assert ((tmpChar == '1') || (tmpChar == '0'));
arrayOfNumbers[i] = tmpChar;
}
/*make sure it is NULL terminated*/
arrayOfNumbers[length] = '\0';
number = atoi(arrayOfNumbers);