Reputation: 1
The input is
name number number
like the example
bank 1 10
I need to read input into a matrix n lines by 3 columns like the next example
{ bank, 1, 10,
bank2, 2, 15,
bank3, 3, 20 }
My main difficulty is reading the name and storing into the matrix. The name can vary from 1 to 41 characters.
I tried doing it the following way but I don't know a way to ignore the blank spaces in the input and how to make the for
loop only count until the word is read.
for (b=0; b<41;b++) {
scanf("%s ",&nome[i]);
}
scanf("%d %d",&rating,&ref);
n[i][0] = *nome;
n[i][1] = rating;
n[i][2] = ref;
I just started learning programming in C so I can't use advanced things in my code.
Upvotes: 0
Views: 2460
Reputation: 84569
Since you are working with a collection of different types of information (e.g. char*
, int
, int
), the proper way to collect this information is in a structure (or struct
). You have two choices on how to create space for any array or array of struct, (1) statically allocate on stack, or (2) dynamically allocate on heap. Given your question requirement, static allocation is the most basic. However, it is not as flexible as dynamically allocating the data, and you are limited to the initial size you choose.
Just as with storing the data, you have choices on how you read the data from stdin
. As a general proposition, when reading from stdin
, the preferred way is to read a line-at-a-time into a buffer and then parse the buffer for the desired content. Just as above, line input is more flexible than squeezing the data into a scanf
format string, but is a bit more involved. For purposes here, we will use scanf
, but know that line-input with getline
or fgets
provide certain advantages.
Next, you can just declare the number of structs you need, or you can take the time to initialize all the values in each of the structs. (this has advantages as you will see below). Aside for allowing some iteration tricks, the primary reason you initialize all your variables is to prevent the possibility of reading from them uninitialized. Reading an uninitialized variable results in Undefined Behavior (bad
). So take the time to learn how to initialize each of your variable types.
With that said, you can tell there are a number of valid ways to approach any problem. How you do it is up to you, as long as you do it correctly. Here is another approach to meet your requirements. Note that the maximum name length MAXNM
and maximum number of lines to read MAXLN
are defined at the top of the code. This allows you to easily adjust the values later on. Let me know if you have any questions:
#include <stdio.h>
#define MAXNM 41
#define MAXLN 100
typedef struct mix {
char name[MAXNM + 1];
int num1;
int num2;
} mix;
int main (void) {
/* initialize array of structs & variables */
mix array[MAXLN] = {{ {0}, 0, 0 }};
size_t i = 0;
size_t read = 0;
/* read array of struct contents from stdin */
while (scanf ("%s %d %d", array[i].name, &array[i].num1, &array[i].num2) == 3) {
i++;
/* check if lines > MAXLN allowed */
if (i >= MAXLN) {
fprintf (stderr, "warning: lines read from stdin exceed MAXLN.\n");
break;
}
}
/* set the number of elements read to i */
read = i;
/* iterate over elements using 'read' */
printf ("\nIterating array using 'while (i < read)'\n\n");
i = 0;
while (i < read) {
printf (" array[%zu] %-41s %4d %4d\n", i, array[i].name, array[i].num1, array[i].num2);
i++;
}
/* iterate over array by virtue of initization of name to 0/null */
i = 0;
printf ("\nIterating array using 'while (array[i].name[0])'\n\n");
while (array[i].name[0]) {
printf (" array[%zu] %-41s %4d %4d\n", i, array[i].name, array[i].num1, array[i].num2);
i++;
}
printf ("\n");
return 0;
}
Input
$ cat dat/staticstruct.txt
TheNamesofVaryingWidth 123 456
SomeOtherName 234 567
Bank_1 12 34
Bank_2 23 45
Bank_3 34 56
OneLastNameThatHasCloseToTheMaximumChars 777 9999
Output
$ ./bin/ptrarraystatic < dat/staticstruct.txt
Iterating array using 'while (i < read)'
array[0] TheNamesofVaryingWidth 123 456
array[1] SomeOtherName 234 567
array[2] Bank_1 12 34
array[3] Bank_2 23 45
array[4] Bank_3 34 56
array[5] OneLastNameThatHasCloseToTheMaximumChars 777 9999
Iterating array using 'while (array[i].name[0])'
array[0] TheNamesofVaryingWidth 123 456
array[1] SomeOtherName 234 567
array[2] Bank_1 12 34
array[3] Bank_2 23 45
array[4] Bank_3 34 56
array[5] OneLastNameThatHasCloseToTheMaximumChars 777 9999
Upvotes: 0
Reputation: 34585
In this example I have interpreted your "matrix" requirement, such that each line of the input fills in a struct
having different field types, so we end up with a 1-D array of the struct
instead of a 2-D array of differing data types.
And instead of entering the data from the keyboard, which is so boring every time you test the program, I have put your data in a file and read from that - although the technique is quite similar.
Also, because your input format is not consistent, I have skipped any chars that don't form part of the data, see delims
.
The program is possibly rather more complicated than you would have liked, but I hope it can help you do what you want. The complexity level rose when I decide not to use a fixed length string in the struct
but a pointer to string memory, allocated for a variable length string.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct {
char *nome;
int rating;
int ref;
} customer;
void fatal(char *msg) {
printf("%s\n", msg);
exit (1);
}
int main()
{
FILE *fp; // for fopen
char line[1000]; // for fgets
char *delims = ", {}\t\r\n"; // for strtok
char *sptr; // for strtok
customer *mark = NULL; // an empty array
int marks = 0; // number of customers
int len; // length of input string
fp = fopen("input.txt", "r"); // open the file
if (fp == NULL) // did it open?
fatal("Cannot open file");
while (fgets(line, 1000, fp) != NULL) { // each line of file
mark = realloc(mark, sizeof(customer) * (marks+1)); // extend
if (mark == NULL)
fatal("Cannot extend array"); // failed extend the array
sptr = strtok(line, delims); // split first field
if (sptr == NULL)
fatal("Cannot get first field");
len = strlen(sptr); // length of bank name
mark[marks].nome = malloc(len+1); // memory for the string
if (mark[marks].nome == NULL)
fatal("Cannot allocate string array");
strcpy(mark[marks].nome, sptr); // copy string to struct
sptr = strtok(NULL, delims); // split second field
if (sptr == NULL)
fatal("Cannot get second field");
mark[marks].rating = atoi(sptr); // extract number
sptr = strtok(NULL, delims); // split third field
if (sptr == NULL)
fatal("Cannot get third field");
mark[marks].ref = atoi(sptr); // extract number
marks++; // one more record
}
fclose (fp);
// print the results (re-using len for convenience)
for (len=0; len<marks; len++)
printf("%s %d %d\n", mark[len].nome, mark[len].rating, mark[len].ref);
// release the data array
for (len=0; len<marks; len++)
free(mark[len].nome);
free(mark);
return 0;
}
Input file:
{ bank, 1, 10,
bank2, 2, 15,
bank3, 3, 20 }
Program output:
bank 1 10
bank2 2 15
bank3 3 20
Upvotes: 0
Reputation: 180460
You are trying to read a string one character at a time, but using the edit descriptor for reading a whole string. You're trying to make it harder than it needs to be.
Also, the term "matrix" is normally understood to mean a 2-dimensional array of elements all the same type, whereas it sounds like you want a 1-dimensional array of struct
s containing members of different types. For example:
#define MAX_BANKS 10
struct bank {
char nome[42];
int rating;
int ref;
};
struct bank banks[MAX_BANKS];
int num_banks = 0;
/* ... */
void read_banks(void) {
while (num_banks < MAX_BANKS) {
int fields;
fields = scanf("%41s %d %d", banks[num_banks].nome,
&banks[num_banks].rating, &banks[num_banks].ref);
if (fields != 3) {
/* handle error */
break;
} else {
num_banks += 1;
}
/* ... */
}
}
Upvotes: 1