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.
Related
I made this function to get input:
void entrada_dados(Time* time, int i){
scanf("%s %d %d", time[i].nome, &time[i].gols_marcados, &time[i].gols_sofridos);
};
The input is in this form:
2
Campinense
23
12
ABC
30
13
The main is:
int main(void) {
int n = 0;
scanf("%d", &n);
for(int i = 0; i < n; i++){
entrada_dados(time, i);
}
....
My problem is when the team name have some space like to "São Paulo". I have tried some forms to solve, but no one solved my problem.
I tried:
void entrada_dados(Time* time, int i){
fscanf(stdin, "%[^\n] %d %d", time[i].nome, &time[i].gols_marcados, &time[i].gols_sofridos);
};
and:
void entrada_dados(Time* time, int i){
fgets(time[i].nome, 100, stdin);
scanf("%d", &time[i].gols_marcados);
scanf("%d", &time[i].gols_sofridos);
}
but in the first case the output have nothing, and second case the output miss some cases. Someone can help me to understand this problem?
Edit 1:
The definition of .name is:
typedef struct Time{
char nome[100];
int gols_marcados;
int gols_sofridos;
} Time;
Edit 2:
Solution:
One way to solve it:
Try two fscanfs fscanf(stdin, " %[^\n]", time[i].nome);
fscanf(stdin, "%d %d", &time[i].gols_marcados, &time[i].gols_sofridos);
Thank you guys.
Because you have to handle strings with spaces, it's better to use fgets for those.
But mixing fgets and scanf doesn't work too well. We can replace scanf with fgets followed by sscanf.
To decode numbers, we can use strtol or sscanf
We take advantage of the fact that each element/member of Time appears on a separate line in the input file, so we can do fgets for every line. This simplifies the code and makes error checking easier.
Here is the refactored code. It is annotated.
I didn't do this, but, if these sequences are done a lot, we can combine some of these sequences in helper functions to reduce some code replication (e.g. a function that combines the fgets followed by the sscanf)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct Time {
char nome[100];
int gols_marcados;
int gols_sofridos;
} Time;
// RETURNS: 1=valid, 0=syntax error
int
entrada_dados(Time *timelist, int i)
{
char buf[100];
char *cp;
Time *tim = &timelist[i];
int valid = 0;
do {
// get name
if (fgets(tim->nome,sizeof(tim->nome),stdin) == NULL)
break;
// strip newline
tim->nome[strcspn(tim->nome,"\n")] = 0;
// get number using strtol
if (fgets(buf,sizeof(buf),stdin) == NULL)
break;
tim->gols_marcados = strtol(buf,&cp,10);
if (*cp != '\n')
break;
// get number using sscanf
if (fgets(buf,sizeof(buf),stdin) == NULL)
break;
if (sscanf(buf,"%d",&tim->gols_sofridos) != 1)
break;
// all input is okay
valid = 1;
} while (0);
return valid;
};
int
main(void)
{
int n = 0;
#if 0
scanf("%d", &n);
#else
char buf[100];
if (fgets(buf,sizeof(buf),stdin) == NULL)
exit(1);
sscanf(buf,"%d",&n);
#endif
// allocate sufficient space
Time *timelist = malloc(sizeof(*timelist) * n);
// read in data
int valid = 0;
for (int i = 0; i < n; i++) {
valid = entrada_dados(timelist, i);
if (! valid)
break;
}
// show the data
if (valid) {
for (int i = 0; i < n; i++) {
Time *tim = &timelist[i];
printf("nome='%s' gols_marcados=%d gols_sofridos=%d\n",
tim->nome,tim->gols_marcados,tim->gols_sofridos);
}
}
return 0;
}
Here is the program input:
3
Campinense
23
12
ABC
30
13
São Paulo
17
82
Here is the program output:
nome='Campinense' gols_marcados=23 gols_sofridos=12
nome='ABC' gols_marcados=30 gols_sofridos=13
nome='São Paulo' gols_marcados=17 gols_sofridos=82
So, I was writing this code for counting the digit frequency i.e. the number of times the digits from 0-9 has appeared in a user inputted string(alphanumeric). So, I took the string, converted into integer and tried to store the frequency in "count" and print it but when I run the code, count is never getting incremented and the output comes all 0s. Would be grateful if anyone points out in which part my logic went wrong.
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
int main() {
// takes string input
char *s;
s = malloc(1024 * sizeof(char));
scanf("%[^\n]", s);
s = realloc(s, strlen(s) + 1);
//turns the string to int
int x = atoi(s);
int temp = x, len = 0;
//calculates string length
while (x != 0) {
x = x / 10;
len++;
}
x = temp;
//parses through the string and matches digits with each number
for (int j = 0; j < 10; j++){
int count = 0;
for(int i = 0; i < len; i++){
if(x % 10 == j){
count++;
}
x = x / 10;
}
x = temp;
printf("%d ", count);
}
return 0;
}
To write a correct and reasonable digit-counting program:
Do not allocate any buffer for this.
Create an array to count the number of times each digit occurs. The array should have ten elements, one for each digit.
Initialize the array to zero in each element.
In a loop, read one character at a time.
Leave the loop when the read routine (such as getchar) indicates end-of-file or a problem, or, if desired, returns a new-line or other character you wish to use as an end-of-input indication.
Inside the loop, check whether the character read is a digit. If the character read is a digit, increment the corresponding element of the array.
After the loop, execute a new loop to iterate through the digits.
Inside that loop, for each digit, print the count from the array element for that digit.
Your approach is way to complicated for a very easy task. This will do:
void numberOfDigits(const char *s, int hist[10]) {
while(*s) {
if(isdigit(*s))
hist[*s - '0']++;
s++;
}
}
It can be used like this:
int main(void) {
char buf[1024];
int hist[10];
fgets(buf, sizeof buf, stdin);
numberOfDigits(s, hist);
for(int i=0; i<10; i++)
printf("Digit %d occurs %d times\n", i, hist[i]);
}
This can also be quite easily achieved without a buffer if desired:
int ch;
int hist[10];
while((ch = getchar()) != EOF) {
if(isdigit(ch))
hist[ch - '0']++;
}
#include <stdio.h>
int main(void) {
int input = 1223330;
int freq[10] = {0};
input = abs(input);
while(input)
{
freq[input%10]++;
input /= 10;
}
for(int i=0; i<10; ++i)
{
printf("%d: %.*s\n", i, freq[i], "*************************************************");
}
return 0;
}
Output:
Success #stdin #stdout 0s 5668KB
0: *
1: *
2: **
3: ***
4:
5:
6:
7:
8:
9:
This app is currently limited by the size of an int (approximately 9 or 10 digits).
You can update it to use a long long easily, which will get you to about 19 digits.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int Extract(char input[], double output[])
{
int i, j, len;
i=0;
j=0;
len=0;
char s[50];
while(i<strlen(input)-1)
{
if(input[i]==' ') i++;
j=0;
s[0]='\0';
while(input[i]!=',')
{
if(input[i]==' ') i++;
s[j]=input[i];
i++;
j++;
}
s[j]='\0';
i++;
printf("%s - ", s);
output[len]=(double)atof(s);
printf("Element %d: %lf\n", len, output[len]);
len++;
}
printf("%d", len);
return len;
}
int main(){
char s[120]="0.1,0.35,0.05,0.1,0.15,0.05,0.2.";
double v[1000];
int len = Extract(s, v);
int i;
for(i=0; i<len; i++)
{
printf("%d: %lf\n", i, v[i]);
}
return 1;
}
I try to run this code but even if it compiles correctly I have stack errors, can anybody help me?
Note that the string is composed by some decimal numbers separated by commas and the string ends with a .
UPDATE: maybe there was some dirty in the folder but now I have an output:
Length: 32
0.1 - Element 0: 0.000000
0.35 - Element 1: 0.000000
0.05 - Element 2: 0.000000
0.1 - Element 3: 0.000000
0.15 - Element 4: 0.000000
0.05 - Element 5: 0.000000
Segmentation fault (core dumped)
Since I already made the thread can I still take advantage of your help for converting the string into double, since atof is converting into float and probably that's the reason why it prints all 0.0000?
I think I found the problem:
Your loop only check if the character is not ','. At the end of your input, you do not have a ',' character, instead you have a '.' which will lead to your loop going on forever, resulting in the segfault. You can fix it by changing the last character of your input into a ','.
You do not have the right format for your float output. If you need to only print two significant figures, then change your %lf into %.2lf.
By the way, you check for spaces in your input, but it doesn't look like your input has any spaces. Maybe take those checks out?
It all depends on how regulated your input is. If you can, process your input before you feed it into your function.
Let us know if that helps!
Here I am presenting 3 codes, where the first addresses the segfault issue(s); the second, a verbose commentary on the Extract function as presented; third, an example of the Extract function written in one of many possible improved forms.
The main take-aways should be to always guard against buffer (array) overruns in code and make friends with the debugger.
The peppering of printf's in the code suggests a debugger is not being used. Coding anything beyond the trivial (hello, world?) begs debugger knowledge. Understanding tools such as a debugger is as important as knowing the language.
I Hope this serves as a guide and maybe even some inspiration. Good luck with your coding adventures.
Here's the original code with minimum changes to fix the segfault (array overrun)
int Extract(char input[], double output[])
{
int i, j, len;
i = 0;
j = 0;
len = 0;
char s[50];
while (i<strlen(input) - 1)
{
if (input[i] == ' ') i++;
j = 0;
s[0] = '\0';
/* Primary bug fix; guard against input array overrun *and* check for separator */
while (input[i] && input[i] != ',')
{
if (input[i] == ' ') i++;
s[j] = input[i];
i++;
j++;
}
s[j] = '\0';
/* bug fix; guard against input array overrun when incrementing */
if (input[i]) {
i++;
}
printf("%s - ", s);
output[len] = (double)atof(s);
printf("Element %d: %lf\n", len, output[len]);
len++;
}
printf("%d", len);
return len;
}
Here's a critique of the original code.
int Extract(char input[], double output[])
{
/* Tedious variable declaration and initialization */
int i, j, len;
i = 0;
j = 0;
len = 0;
/* why not 70? or 420? */
char s[50];
/* This is an exceedingly expensive way to determine end of string. */
while (i<strlen(input) - 1)
{
/* Why test for space? There are no spaces in sample input.
This increment risks overrunning the input array (segfault)
*/
if (input[i] == ' ') i++;
j = 0;
s[0] = '\0';
/* no guard against input array overrun */
while (input[i] != ',')
{
/* Why test for space? There are no spaces in sample input.
This increment risks overrunning the input array (segfault)
*/
if (input[i] == ' ') i++;
s[j] = input[i];
i++;
j++;
}
s[j] = '\0';
/* Bug - no guard against input array overrun when incrementing i */
i++;
/* these print statements suggest someone is NOT using a debugger - major fail if so. */
printf("%s - ", s);
output[len] = (double)atof(s);
printf("Element %d: %lf\n", len, output[len]);
len++;
}
/* again, this is easily seen in the debugger. Use the debugger. */
printf("%d", len);
return len;
}
Lastly, an alternative Extract with some (cherry picked) conventions.
int Extract(double* output, const int output_max, const char* input, const char separator)
{
/* declare variables in the scope they're needed and ALWAYS give variables meaningful names */
int input_index = 0, output_count = 0;
/* Detect end of string and guard against overrunning output buffer */
while (input[input_index] && output_count < output_max)
{
const int BUFFER_MAX = 50;
/* let the compiler init buffer to 0 */
char buffer[BUFFER_MAX] = { 0 };
int buffer_index = 0;
/* accumulate values into buffer until separator or end of string encountered */
while (input[input_index] && input[input_index] != separator)
{
buffer[buffer_index++] = input[input_index++];
if (buffer_index == BUFFER_MAX) {
/* Overrun, cannot process input; exit with error code. */
return -1;
}
}
/* only convert buffer if it had accumulated values */
if (buffer_index) {
/* note atof will discard, say, a trailing period */
output[output_count++] = atof(buffer);
}
/* Guard against input_index increment causing an array overrun (possible segfault) */
if (input[input_index]) {
input_index++;
}
}
return output_count;
}
int main() {
const int OUTPUT_MAX = 1000;
const char separator = ',';
const char* input = "0.1 ,0.35,0.05,0.1,0.15,0.05,0.2.";
double output[OUTPUT_MAX];
const int num_elems = Extract(output, OUTPUT_MAX, input, separator);
/* print results to stdout */
if (num_elems == -1) {
fprintf(stdout, "\nElement too long to process error\n");
}
else {
fprintf(stdout, "\nTotal number of elements: %d\n\n", num_elems);
for (int i = 0; i < num_elems; i++) {
fprintf(stdout, "Element %d: %lf\n", i, output[i]);
}
}
return num_elems;
}
Good luck with your coding adventures.
I am new to programming so this is difficult for me. I need the program to end if the user's first input is -999, if not then they go on to input the account_num, last_name, and balance. But if the user enters -999 after the first input then it ends their input and displays the results. I cannot figure out how to get this whole -999 part to work while making my client[x].account_num be sorted in ascending order.. My code is below.
#include <stdio.h>
void bubble_sort(int[], int);
struct information
{
int account_num;
char last_name[30];
float balance;
};
int main()
{
/* declare variables */
struct information client[5];
int i, x, temp;
char c;
/* Prompt user */
printf ("Enter account number, last name, and balance.\n");
printf ("Enter -999 to end input:\n\n");
/* prompt user to enter number of people */
x = 0;
while (client[x].account_num != -999)
{
int tmp;
scanf ("%i", &tmp);
/* if types -999 as their first input program ends */
if (tmp == -999)
{
break;
}
else if (tmp < 1 || tmp > 1000)
{
printf ("*** Invalid account number. Please enter 1 - 1000 or -999 to exit ***\n");
}
else
{
client[x].account_num = tmp;
x ++;
}
bubble_sort(client[x].account_num, i);
scanf("%s", client[x].last_name);
while ( (c = getchar() != '\n') && c != EOF); /* clear input buffer. */
scanf("%.2f", &client[x].balance);
}
for (x = 0; x < 5; x++)
printf("%i\n", &client[x].account_num);
return 0;
}
void bubble_sort(int list[], int i)
{
int e, d, t;
for (e = 0; e < (i - 1); e++)
{
for (d = 0; d < i - e - 1; d++)
{
if (list[d] > list[d + 1])
{
/* swapping */
t = list[d];
list[d] = list[d + 1];
list[d + 1] = t;
}/* end for*/
}/*end for*/
}/* end for */
}/* end function */
There are several issues here. First, you don't want to index account_num and balance in the struct, unless you want to have several account numbers and balances per account holder. I also suggest replacing the for with a while loop so you don't have to fiddle with the loop counter x in case the user enters an invalid account number. Finally, for the sake of clarity I introduced a temporary variable tmpfor input and performed all tests on it, assigning the content to the account structure only if all validity tests were passed. tmpis only needed inside the whileloop which is why I declared it there, instead of making it part of the declarations in main().
#include <stdio.h>
#define MAX_CLIENTS 5
#define MAX_ACCOUNTS 1000
struct information
{
int account_num;
char last_name[30];
float balance;
};
int main()
{
/* declare variables */
struct information client[MAX_CLIENTS];
int i, x, people;
char c;
/* Prompt user */
printf ("Enter account number, last name, and balance.\n");
printf ("Enter -999 to end input:\n\n");
/* prompt user to enter number of people */
x = 0;
while (x < MAX_CLIENTS)
{
int tmp;
scanf ("%i", &tmp);
/* if types -999 as their first input program ends */
if (tmp == -999)
{
break;
}
else if (tmp < 1 || tmp > MAX_ACCOUNTS)
{
printf ("*** Invalid account number. Please enter 1 - %d or -999 to exit ***\n", MAX_ACCOUNTS);
}
else
{
client[x].account_num = tmp;
x ++;
}
}
return 0;
}
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;
}