C - fscanf error with char * - c

I'm trying to read a txt file with this format:
8590 2 07 Goku
8591 2 07 Vegeta
6973 2 07 Picolo
5432 3 02 Jerez
6773 3 02 Sour
4689 4 03 Mosco
6981 5 06 Cabba
7891 5 06 Frost
The columns are: hp, universe color, universe number and name. What I do is this read the line and save the parameters in an array of structures called warrior with this format:
typedef struct Warrior{
int hp;
int color;
int universe;
char * name;
int posX;
int posY;
int ki;
} warrior;
warrior createWarrior(int inHp, int inColor, int inUniverse, char * inName){
warrior guerrero;
guerrero.hp = inHp;
guerrero.color = inColor;
guerrero.universe = inUniverse;
guerrero.name = inName;
guerrero.posX= 0;
guerrero.posY= 0;
guerrero.ki=0;
return guerrero;
}
The readFile code is:
warrior * readFile(char * nameFile, warrior * listGuerrero){
FILE * filePointer;
int sizeFile = 0, ch = 0;
int inHp, inColor, inUniverse;
char inName[50];
filePointer = fopen(nameFile, "r");
while(fscanf(filePointer, "%d %d %d %s\n", &inHp, &inColor, &inUniverse, inName) != EOF){
sizeFile ++;
}
rewind(filePointer);
listGuerrero = (warrior *)malloc(sizeFile*sizeof(warrior));
for(int k = 0; k < sizeFile; k++){
fscanf(filePointer, "%d %d %d %s\n", &inHp, &inColor, &inUniverse, &inName[0]);
listGuerrero[k] = createWarrior(inHp,inColor,inUniverse,inName);
printf("k: %d - HP: %d - Color: %d - Universo: %d - Nombre: %s \n", k, listGuerrero[k].hp, listGuerrero[k].color, listGuerrero[k].universe, listGuerrero[k].name);
}
fclose(filePointer);
return listGuerrero;
}
But for some reason I can't understand, the final list of warriors all have the same name like:
j: 0 - HP: 8590 - Color: 2 - Universo: 7 - Nombre: Frost
j: 1 - HP: 8591 - Color: 2 - Universo: 7 - Nombre: Frost
j: 2 - HP: 6973 - Color: 2 - Universo: 7 - Nombre: Frost
j: 3 - HP: 5432 - Color: 3 - Universo: 2 - Nombre: Frost
j: 4 - HP: 6773 - Color: 3 - Universo: 2 - Nombre: Frost
j: 5 - HP: 4689 - Color: 4 - Universo: 3 - Nombre: Frost
j: 6 - HP: 6981 - Color: 5 - Universo: 6 - Nombre: Frost
j: 7 - HP: 7891 - Color: 5 - Universo: 6 - Nombre: Frost
Is something wrong with the inName pointer?
When I debug, the first iteration prints:
j: 0 - HP: 8590 - Color: 2 - Universo: 7 - Nombre: Goku
And the second iteration prints:
j: 0 - HP: 8590 - Color: 2 - Universo: 7 - Nombre: Vegeta
j: 1 - HP: 8591 - Color: 2 - Universo: 7 - Nombre: Vegeta
and so on.

the problem is that you read the first name and after that for every warrior in the file you just set a pointer to that first name. For every element from your file you must allocate new memory for it's name (using malloc) and copy the new name into it( using strcpy). Because you declared the name char*
warrior createWarrior(int inHp, int inColor, int inUniverse, char * inName){
warrior guerrero;
guerrero.hp = inHp;
guerrero.color = inColor;
guerrero.universe = inUniverse;
guerrero.name = malloc(sizeof(char) * 30); // 30 is the length of the name
strcpy(guerrero.name,inName); // copy new name
guerrero.posX= 0;
guerrero.posY= 0;
guerrero.ki=0;
return guerrero;
}
There is another cool way to do it using strdup() which basically alocates new memory and copy the parameter string there ( but i've not tested this):
warrior createWarrior(int inHp, int inColor, int inUniverse, char * inName){
warrior guerrero;
guerrero.hp = inHp;
guerrero.color = inColor;
guerrero.universe = inUniverse;
guerrero.name = strdup(inName);
guerrero.posX= 0;
guerrero.posY= 0;
guerrero.ki=0;
return guerrero;
}
Don't forget:
#include <string.h>
#include <stdlib.h>

All of your input from scanf is written to the same memory location given for inName[50]. In each iterration you are overwritting the content, but assigning the same address to the guerrero.name. And when you print out, you get last entry printed.
You may try this:
warrior createWarrior(int inHp, int inColor, int inUniverse, char * inName){
...
guerrero.name = strdup(inName);
....
return guerrero;
}

Related

I want to read a file and save them into the array of struct how can I do it?

I'm very new to file and struct and I just don't know how to do it. Now, I try to find how to do it everywhere but I can't find it. This is my code.
#include <stdio.h>
typedef struct
{
int site_id_num;
int day_of_month[14];
int wind_speed[14];
int temperature[14];
}measured_data_t;
int main()
{
FILE *read;
measured_data_t station[5];
read = fopen("data", "r");
for(int i = 0; i < 5; i++)
{
for(int j = 0; j < 14; j++)
{
fscanf(read, "%d %d %d %d", station[i].site_id_num, station[i].day_of_month[j], station[i].wind_speed[j], station[i].temperature[j]);
}
}
for(int i = 0; i < 5; i++)
{
for(int j = 0; j < 14; j++)
{
printf("%d %d %d %d\n", station[i].site_id_num, station[i].day_of_month[j], station[i].wind_speed[j], station[i].temperature[j]);
}
}
fclose(read);
return 1;
}
And this is the text file that I want to read and save into an array of struct.
1000 1 6 22
1000 2 9 21
1000 3 15 27
1000 4 24 26
1000 5 11 23
1000 6 24 22
1000 7 21 16
1000 8 10 20
1000 9 22 22
1000 10 3 25
1000 11 14 32
1000 12 23 33
1000 13 4 22
1000 14 25 35
2000 1 13 20
2000 2 1 28
2000 3 18 31
2000 4 2 34
2000 5 4 31
2000 6 18 15
2000 7 10 34
2000 8 14 33
2000 9 12 25
2000 10 11 24
2000 11 6 21
2000 12 12 26
2000 13 17 35
2000 14 20 25
3000 1 5 23
3000 2 17 33
3000 3 20 19
3000 4 7 35
3000 5 17 16
3000 6 2 28
3000 7 13 15
3000 8 23 33
3000 9 19 19
3000 10 16 27
3000 11 21 28
3000 12 22 18
3000 13 11 20
3000 14 1 32
4000 1 10 30
4000 2 2 28
4000 3 24 19
4000 4 11 22
4000 5 25 26
4000 6 1 23
4000 7 24 16
4000 8 13 24
4000 9 23 28
4000 10 2 15
4000 11 3 24
4000 12 7 28
4000 13 17 16
4000 14 10 18
5000 1 12 31
5000 2 10 24
5000 3 3 18
5000 4 25 16
5000 5 14 21
5000 6 11 24
5000 7 15 29
5000 8 4 28
5000 9 2 28
5000 10 22 21
5000 11 9 18
500 12 11 16
5000 13 2 33
5000 14 21 27
I want each station to have id, 14 days, 14 wind speeds, and 14 temperatures. But I have no clues right now. Please help me.
If your data is indeed fixed format like this then you just need to pass in the address of your variables when calling fscanf(). Initialized the array so at least you will 0 values if the data doesn't conform. Check the return value from fscanf() to ensure you read 4 numbers. Use sizeof() instead of hard-coding the array sizes. Don't return 1 which means there was an error.
#include <stdio.h>
typedef struct {
int site_id_num;
int day_of_month[14];
int wind_speed[14];
int temperature[14];
} measured_data_t;
int main(void) {
FILE *read = fopen("data", "r");
measured_data_t station[5] = { 0 };
for(size_t i = 0; i < sizeof station / sizeof *station; i++) {
for(size_t j = 0; j < sizeof station->day_of_month / sizeof *station->day_of_month; j++) {
int r = fscanf(read, "%d %d %d %d",
&station[i].site_id_num,
&station[i].day_of_month[j],
&station[i].wind_speed[j],
&station[i].temperature[j]
);
if(r != 4) {
printf("fscanf failed\n");
return 1;
}
}
}
fclose(read);
for(size_t i = 0; i < sizeof station / sizeof *station; i++)
for(size_t j = 0; j < sizeof station->day_of_month / sizeof *station->day_of_month; j++)
printf("%d %d %d %d\n", station[i].site_id_num, station[i].day_of_month[j], station[i].wind_speed[j], station[i].temperature[j]);
}
Obvious fix of an error that a decent compiler should warn about:
main.c: In function ‘main’:
main.c:23:28: warning: format ‘%d’ expects argument of type ‘int *’, but argument 3 has type ‘int’ [-Wformat=]
23 | fscanf(read, "%d %d %d %d", station[i].site_id_num, station[i].day_of_month[j], station[i].wind_speed[j], station[i].temperature[j]);
| ~^ ~~~~~~~~~~~~~~~~~~~~~~
| | |
| int * int
main.c:23:31: warning: format ‘%d’ expects argument of type ‘int *’, but argument 4 has type ‘int’ [-Wformat=]
etc.
Use the address operator & to pass the address of the variable where fscanf shall store the value:
fscanf(read, "%d %d %d %d", &station[i].site_id_num, &station[i].day_of_month[j], &station[i].wind_speed[j], &station[i].temperature[j]);
There are more problems in the code:
You should check the return value of all *scanf functions. It is the number of converted items which is expected to be 4 in your case.
Better read a line of input using fscanf and parse the string using sscanf. This avoids getting out of sync in case an input line contains an error or more or less values than expected.
char line[100];
if(fgets(line, sizeof(line), read) == NULL)
{
/* handle EOF or error */
}
/* check for trailing newline to detect input lines that are too long */
if(sscanf(line, "%d %d %d %d", &station[i].site_id_num, &station[i].day_of_month[j], &station[i].wind_speed[j], &station[i].temperature[j]) != 4)
{
/* handle error */
}
Your code is implemented in a way that the loops must match (predict) the input, i.e. 5 stations with 14 records each. I suggest to read the data into a temporary structure or temporary variables, compare the station ID to check if you have the next record for the same station or the next station, and copy the data into the final location.
Instead of using 3 arrays in the structure which in fact represent a set of data records, I suggest to use an array of structures.
typedef struct
{
int site_id_num;
struct record {
int day_of_month;
int wind_speed;
int temperature;
} data[14];
}measured_data_t;
I would like to suggest to read data into array of structures, such as in code that follows.
#include <stdio.h>
#include <stdlib.h>
typedef struct measured_data
{
int site_id_num;
int day_of_month;
int wind_speed;
int temperature;
} measured_data_t;
int main()
{
FILE *fp;
int stations = 5;
int measurements = 14;
measured_data_t data[stations * measurements];
if( (fp = fopen("data", "r")) == NULL )
{
printf("error opening file\n");
exit(1);
}
int retv = 0;
for(int i = 0; i < stations * measurements && retv != EOF; i++ )
{
retv = fscanf(fp, "%d %d %d %d",
&data[i].site_id_num,
&data[i].day_of_month,
&data[i].wind_speed,
&data[i].temperature);
}
for(int i = 0; i < stations * measurements ; i++ )
{
printf( "%d %d %d %d\n",
data[i].site_id_num,
data[i].day_of_month,
data[i].wind_speed,
data[i].temperature);
}
fclose(fp);
}
Just use binary file I/O
Writing:
fp = fopen("data.bin", "wb");
for(int i = 0; i < 5; i++)
fwrite(&station, 1, sizeof(measured_data_t), fp);
Reading:
fp = fopen("data.bin", "rb");
for(int i = 0; i < 5; i++)
fread(&station, 1, sizeof(measured_data_t), fp);

How do I get the sum of a txt file and a binary file both of which have array size of 10?

My code is very likely to be incorrect everywhere since I just go started on learning files.
The array of the text file is {3 2 1 3 4 5 6 1 2 3}
The array of the binary is {1 2 3 4 5 6 7 8 9 10}
#include <stdio.h>
#define ARR_SIZ 10
int main()
{
int arr_in[ARR_SIZ];
int arr_bin[ARR_SIZ];
int i = 0;
FILE * fp_in = fopen("data/in.txt", "r");
FILE * fp_bin = fopen("data/in.bin", "wb");
fread(arr_in, sizeof(int), ARR_SIZ, fp_in);
fread(arr_bin, sizeof(int), ARR_SIZ, fp_bin);
int sum[ARR_SIZ];
for (i=0; i < ARR_SIZ; i++){
fscanf("%d", arr_in);
fscanf("%d", arr_in);
sum[i] = arr_in[i] + arr_bin[i];
} printf("%d", sum[i]);
return 0;
}
fread() reads binary data even when the file is not opened with "b" which just means it doesn't do funny stuff with things like Windows-style line breaks.
If you want to read a text file you will how to do more complex work like reading in the data, look for line breaks, and than use the data before each line break. As that data is still a string you will need to convert it to an integer (e.g. using atoi())
You can use this simple program (without fread()):
#include <stdio.h>
#define SIZE 10
int main(void) {
FILE *text = fopen("in.txt", "r"); // --- declaration
FILE *binr = fopen("in.bin", "r");
int text_number[SIZE], binary_number[SIZE], sum = 0;
// alt: you can change sum to sum[SIZE] = {0} if you want to hold into an array.
// --- reading data and assigning into arrays
for (int i = 0; i < SIZE; i++) {
fscanf(text, "%d", &text_number[i]);
fscanf(binr, "%d", &binary_number[i]);
}
// --- summation
for (int i = 0; i < SIZE; i++) {
sum += text_number[i] + binary_number[i]; // alt: do sum[i] when you do sum[SIZE]
printf("%d ", sum); // alt: do sum[i]
sum = 0; // should be omitted when you change into sum[SIZE]
}
printf("\n");
return 0;
}
in.bin contains: 1 2 3 4 5 6 7 8 9 10
Similarly, in.txt contains: 3 2 1 3 4 5 6 1 2 3
And the result is: 4 4 4 7 9 11 13 9 11 13 (sum of both files' integers taken by array).
Note: If you want to store the sum into array, then use the alt code.
I'm not very much aware of fread(), so I just did what I could at the moment.

C language wrong output...pascal triangle using 2d arrays

So this is my code for printing pascal triangle using 2d arrays but its not giving me the desired output and I cannot determine what's wrong with the logic/code.
#include <stdio.h>
int main()
{
int num, rows, col, k;
printf("Enter the number of rows of pascal triangle you want:");
scanf("%d", &num);
long a[100][100];
for (rows = 0; rows < num; rows++)
{
for (col = 0; col < (num - rows - 1); col++)
printf(" ");
for (k = 0; k <= rows; k++)
{
if (k == 0 || k == rows)
{
a[rows][k] = 1;
printf("%ld", a[rows][k]);
}
else
a[rows][k] = (a[rows - 1][k - 1]) + (a[rows - 1][k]);
printf("%ld", a[rows][k]);
}
printf("\n");
}
return 0;
}
You don't have curly braces around the statements after the else, so it looks like you'll double-printf() when the condition of the if-statement is true.
I copied the source into codechef.com/ide and changed the io for num to be just assigned to 6 which produced the following output:
Enter the number of rows of pascal triangle you want:
11
1111
11211
113311
1146411
1151010511
It looks like your close, but you want 1, 11, 121, 1331 etc right?
Wraping the else case produced the following output:
if (k == 0 || k == rows)
{
a[rows][k] = 1;
printf("(%ld)", a[rows][k]);
}
else{// START OF BLOCK HERE
a[rows][k] = (a[rows - 1][k - 1]) + (a[rows - 1][k]);
printf("(%ld)", a[rows][k]);
}//END OF BLOCK HERE, NOTE THAT IT INCLUDES THE PRINT IN THE ELSE CASE NOW
OUTPUT:
Enter the number of rows of pascal triangle you want:
(1)
(1)(1)
(1)(2)(1)
(1)(3)(3)(1)
(1)(4)(6)(4)(1)
(1)(5)(10)(10)(5)(1)
But i added () to make it clearer to me. I also added a "/n" to the end of the first printf that asks for the value of num, so that the first line is on a new line.
printf("Enter the number of rows of pascal triangle you want:\n");
You can do that without using any arrays:
#include <stdlib.h>
#include <stdio.h>
int num_digits(int number)
{
int digits = 0;
while (number) {
number /= 10;
++digits;
}
return digits;
}
unsigned max_pascal_value(int row)
{
int result = 1;
for (int num = row, denom = 1; num > denom; --num, ++denom)
result = (int)(result * (double)num / denom );
return result;
}
int main()
{
printf("Enter the number of rows of pascals triangle you want: ");
int rows;
if (scanf("%d", &rows) != 1) {
fputs("Input error. Expected an integer :(\n\n", stderr);
return EXIT_FAILURE;
}
int max_digits = num_digits(max_pascal_value(rows));
for (int i = 0; i <= rows; ++i) {
for (int k = 0; k < (rows - i) * max_digits / 2; ++k)
putchar(' ');
int previous = 1;
printf("%*i ", max_digits, previous);
for (int num = i, denom = 1; num; --num, ++denom) {
previous = (int)(previous * (double)num / denom );
printf("%*i ", max_digits, previous);
}
putchar('\n');
}
}
Output:
Enter the number of rows of pascals triangle you want: 15
1
1 1
1 2 1
1 3 3 1
1 4 6 4 1
1 5 10 10 5 1
1 6 15 20 15 6 1
1 7 21 35 35 21 7 1
1 8 28 56 70 56 28 8 1
1 9 36 84 126 126 84 36 9 1
1 10 45 120 210 252 210 120 45 10 1
1 11 55 165 330 462 462 330 165 55 11 1
1 12 66 220 495 792 924 792 495 220 66 12 1
1 13 78 286 715 1287 1716 1716 1287 715 286 78 13 1
1 14 91 364 1001 2002 3003 3432 3003 2002 1001 364 91 14 1
1 15 105 455 1365 3003 5005 6435 6435 5005 3003 1365 455 105 15 1

How to generate unique numbers in range 0001 - 2000 with rand() in C

I am trying to generate a dataset that has these two items: (i) a student ID containing values (0001 to 2000) generated from random and (ii) a corresponding age to the student ID (18 to 30). These random values are held in their respective array[1000] as you can see in Code
I am running into an issues with rand() where I have specified that I want to generate random numbers for the student ID from 1 to 2000 but I am running into what I think to be an issues of interger overflow. I think that the issues may be coming from one of the following:
My function is of type int, I may need to try a different type?
There is something wrong with the way I implemented my rand() % declaration
Some other problem that I am not aware of
You can see the issue I am having in Output
Code:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int createDataSet(void)
{
srand(time(NULL)); // generates the random numbers
int i = 0, x, p, count;
char arrayId[1000]; // array that holds the ID's of 1000 students
char arrayAges[1000]; // array that holds the ages of 1000 students
for (count = 0; count < 1000; count++) // Init the "age" and "id" arrays
{
arrayId[count] = rand() % 2000 + 1; // ID range 0001 - 2000
arrayAges[count] = rand() % (30 + 1 - 18) + 18; // Age range 18 - 30
}
while(i<1000){
int r=rand() % (2000 + 1 - 0001) + 0001;
for (x = 0; x < i; x++)
{
if(arrayId[x]==r){
break;
}
}
if(x==i){
arrayId[i++]=r;
}
}
for (p = 0; p < 1000; p++)
{
printf("ID Number: %d Age: %d\n", arrayId[p], arrayAges[p]);
}
return 0;
}
Output:
ID Number: 115 Age: 28
ID Number: 104 Age: 21
ID Number: -113 Age: 25
ID Number: -3 Age: 18
ID Number: -41 Age: 20
ID Number: -94 Age: 28
ID Number: -4 Age: 19
ID Number: 4 Age: 28
ID Number: -112 Age: 23
ID Number: 33 Age: 20
ID Number: -119 Age: 30
ID Number: 12 Age: 23
ID Number: -96 Age: 27
ID Number: -88 Age: 30
ID Number: -105 Age: 20
My goal is to try and get the value in the array as seen in ID Number: to display random values between 1 to 2000 and be of unsigned type. Any help is appreciated. Thanks for your time!
While you already have a good answer to your initial problem of attempting to assign and integer value outside the range of char to a char variable, there are a large number of small problems that remain unaddressed.
First, don't use magic numbers in your code. If you need constants, either #define them or use a global enum to define them, e.g.
/* if you need a constants, define them */
enum { MINA = 18, MAXA = 30, MAXS = 1000, MAXID = 2000 };
(where MINA is just short for MINIMUMAGE and MAXS for MAXIMUMSTUDENTS, etc.)
That way if you need to change a range or a limit, you have one simple location at the top of your code to make the change and you don't have to pick through all loop limits and variable declarations.
Next, your return 0; in createDataset is meaningless. If you have no value to return, and you are not doing anything within the function that requires a return to gauge success/failure, then declare your function as void. On the same note, the function may generate a dataset and print the values to stdout, but if the dataset is needed in the rest of your code, there is no way it can be used. Why? All your arrays char arrayId[].. are declared local to your function and the memory they are stored in is destroyed (release for reuse) when the function returns. You may want to refactor your code to declare the arrays in main() and pass the arrays, along with the number of elements to your function for initialization.
You can use this temporary storage within your function to your advantage in preventing duplicate IDs. You can simply declare a character array of MAXID length (say char filled[MAXID] = "";), initialized to all zeros and as each corresponding ID is generated, set the value at that index to 1 (or some nonzero value). That makes duplicate checks a simple test of if (filled[r]) { /* regenerate ID */ }
When you consider refactoring your code, you want to separate the function of each function into logical units. Your combined generate ID/age and output may fit your immediate needs, but consider separating the generating function and output into separate function.
While not an error, the standard coding style for C avoids the use of camelCase or MixedCase variable names in favor of all lower-case while reserving upper-case names for use with macros and constants. It is a matter of style -- so it is completely up to you, but failing to follow it can lead to the wrong first impression in some circles.
Putting those pieces together, you could refactor your current function into a separate generate and print function as follows:
void createdataset (unsigned short *ids, char *ages, int count)
{
char filled[MAXID] = {0}; /* array preventing duplicates */
for (count = 0; count < MAXS; count++) /* for each student */
{
/* generate an ID */
unsigned short r = (unsigned short)(rand() % MAXID + 1);
while (filled[r]) /* while a duplicate, regenerate */
r = (unsigned short)(rand() % MAXID + 1);
filled[r] = 1; /* set filled[index] to 1 */
ids[count] = r; /* assign ID to student */
ages[count] = (char)(rand() % (MAXA - MINA + 1) + MINA);
}
}
void prndataset (unsigned short *ids, char *ages, int count)
{
int i = 0;
for (i = 0; i < count; i++)
printf ("ID Number: %4hu Age: %2hhd\n", ids[i], ages[i]);
}
note: srand should only be called once in your code. So if you may potentially generate more than one dataset, it should be placed in main() to insure it is only called once.
When you are developing code that must meet special criteria, like IDs between 1-2000 and age between 18-30 consider writing a simple validation check that will verify all of your values are within range. For example here you could do something like:
int validateset (unsigned short *ids, char *ages, int count)
{
int i = 0, err = 0;
for (i = 0; i < count; i++) {
if (ids[i] < 1 || ids[i] > MAXID) {
fprintf (stderr, "error: arrayid[%d] : %hu out of range.\n",
i, ids[i]);
err = 1;
}
if (ages[i] < MINA || ages[i] > MAXA) {
fprintf (stderr, "error: arrayages[%d] : %hhd out of range.\n",
i, ages[i]);
err = 1;
}
}
return err;
}
(which will return 0 on success, and 1 if there is any value out of range after outputting any offending values)
Also, when you are printing values, make sure your format specifiers match the type of value you are outputting. While rules of promotion will handle converting smaller values (e.g. short) to int using the %d or %u format specifiers, if your compiler supports the h modifiers, they should be used to specify the proper output size (e.g. to print a unsigned short, use %hu or to print an unsigned char, use %hhu).
Putting all the pieces together in a short example, you could refactor your code and add a validation check with something similar to the following:
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
/* if you need a constants, define them */
enum { MINA = 18, MAXA = 30, MAXS = 1000, MAXID = 2000 };
void createdataset (unsigned short *ids, char *ages, int count)
{
char filled[MAXID] = {0}; /* array preventing duplicates */
for (count = 0; count < MAXS; count++) /* for each student */
{
/* generate an ID */
unsigned short r = (unsigned short)(rand() % MAXID + 1);
while (filled[r]) /* while a duplicate, regenerate */
r = (unsigned short)(rand() % MAXID + 1);
filled[r] = 1; /* set filled[index] to 1 */
ids[count] = r; /* assign ID to student */
ages[count] = (char)(rand() % (MAXA - MINA + 1) + MINA);
}
}
void prndataset (unsigned short *ids, char *ages, int count)
{
int i = 0;
for (i = 0; i < count; i++)
printf ("ID Number: %4hu Age: %2hhd\n", ids[i], ages[i]);
}
int validateset (unsigned short *ids, char *ages, int count)
{
int i = 0, err = 0;
for (i = 0; i < count; i++) {
if (ids[i] < 1 || ids[i] > MAXID) {
fprintf (stderr, "error: arrayid[%d] : %hu out of range.\n",
i, ids[i]);
err = 1;
}
if (ages[i] < MINA || ages[i] > MAXA) {
fprintf (stderr, "error: arrayages[%d] : %hhd out of range.\n",
i, ages[i]);
err = 1;
}
}
return err;
}
int main (void) {
unsigned short arrayid[MAXS] = {0}; /* size your type to your needed */
char arrayages[MAXS] = {0}; /* range and enforce the range */
srand(time(NULL)); /* initialize random number seed */
createdataset (arrayid, arrayages, MAXS); /* initialize dataset */
if (validateset (arrayid, arrayages, MAXS)) /* validate dataset */
exit (EXIT_FAILURE);
prndataset (arrayid, arrayages, MAXS); /* output dataset */
return 0;
}
(by adding the validation check, you can have confidence that if your code runs without displaying an error, the dataset was generated properly)
Example Use/Output
$ ./bin/createdataset > dat/dataset1.txt
$ head -n 10 dat/dataset1.txt; echo "..."; tail -n 10 dat/dataset1.txt
ID Number: 1049 Age: 29
ID Number: 743 Age: 21
ID Number: 915 Age: 22
ID Number: 1539 Age: 19
ID Number: 793 Age: 18
ID Number: 1166 Age: 21
ID Number: 372 Age: 28
ID Number: 1763 Age: 19
ID Number: 782 Age: 20
ID Number: 1490 Age: 30
...
ID Number: 186 Age: 30
ID Number: 1389 Age: 23
ID Number: 1630 Age: 22
ID Number: 432 Age: 27
ID Number: 240 Age: 24
ID Number: 152 Age: 25
ID Number: 1598 Age: 22
ID Number: 1408 Age: 24
ID Number: 834 Age: 24
ID Number: 1699 Age: 25
While your main issues was the storage of an int in char problem, there are many other more subtle issues to consider. Look things over and let me know if you have any further questions.
Declare arrayId as unsigned short array because unsigned char arrayId[index] won't work as maximum in each arrayId[index] you can store only 255 but you want to store upto 2000.
unsigned short arrayId[1000]; /* try to store negative number, cyclic flow will happen */
unsigned char arrayAges[1000];
use this code
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void)
{
srand(time(NULL));
int i = 0, x, p, count;
unsigned arrayId[1000]; //You Can USE :unsigned int or unsigned short
char arrayAges[1000];
for (count = 0; count < 1000; count++)
{
arrayId[count] = rand() % 2000 + 1;
arrayAges[count] = rand() % (30 + 1 - 18) + 18;
}
for (p = 0; p < 1000; p++)
{
printf("%d.ID Number: %ld Age: %d\n",p+1, arrayId[p], arrayAges[p]);
}
return 0;
}
output:
1.ID Number: 1467 Age: 27
2.ID Number: 1316 Age: 21
3.ID Number: 1213 Age: 19
4.ID Number: 171 Age: 29
5.ID Number: 661 Age: 21
6.ID Number: 297 Age: 27
7.ID Number: 853 Age: 23
8.ID Number: 67 Age: 29
9.ID Number: 500 Age: 20
10.ID Number: 274 Age: 24
11.ID Number: 821 Age: 25
12.ID Number: 355 Age: 19
13.ID Number: 1797 Age: 23
14.ID Number: 1036 Age: 30
15.ID Number: 1637 Age: 18
16.ID Number: 385 Age: 22
17.ID Number: 1574 Age: 24
18.ID Number: 1305 Age: 20
19.ID Number: 1658 Age: 24
20.ID Number: 794 Age: 29
21.ID Number: 1758 Age: 24
22.ID Number: 1239 Age: 27
23.ID Number: 989 Age: 30
24.ID Number: 1449 Age: 22
25.ID Number: 1390 Age: 26
26.ID Number: 1731 Age: 25
27.ID Number: 1465 Age: 26
28.ID Number: 792 Age: 20
29.ID Number: 1974 Age: 24
30.ID Number: 1674 Age: 23
31.ID Number: 533 Age: 19
32.ID Number: 1078 Age: 28
33.ID Number: 571 Age: 25
34.ID Number: 48 Age: 20
35.ID Number: 115 Age: 19
36.ID Number: 345 Age: 24
.
.
.
979.ID Number: 35 Age: 30
980.ID Number: 965 Age: 29
981.ID Number: 457 Age: 26
982.ID Number: 615 Age: 24
983.ID Number: 667 Age: 26
984.ID Number: 1381 Age: 19
985.ID Number: 1032 Age: 20
986.ID Number: 534 Age: 26
987.ID Number: 1372 Age: 27
988.ID Number: 1299 Age: 24
989.ID Number: 1463 Age: 24
990.ID Number: 880 Age: 18
991.ID Number: 1928 Age: 28
992.ID Number: 867 Age: 23
993.ID Number: 1580 Age: 29
994.ID Number: 917 Age: 18
995.ID Number: 237 Age: 28
996.ID Number: 384 Age: 19
997.ID Number: 356 Age: 20
998.ID Number: 327 Age: 27
999.ID Number: 1768 Age: 18
1000.ID Number: 148 Age: 27
Process returned 0 (0x0) execution time : 1.832 s
Press any key to continue.
it'll also help you
#include <stdio.h>
#include <stdlib.h>
#include <time.h>
int main(void)
{
srand(time(NULL)); // generates the random numbers
int i = 0, x, p, count;
int arrayId[1000]; // array that holds the ID's of 1000 students
char arrayAges[1000]; // array that holds the ages of 1000 students
for (count = 0; count < 1000; count++) // Init the "age" and "id" arrays
{
//arrayId[count] = rand() % 2000 + 1; // ID range 0001 - 2000
arrayId[count] =rand() % (2000 + 1 - 1) + 1;
arrayAges[count] = rand() % (30 + 1 - 18) + 18; // Age range 18 - 30
}
while(i<1000){
int r=rand() % (2000 + 1 - 0001) + 0001;
for (x = 0; x < i; x++)
{
if(arrayId[x]==r){
break;
}
}
if(x==i){
arrayId[i++]=r;
}
}
for (p = 0; p < 1000; p++)
{
printf("%d.ID Number: %ld Age: %d\n",p+1, arrayId[p], arrayAges[p]);
}
return 0;
}

Process data from char array

I have a little problem,
I have a char array like this:
char buff[256] = { "2 22 3 14 5 8 23 45 2 7 88"};
and what I need to do is:
if 1st number in buff is bigger than 5 I need to sort this numbers ASC
if 1st number in buff is smaller than 5 I need to sort this numbers DESC
in this example the 1st number is 2, so I need to sort this array DESC
I want to create an int array and copy numbers from char buff to int array but I can't figure out how to do this.
Sorting this data in int array will be easy.
I have tried smth like this:
int array[256];
for (int i = 0; i<26; i++)
array[i] = atoi(&buff2[i]);
and the result is not good
array[0]: 2
array[1]: 22
array[2]: 22
array[3]: 2
array[4]: 3
array[5]: 3
array[6]: 14
array[7]: 14
array[8]: 4
array[9]: 5
array[10]: 5
array[11]: 8
array[12]: 8
array[13]: 23
array[14]: 23
array[15]: 3
array[16]: 45
array[17]: 45
array[18]: 5
array[19]: 2
array[20]: 2
array[21]: 7
array[22]: 7
array[23]: 88
array[24]: 88
array[25]: 8
For a 'C' answer, I would use strtol, because it tells you where the parsed number ends in the buffer:
#include <stdio.h>
#include <stdlib.h>
int main() {
char buff[] = "2 22 3 14 5 8 23 45 2 7 88";
char* p=buff;
for(;;) {
char* ep; // end pointer
int n = strtol(p, &ep, 0);
// if ep == p, no parsing took place
if(p != ep) {
// parsing succeeded
printf("%d\n", n);
}
if(!*ep) break; // check if we hit the end of the string
p = ep + 1; // advance to the next character
}
}
Prints:
2
22
3
14
5
8
23
45
2
7
88
For C++, you may want to convert the text to a std::istringstream then treat as an input stream:
const char buff[] = { "2 22 3 14 5 8 23 45 2 7 88"};
const std::string text(buff);
std::vector<int> database;
std::istringstream buf_stream(text);
int value;
while (buf_stream >> value)
{
database.push_back(value);
}
For ascending and descending sorting, you can write comparison functions and pass them to std::sort.

Resources