So, I am creating a program that reads in a file called "Bankfile.txt" and the the first number "3" is to indicate how many account we are working with. The numbers "123" "467" and "499" are the bank account numbers and the numbers next to each is their original balances. In my code I am using a 2D array to scan them in. I think I have everything correct in scanning them in but when I run the program the account numbers are being printed very weird as seen here. Any ideas on why it is being printed like this?
Thank you!
#include <stdio.h>
int main(){
FILE* file;
file = fopen("bankfile.txt","r");
int accounts,b=1,w=2,d=3,u=4,i,j,accNum,origBal;
float interest = .0185;
float test;
float accountInfo[accNum][origBal];
fscanf(file, "%d", &accounts);
for(i = 0; i < accounts; i++)
{
fscanf(file, "%d", &accountInfo[i]);
for(j = 0; j < 1; j++)
{
fscanf(file, "%f", &accountInfo[i][j]);
printf("Account %d has a balance of $%.2f\n", accountInfo[i], accountInfo[i][j]);
}
}
system("pause");
return 0;
}
Ok what you have here is not a 2-dimensional array -- this is conceptually wrong. An account number only has one balance associated with it. So what you have is only a single dimension, but your data has several fields ... that's where you use a struct in C. Here's some example code that would produce the output you expect:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
/* data structure holding a bank account */
typedef struct account
{
int id;
double balance;
} account;
int main(void)
{
int cap = 1024; /* initial capacity of account array */
int count = 0; /* number of accounts */
char buf[1024]; /* buffer for a line of text */
char *tok; /* token from text line */
FILE *bankfile;
int i;
account *accounts = malloc(cap * sizeof(account));
bankfile = fopen("bankfile.txt", "r");
while (fgets(buf, 1024, bankfile))
{
int accId;
tok = strtok(buf, " \t\r\n");
if (!tok) continue;
accId = atoi(tok);
if (accId > 0)
{
/* first token in line was a positive integer */
tok = strtok(0, " \t\r\n");
if (tok)
{
/* there was a second token in the same line, then we found
* an account with a balance */
accounts[count].id = accId;
accounts[count].balance = atof(tok);
if (++count == cap)
{
cap *= 2;
accounts = realloc(accounts, cap * sizeof(account));
}
}
}
}
fclose(bankfile);
for (i = 0; i < count; ++i)
{
printf("Account %d has a balance of $%.2f\n",
accounts[i].id, accounts[i].balance);
}
free(accounts);
return 0;
}
This can be simplified by first reading the first line and then only allocating as many elements of account as needed.
of course, for production, add error checking to fopen() and malloc() and friends ...
First of all I think you don't understand the concept of two-dimensional arrays. When you have a 2D array (foo) and add two arrays into that it will look something like this.
int foo[][] = { {1,2,3} {4,5,6} };
And when you call foo[0] it will actually refer to the first array you added (i.e [1,2,3]) and foo[1] will refer to the second array. You should instead use two seperate arrays called accountNum and accountBal.
Finally you never give values to accNum or origBal which makes your 2D array an empty array. So you could instead dynamically allocate memory for them based on the accounts variable.
Keeping this in mind you should change your main logic to solve these issues.
fscanf(file, "%d", &accounts);
accountNum = malloc(sizeof(int) * accounts);
accountBal = malloc(sizeof(float) * accounts);
for(i = 0; i < accounts; i++) {
fscanf(file, "%d", &accountNum[i]);
fscanf(file, "%f", &accountBal[i]);
printf("Account %d has a balance of $%.2f\n", accountNum[i], accountBal[i]);
}
free(accountBal);
free(accountNum);
Related
I´m getting a "Access violation writing location" error when I run that code. I know that probably is because I´m trying change a const value, but I dont know how correct the code.
OBS: I want create n arrays to storage strings with 25 characters.
#include <stdio.h>
#include <stdlib.h>
int main() {
//variables
int i = 0, n = 0;
//code
scanf("%d\n", &n); //define the number of arrays
char* exp;
exp = (char*)malloc(n * 25); //allocate memory for the string size
for (i = 0; i < n; i++)
{
//takes strings from keyboard
fgets(exp[i], n*25, stdin); //the below error takes place here.
}
//prints the first string taked from stdin
printf("%s", exp[0]);
}
ERROR:
Exception thrown at 0x00007FFBC6EC916F (ucrtbased.dll) in BEE-URI 1022.exe: 0xC0000005: Access violation writing location 0xFFFFFFFFFFFFFFCD.
The first argument expression of this call shall have the type char *, So instead of
fgets(exp[i], n*25, stdin);
you need at least to write
fgets(exp, n*25, stdin);
And the used conversion specifier
printf("%s", exp[0]);
is also incorrect. Either use
printf("%c", exp[0]);
or
printf("%s", exp);
Pay attention to that it is unclear what you are trying to achieve using this for loop
for (i = 0; i < n; i++)
{
fgets(exp, n*25, stdin); //the below error takes place here.
}
Maybe you mean something like the following
char ( *exp )[25];
exp = malloc( n * sizeof( char[25] ) );
for (i = 0; i < n; i++)
{
fgets(exp[i], sizeof( exp[i] ), stdin);
}
// either
// printf( "%s", exp[0] );
// or the loop below
for (i = 0; i < n; i++)
{
printf( "%s", exp[i] );
}
free( exp );
You say you want n arrays of 25 characters each, but what you malloc is one array of n * 25 characters. I think you want something like this:
#include <stdio.h>
#include <stdlib.h>
int main(void) {
int n;
char **exp;
scanf("%d", &n); // get the number of arrays
exp = malloc(n * sizeof *exp); // allocate memory for n string pointers
for (int i = 0; i < n; i++)
exp[i] = malloc(25 * sizeof **exp);
for (int i = 0; i < n; i++)
fgets(exp[i], 25, stdin); // takes strings from keyboard
printf("%s", exp[0]); // print 1st string taken from stdin
}
Note that you should also check the return values from your malloc calls so you know if they succeeded or failed. Same with fgets and scanf.
BTW, remember that a string of 25 characters can only hold 24 characters because you must have room for the terminating null character.
I have an integer array like int a[50];. Now I want to store values entered by the user in the integer array as integers.
The problem is that I don't know the number of elements the user is going to input and hence I am unable to traverse the entire array.
So is there any method for the user to input the values dynamically and store it in the integer array and display it.
For this take a input from user for number of element to have in an array. Then malloc that memory and store the inputs in the array.
You can use realloc and make a specific input as end of the input
int readinput(int *value)
{
int status;
//function returns 0 on conversion -1 if exit keywoard entered
return status;
}
int value, *table = NULL,size = 0;
while (!readinput(&value))
{
table = realloc(table, (size++ + 1) * sizeof(int));
if (table == NULL)
{
break;
}
table[size] = value;
}
example converting function you can find here:
How to get Integer and float input without `scanf()` in c? in my answer
This code should work well, you can change BUFFER_SIZE to whatever you want, after these steps array will realloc to arr size + BUFFER_SIZE.
#include <stdio.h>
#include <stdlib.h>
#define BUFFER_SIZE 50
int main(void)
{
int * userInputBuffer = malloc(sizeof(int) * BUFFER_SIZE);
int userInput;
int counter = 0;
int reallocCounter = 1;
while ((scanf(" %d", &userInput)) == 1)
{
if ((counter % BUFFER_SIZE) == 0)
{
userInputBuffer = realloc(userInputBuffer, (reallocCounter++ + 1) * BUFFER_SIZE * sizeof(int));
}
userInputBuffer[counter++] = userInput;
}
for (int i = 0; i < counter; i++)
{
printf("User input #%d: %d\n", i + 1, userInputBuffer[i]);
}
free(userInputBuffer);
return 0;
}
The following solution uses the scanf() function with %d as format specifier. The while loop checks the return value so that it can detect if the conversion was successful. If anything other than a valid number is inputted the loop will break. A valid number is also beginning with space but not with any other characters.
The memory is allocated with malloc() and will be reallocated with realloc() each time the user entered a number. Note that there is no error checking about the reallocation this should be done with a temporary pointer like here.
Further this code will reallocate for every single number. You could also reallocate in bigger steps to avoid reallocation on every input. But this only matters if there is much data. In this case the speed improvement wouldn't matter.
After the memory is no longer needed you have to use free().
The user can type:
1<Enter>
2<Enter>
3<Enter>
any characters<Enter>
and will get:
Numbers entered:
1 2 3
as output.
Code:
#include <stdio.h>
#include <stdlib.h>
int main (int argc, char *argv[])
{
size_t idx;
int number;
size_t count = 0;
int* numberArr = malloc(sizeof(*numberArr));
printf("Enter each number separated by <Enter>,\n"
"to abort type any other character that isn't a number!\n");
while (scanf("%d", &number) == 1)
{
numberArr = realloc(numberArr, (count + 1) * sizeof(*numberArr));
numberArr[count] = number;
count++;
}
printf("\nNumbers entered:\n");
for (idx = 0; idx < count; idx++)
{
printf("%d ", numberArr[idx]);
}
printf("\n");
free(numberArr);
return 0;
}
I need to write a program that loads data from a file with Hurricane data (like year, name, states affected) The data file looks like this:
1960 Dnna Fl,NC
1972 Agnes FL
1969 Camile MS
The user will be able to select whether the hurricanes are sorted by year or name. The sort function should keep the year list and affected states list parallel with the hurricane names. Allow for a max of 30 hurricanes, but use constant macro for this number to permit easy future expansion of the database.
Here is what they want the output to look like if sorted by years.
Year Name States
1960 Donna FL,NC
1969 Camille MS
1972 Anges FL
I Think i'm not going about this problem right. I just can't figure out how to sort the array and print it. Every time I just try to print the array to make sure it is loaded with the right data, I just get a bunch of junk, or it just crashes.Here is the code that has worked best (if you can call it that)
so far.
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#define Numof_Hurricane 23
char Hurrican_data[Numof_Hurricane][3];
char temp[Numof_Hurricane][3];
int i,j;
char HowSort;
int cmp ( const void *pa, const void *pb ) {
const char (*a)[4] = pa;
const char (*b)[4] = pb;
return strcmp(*a, *b);
}
// start of program
int main()
{
FILE *Hurrican;
Hurrican = fopen("hurricane_data.txt","r"); // the data file for Hurricanes
if (Hurrican==NULL)
{
printf("ERROR: File failed to open\n");
fclose(Hurrican);
}
for(i=0; i<30; i++)
{
for(j=0; j<3; j++)
{
fscanf(Hurrican," %s", &Hurrican_data[i][j]); //loads data into array
}
}
fclose(Hurrican);
printf("How would you like to sort the data?\n"
"(by Year or Name, use Y for year and N for name)"); // ask how user wants to sort it
scanf(" %c", &HowSort);
if (HowSort == 'Y'|| HowSort == 'y') //sort by year
{
printf("\nYou chose to sort by year");
//I plan on adding a function here to sort by year
// my atempt to sort by year
qsort(Hurrican_data, 1, sizeof Hurrican_data[0], cmp );
// To print sorted data
for ( i = 0 ; i < Numof_Hurricane ; i++ )
{
for ( j = 0 ; j < 4 ; j++ )
{
printf( "%s ", Hurrican_data[i][j] );
}
printf("\n");
}
}
else
{
printf("\nYou chose to sort by name");
// I plan to put a function here to sort by Name
}
return 0;
}
Among the things wrong in this code:
Incorrect fclose invoke
if (Hurrican==NULL)
{
printf("ERROR: File failed to open\n");
fclose(Hurrican); /// HERE
}
That fclose makes no sense, and is a recipe for a crash. You just determined the result of the fopen was NULL. Therefore, the file didn't open. Therefore, the file pointer isn't something you can close. There is no reason to continue the program if the file fails to open:
if (Hurrican==NULL)
{
perror("hurricane_data.txt: ");
return EXIT_FAILURE;
}
The array sizes are wrong.
Given that your data looks like this:
1960 Dnna Fl,NC
1972 Agnes FL
1969 Camile MS
and your loader loop tries to read this content into this:
#define Numof_Hurricane 23
char Hurrican_data[Numof_Hurricane][3];
using this loop:
for(i=0; i<30; i++) // HERE: 30??? What about that 23 ??
{
for(j=0; j<3; j++)
{
// HERE: Each of these can be no longer than TWO chars wide.
fscanf(Hurrican," %s", &Hurrican_data[i][j]);
}
}
This assumes there are always exactly 30 items in the file, which the assignments clearly states is possible, but not precise. "Allow for a max of 30 hurricanes..." means there could be thirty, but there could also be one, five, and even none. Really pouring salt on the wound, you're looping to thirty (overflowing buffers along the way, more on that below) on a core array of arrays that is only 23 elements wide. If there were thirty elements, you breach your primary array at the twenty-fourth line.
Further, your loader look is (a) unchecked, and (b) a recipe for buffer overflow on each read. Consider the very first string value on the very first line, 1960. That string is four characters long; five including the terminator, yet you're trying to shove it into a buffer only three characters wide.
Broken Sorting Algorithm
Your sorting loop is sorting the first character of the names. This is wrong.
A Different Approach
The algorithm is simple:
Define a structure, Hurricane, that holds three fields
year - a simple integer
name - a char buffer of reasonable length
states - a char buffer capable of holding a sufficient number of state abbreviations with comma separators.
Your overall data array is a sequence of up to thirty of these structures.
Read the data from the file one complete line at a time. A line length of 256 characters should be sufficient to hold the data.
For each line parse out the year, the name, and the list of strings.
Store these in the structure array as a complete entity.
Use this structure array for sorting operations.
The resulting code would look something like this:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAX_DATA 30
#define MAX_NAME_LEN 64
#define MAX_STATES_LEN 151
struct Hurricane
{
int year;
char name[MAX_NAME_LEN];
char states[MAX_STATES_LEN];
};
struct Hurricane data[MAX_DATA];
void print_data(const struct Hurricane ar[], int size)
{
for (int i=0; i<size; ++i)
printf("%d %s %s\n", ar[i].year, ar[i].name, ar[i].states);
}
void sort_year(struct Hurricane ar[], int size)
{
int swapped = 1;
while (swapped && size--)
{
swapped = 0;
for (int i=0; i<size; ++i)
{
if (ar[i].year > ar[i+1].year)
{
swapped = 1;
struct Hurricane tmp = ar[i];
ar[i] = ar[i+1];
ar[i+1] = tmp;
}
}
}
}
void sort_name(struct Hurricane ar[], int size)
{
int swapped = 1;
while (swapped && size--)
{
swapped = 0;
for (int i=0; i<size; ++i)
{
if (strcmp(ar[i].name, ar[i+1].name) > 0)
{
swapped = 1;
struct Hurricane tmp = ar[i];
ar[i] = ar[i+1];
ar[i+1] = tmp;
}
}
}
}
// start of program
int main()
{
int count=0, i;
char line[256];
char HowSort;
FILE *fp = fopen("hurricane_data.txt","r"); // the data file for Hurricanes
if (fp==NULL)
{
printf("ERROR: File failed to open\n");
fclose(fp);
}
// read until we are full or no more data
for (i=0; (i < MAX_DATA && fgets(line, sizeof(line), fp)); )
{
if (sscanf(line, "%d %63s %150s", &data[i].year, data[i].name, data[i].states) == 3)
++i; // only increment if we got good data
}
// save the number of successful reads.
count = i;
// close the file
fclose(fp);
printf("How would you like to sort the data?\n"
"(by Year or Name, use Y for year and N for name)"); // ask how user wants to sort it
scanf(" %c", &HowSort);
if (HowSort == 'Y'|| HowSort == 'y')
{
printf("\nYou chose to sort by year");
sort_year(data, count);
}
else if (HowSort == 'N' || HowSort == 'n')
{
printf("\nYou chose to sort by year");
sort_name(data, count);
}
print_data(data, count);
return EXIT_SUCCESS;
}
I didn't have the chance to test this, but it is probably very close to what you're trying to to. The sorting algorithm in both cases is a simple bubble sort. For a real-world equivalence we would create appropriate qsort comparison functions and use the standard library, especially if the number of elements was significantly larger than a few dozen. For our purposes here, however, this is sufficient. See the documentation and examples of qsort() here.
Most importantly, note that by using a structure to hold a record rather than splaying it across a sequence of character buffers, you not only get the benefit of proper types (int for the year, for example), you get better data management, and above all, much easier swapping of elements in the sorting routines (structure value swapping ftw).
Anyway, that's what I think you're trying to do.
I am trying to merge a lot of char arrays into a single one. My task is to change float array into a char array to be sent as a line of data via TCP/IP socket, so I thought to use sprintf to print float array values into a char array and then merge those arrays into a single char array, I wrote a little algorithm, but the data does not form into a single line of data and overwrites the last input, what am I doing wrong? Here is the code:
#include <stdio.h>
#include <iostream>
/*
* Mock data loop - a loop where data is created
* String loop - a loop where a single word is merged into a sentance
* Formating loop - a loop where floats are converted into char arrays
!!! - The place where things go wrong (I think)
*/
using namespace std;
int main(){
float data[5]; // Mock data array
char tmp[10]; // Temprorary array, where a word (flaot value) is stored
char text[256]; // String array, where words are stored into a single sentance
int n=5; // Size of mock data
int i, j, k; // Loop counters
// Mock data loop
for (i = 0; i < n; i++){
data[i] = float(i);
printf("Data: %f \n", data[i]);
}
printf("------------------------- \n");
/////////////////////////////////////////////////////////////////////// !!!
for (i = 0; i < 256; i++){ // String loop
for(j = 0; j < n; j++){ // Mock data loop
for (k = 0; k < 10; k++){ // Formating loop
sprintf(tmp, "%f", data[j]);
printf("Sprintf: %s \n", tmp);
text[i + k] = tmp[k];
}
}
printf("Text %d : %s \n", i, text);
i = i + 9;
}
/////////////////////////////////////////////////////////////////////// !!!
printf("------------------------- \n");
printf("Text: %s \n", text);
std::cin.get();
return 0;
}
Appreciate the help, guys!
P.S. I am trying not to use any C++ functions, because I am working with a microcontroller, this code has been written in MS Visual 2013, so I use #include and std::cin.get(); to halt the console and see the results.
As far as I can tell by your code, you're reserving 10 characters in the line for each float value (you do i++, but also i += 9). What if the string representation for the float requires more positions? Your tmp will overflow and your counting will be off.
Here's an attempt that doesn't use 10 positions, but just as many as necessary. On the receiving side you'd have to split by spaces and sscanf() to get the floats back. The code also checks for buffer overflows. I hope that I've understood your question correctly and that this helps...
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main() {
float data[5]; /* Mock data */
char text[256]; /* Line of data */
int i;
/* Build up mock data */
for (i = 0; i < 5; i++)
data[i] = i * 3 + 3.1415729;
/* Stuff int text */
text[0] = 0;
for (i = 0; i < 5; i++) {
char tmp[100]; /* Conversion buffer, should be large enough */
if (snprintf(tmp, sizeof(tmp), "%f ", data[i]) >= sizeof(tmp)) {
fprintf(stderr, "conversion buffer overflow\n");
exit(1);
}
if (strlen(text) + strlen(tmp) >= sizeof(text)) {
fprintf(stderr, "text buffer overflow\n");
exit(1);
}
strcat(text, tmp);
}
printf("Built up text: %s\n", text);
return 0;
}
I am writing a program to split up data entered via command line and put it into separate fields. Right now I am having problems splitting up the data and assigning it to respective pointers. The text file is this:
5, 08:00:00, 2, 60
Where 5 is the patient number, the reading was at 8am, and it is field 2 and he got a 60. I keep getting a segmentation fault error when I run my code, so I put it though gdc and got this, and I think line 88:
*hours = atoi(j);
is messing up:
Welcome to the Health Monitoring System
Program received signal SIGBUS, Bus error.
0x0000000000400826 in get_field ()
This is my code
/*
* Health Monitoring System
*/
#include <stdio.h>
#include <ctype.h>
#define MAXPATIENTS 5
#define MAXREADINGS 10
#define MAXTYPES 5
#define MAXTIME 8
/* One health type reading: timestamp + actual value */
typedef struct{
char timestamp[MAXTIME+1];
int value;
}Element;
/* Circular buffer of health type readings */
typedef struct{
int start; /* index of oldest reading */
int end; /* index of most current reading */
Element reading[MAXREADINGS];
}CircularBuffer;
/* Patient's health chart: ID + multiple health type readings */
typedef struct{
int id;
CircularBuffer buffer[MAXTYPES];
}Chart;
/*
* Health records for all patients defined here.
* The variable record is visible to all functions
* in this file, i.e. it is global.
*/
Chart record[MAXPATIENTS];
void main(){
int i, j;
/* initialize health data records for each patient */
for( i=0; i < MAXPATIENTS; i++ ){
record[i].id = i + 1;
for( j=0; j < MAXTYPES; j++ ){
record[i].buffer[j].start = 0;
record[i].buffer[j].end = 0;
}
}
printf("Welcome to the Health Monitoring System\n\n");
int id;
int hours;
int mins;
int secs;
int field;
int score;
get_field(&id, &hours, &mins, &secs, &field, &score);
printf("%d This is the ID\n", id);
printf("%d This is the hours\n", hours);
printf("%d This is the mins\n", mins);
printf("%d This is the secs\n", secs);
printf("%d This is the field\n", field);
printf("%d This is the score\n", score);
printf("\nEnd of Input\n");
}
int get_field(int* id, int* hours, int* mins, int* secs, int* field, int* score){
//get the patient ID
int z = getchar();
*id = z;
getchar();
getchar();
//this gets the hour
char j[MAXTIME];
int m,n = 0;
while((n=getchar()) != ':'){
j[m] = n;
m++;
}
*hours = atoi(j);
//this gets the mins
char k[MAXTIME];
n = 0;
m = 0;
while((n=getchar()) != ':'){
k[m] = n;
m++;
}
*mins = atoi(k);
// this gets the seconds
char l[MAXTIME];
n = 0;
m = 0;
while((n=getchar()) != ':'){
l[m] = n;
m++;
}
*secs = atoi(l);
getchar();
getchar();
// this gets the field
z = getchar();
*field = z;
getchar();
getchar();
// this gets the score
m = 0;
n = 0;
char x[MAXTIME];
while ((n=getchar()) != '\n'){
x[m] = n;
m++;
}
*score = atoi(x);
return 0;
}
I would use scanf instead of running it manually...
scanf("%d, %d:%d:%d, %d, %d", &field1, &hour, &min, &sec, &field2, &field3);
That would probably clean up some of the problems you are having.
Hope that helps.
The problem is, somewhere in that mess of get_field, you are running into an error you don't need to have. scanf uses what are called format strings, meaning they match to a SPECIFIC format and insert data into their respective fields. This takes the pain away from the parsing you are needlessly doing and makes it a lot easier when you can debug the hard stuff instead of trivial stuff like that.
You're not zero-terminating the strings you're building; atoi() may be reading past the ends of the arrays.
// x will be uninitialized, not necessarily zero-filled
char x[MAXTIME];
while ((n=getchar()) != '\n'){
x[m] = n;
m++;
}
x[m] = '\0'; // make it a valid C string
*score = atoi(x);
All of this assumes that we don't get more than MAXTIME characters.
To avoid that problem:
while ((m < (MAXTIME - 1)) && ((n=getchar()) != '\n')){
You'll have problems with the following lines:
*hours = atoi(j);
*mins = atoi(k);
*secs = atoi(l);
*score = atoi(x);
since you are not terminating the strings with a null character before calling atoi.