C Bubble Sort Integer Array - Output Issue - c

Newbie Here.
For my C programming class, I'm required to use bubble sort to sort a list that's read from an input .txt file. Each line on the .txt file has a year, name, and states affected by a hurricane [year] [name] [states].
Ex:
1999 Floyd NC
2003 Isabel NC, VA
2004 Charley FL, SC, NC
2004 Frances FL
...etc.
The program needs to sort the list by year while keeping all the data lines correct (keep the relative array elements together). My integer array bubble sort works fine except for one issue- one line of data is off to the side of the list. Here's an example output of this issue:
1960 Donna FL, NC
1969 Camille MS 1972 Agnes FL
1983 Alicia TX
2004 Charley FL, SC, NC
The 1972 Agnes FL line is almost correct, but for some reason prints off to the side rather than right under the previous line.
Code:
#include <stdio.h>
#include <string.h>
#define MAX_HURCS 30
int main() {
FILE *hurricaneData;
int year[MAX_HURCS];
char name[MAX_HURCS][50];
char states[MAX_HURCS][50];
int i = 0, j;
int count = 0;
int sort;
int tempYear;
char tempName[50];
char tempStates[50];
if ((hurricaneData = fopen("hurricanes2.txt", "r")) == NULL) {
printf("Error: Could not open file");
}
while ((fscanf(hurricaneData, "%d %s", &year[i], &name[i]) != EOF)
&& (fgets(states[i], 50, hurricaneData) != NULL)) {
i++;
count++;
}
for (i = 0; i < count - 1; i++) {
for (j = 0; j < count - 1 - i; j++) {
if (year[j] > year[j + 1]) {
tempYear = year[j];
year[j] = year[j+1];
year[j+1] = tempYear;
strcpy(tempName, name[j]);
strcpy(name[j], name[j+1]);
strcpy(name[j+1], tempName);
strcpy(tempStates, states[j]);
strcpy(states[j], states[j+1]);
strcpy(states[j+1], tempStates);
}
}
}
for (i = 0; i < count; i++) {
printf(" \t%d\t%s\t%s ", year[i], name[i], states[i]);
}
return 0;
}
I've also tried this for the sorting algorithm, but I come across this same issue:
for (i = 0; i < count; i++) {
for (j = 0; j < count; j++) {
if (year[j] > year[i]) {
tempYear = year[i];
year[i] = year[j];
year[j] = tempYear;
strcpy(tempName, name[i]);
strcpy(name[i], name[j]);
strcpy(name[j], tempName);
strcpy(tempStates, states[i]);
strcpy(states[i], states[j]);
strcpy(states[j], tempStates);
}
}
}

I think the error is that your last line in your file does not have a end of line character so it reads upto end of file and when it print the same line it does not move to next line so either go to last line in your text file and put a endl in the last line or print a endl manually for each line. Another or more generic way would be to remove new line from your input, that can be done like this, while reading text do this
int len = strlen(states[i]);
if(len>0 && states[i][len-1] == '\n')
{
states[i][len-1] = '\0';
}
this will remove all new line and then you can print them manually in printf

Related

Reading CSV into C Struct

I'm trying to read a CSV into a struct in C. I need to read in an item name, its weight and its value. They are listed straight through in the CSV i.g (name, name, name, ..., weight, weight, ..., value, value, ..).
#include <stdio.h>
typedef struct {
char name[25];
double weight;
double value;
} Item;
int main() {
// Open data.csv
FILE *packingList;
packingList = fopen("data.csv", "r");
// Check for proper file Opening
if (packingList == NULL) {
printf("File did not open correctly.\n");
return 1; // Signal error
}
// Declare array of items to store data
Item items[100];
for (int i = 0; i < 3; i++)
{
fscanf(packingList,
"%24[^,]",
items[i].name);
printf("| %s | ", items[i].name);
}
fclose(packingList);
return 0;
}
csv
MRE1,MRE2,MRE3,MRE4,PolyPro,HygieneKit,PoopyWipes,Gloves,ExtraSocks1,ExtraSocks2,ExtraSocks3,Snacks,JetBoil,Ammo1,Ammo2,M16,SleepingBag,BivvySack,GoreTex,E-Tool,Canteens,FlakJacket,FrontSAPIPlate,BackSAPIPlate,WarBelt,Compass,NVG,Bayonet,Diary,Iodine,Knife,Lamp,Nameplate,Ointment,Quiver,Radio,Toothbrush,Utensils,Vitamins,X-acto Knife,Yellow safety belt,Zinc-oxide
2.125,2,1.875,2,1.5,2.5,0.5,0.5,0.25,0.25,0.25,1.5,1,3,3.75,7,5,2.5,2.5,3,4.25,3,8.25,8,3.5,1.125,1.125,5,0.75,0.375,0.875,1.125,0.25,0.875,3.75,7.625,0.375,0.25,0.125,3.75,2.125,4.625
12,10,8,6,10,5,6.5,4.5,9,6,2,1.5,5,15,100,80,35,22,18,12,18,30,50,25,12,50,3,86,50,6,9,5,1,8,7,20,5,2,1,5,2,6
The code I'm running only reads in the first first 3 items as a test, but only properly gets the first item name, the other 2 come out as weird characters. How would I go about writing this to properly read the CSV and attach the appropriate weight and values to each item?
My Output
| MRE1 | | $5�� | | �¤ |
Consider reading the 3 lines using fgets() and then parse the lines. Unless 3 lines read, no point in parsing.
Then parse the 3 lines, one at a time or as a group, as shown below.
This sample code uses "%n" to detect the offset of the scan, if it got that far. Notice that the ',' is in the format.
Other code could use strtod(), strcspn(), strtok(), for parsing.
#define ITEM_N 100
#define NAME_SIZE 25
// Scale the max lines size in some fashion.
// I recommend 2x the maximum expected size.
#define LINE_SIZE ((ITEM_N * NAME_SIZE + 3)*2)
char lines[3][LINE_SIZE];
char *s[3];
int i;
for (i = 0; i < 3; i++) {
if (fgets(lines[i], sizeof lines[i], packingList) == NULL) {
break;
}
s[i] = lines[i];
}
if (i == 3) {
Item items[ITEM_N];
size_t index;
for (index = 0; index < ITEM_N; index++) {
int n = 0;
sscanf(s[0], "%24[^,]%*[,\n]%n", items[index].name, &n);
if (n == 0) break;
s[0] += n;
n = 0;
sscanf(s[1], "%lf%*[,\n]%n", &items[index].weight, &n);
if (n == 0) break;
s[1] += n;
// likewise for .value (not shown)
}
// Code can now use `index` items.
}

Not able to print this 2D array (weird output) in C

I am trying to read a text file with 100 numbers like 1 2 45 55 100 text file here (all on a single line) and then put them in a 10x10 array (2D array).
736.2 731.6 829.8 875.8 568.3 292.2 231.1 868.9 66.7 811.9 292.0 967.6 419.3 578.1 322.5 471.7 980.0 378.8 784.1 116.8 900.4 355.3 645.7 603.6 409.1 652.1 144.1 590.6 953.1 954.0 502.0 689.3 685.6 331.9 565.1 253.9 624.1 796.2 122.8 690.7 608.0 414.8 658.3 27.3 992.9 980.8 499.0 972.8 359.7 283.1 89.7 260.1 638.4 735.4 863.6 47.5 387.5 7.7 638.1 340.6 961.7 140.1 29.8 647.3 471.9 594.9 901.2 96.0 391.1 24.0 786.7 999.1 438.7 445.0 26.4 431.6 425.9 525.4 404.4 785.6 808.5 494.1 45.7 447.0 229.5 909.3 494.4 617.0 917.0 132.5 957.5 878.8 272.6 987.4 526.1 744.5 582.3 427.3 840.5 973.3
Here is my code:
#include <stdio.h>
#define NR 10
#define NC 10
int main(void) {
int numbers[9][9];
int i = 0;
int count;
int j = 0;
FILE *file;
file = fopen("numbers.txt", "r");
for (count = 1; count < 101; count++) {
fscanf(file, "%d", &numbers[i][j]);
j++;
if ((count != 1) && (count % 10 == 0)) {
i++;
j = 0;
}
}
fclose(file);
int p = 0;
int q = 0;
for (p = 0; p < NR; p++) {
for (q = 0; q < NC; q++) {
printf("%d", numbers[p][q]);
}
printf("\n");
}
return 0;
}
As SparKot noted in a comment, to read a 10x10 matrix, you need to define the matrix with 10x10 elements:
int numbers[10][10];
That has to be one of the weirder ways of reading a 10x10 matrix that I've ever seen. Why not go for a simple approach of nested loops. Since the data contains floating-point numbers, you need to read them as double (or perhaps float) values.
for (int i = 0; i < 10; i++)
{
for (int j = 0; j < 10; j++)
{
double double_val;
if (fscanf(file, "%lf", &double_val) != 1)
{
fprintf(stderr, "failed to read matrix[i][j]\n", i, j);
exit(EXIT_FAILURE);
}
numbers[i][j] = double_val;
}
}
The mess with double_val works around the data containing floating point numbers and your original code trying to read integers. You'll get one valid value; thereafter, fscanf() will return 0 because the . is not a part of a valid integer. This highlights the importance of checking the return value from fscanf() and its relatives.
Frankly, you should be using double numbers[10][10]; for the data from the file. Then you could read directly into the array:
if (fscanf("%lf", &numbers[i][j]) != 1)
But you'd need to check (and probably change) all the rest of the code too.
There are multiple issues in your code:
the matrix is too small, make it numbers[NR][NC].
you do not check for fopen failure: you will have undefined behavior if the file numbers.txt is not in the current directory or cannot be open for reading.
you read the file contents as integers, but the file contains floating point numbers with a . decimal separator: the second and subsequent fscanf() will get stuck on the . and keep returning 0 without modifying the destination number, leaving the matrix mostly uninitialized. Make the matrix double numbers[NR][NC], read the numbers with %lf and test for conversion failure.
the counting method in the reading loop is weird. Just use 2 nested for loops with proper counter and tests.
printing the matrix contents, you should output at least a space between numbers so the output is readable.
Here is a modified version:
#include <errno.h>
#include <stdio.h>
#include <string.h>
#define NR 10
#define NC 10
int main() {
double numbers[NR][NC];
FILE *file;
file = fopen("numbers.txt", "r");
if (file == NULL) {
fprintf(stderr, "cannot open numbers.txt: %s\n", strerror(errno));
return 1;
}
for (int i = 0; i < NR; i++) {
for (int j = 0; j < NC; j++) {
if (fscanf(file, "%lf", &numbers[i][j]) != 1) {
fprintf(stderr, "error reading number at row %d, col %d\n",
i + 1, j + 1);
fclose(file);
return 1;
}
}
}
fclose(file);
for (int p = 0; p < NR; p++) {
for (int q = 0; q < NC; q++) {
printf(" %5g", numbers[p][q]);
}
printf("\n");
}
return 0;
}
Clear all a common condition that causes programs to crash; they are often associated with a file named core.
code is showing segmentation fault.

How to store a number string in a file as a seperate integer in an array in C

I have 32 bits as a text file in Sender.txt like
00100100101110001111111100000001
I want to store each individual number as an integer in the array. I have tried the following code but not working.
#include <stdio.h>
#include<stdlib.h>
void main()
{
FILE *myfile;
myfile = fopen("Sender.txt" , "r");
char data[32];
int i,con, data1[32];
for(i=0;i<32;i++)
{
fscanf(myfile, "%1s", &data[i]);
}
for(i=0;i<32;i++)
{
con = atoi(data[i]);
data1[i]=con;
}
for(i=0;i<32;i++)
{
printf("%d \n", &data1[i]);
}
}
Still without fully understanding the purpose of your endeavor, I suggest to rewrite the first two loops:
for(i = 0; i < 32; i++)
{
int next = fgetc(myfile);
data1[i] = (next == '0') : 0 ? 1;
}
This code assumes that the file has 32 1's or 0's, all on the same line, and nothing else.
This could be further compressed, possibly at the expense of clarity:
for(i = 0; i < 32; i++)
{
data1[i] = fgetc(myfile) - '0';
}
Why don't you use fgetc ? This function reads only one Charakter and returns it.
Your code should then look like this:This one got errors see EDIT
FILE *file;
char c[32];
for(int i = 0; i < 32; i++){
if((c[i] = fgetc(file)) == NULL)
//then Error
}
fclose(file);
EDIT: As rightly pointed out by "alk" (what a name mate xD) The if clause makes no sense at all. It was to early in the morning i apologize. The right code should of course look like this:
FILE *file;
int data[32]; //The Question was to store the Data in an int not char like i did...
for(int i = 0; i < 32; i++)
data[i] = fgetc(file) - '0';
fclose(file);
Best regards

How can I merge N files

I have N files, in each lines of every file there are unique words and the word count, for example
file1 file2 file3
the 2 black 3 red 4
apple 4 tree 2 crab 6
snake 3 mantle 8 puppet 1
How can I merge these files in sorted order into a one file, thanks in advance, really need an idea.
void *doMerge(void* arg){
int i,j,p = 0, k = 0;
char*min = malloc(sizeof(char)*256);
FILE *f = fopen("fileFinal","w+");
char **StringBuffer = (char **)malloc(sizeof(char*)*R);
int *IntBuffer = malloc(sizeof(int)*R);
for(i=0; i < R; i++){
rewind(temp2[i]);
StringBuffer[i] = (char *)malloc(sizeof(char)*256);
if(fscanf(temp2[i],"%s %d",StringBuffer[i],&IntBuffer[i]) == 1)
printf("String is %s and int is %d\n",StringBuffer[i],IntBuffer[i]);
}
while(1){
strcpy(min, StringBuffer[0]);
for(j=0 ; j < R-1; j++){
if(strcmp(StringBuffer[j+1],StringBuffer[j]) <= 0){
strcpy(min,StringBuffer[j+1]);
p = j+1;
}
}fprintf(f,"%s %d\n",min, p);
if(fscanf(temp2[p],"%s %d",StringBuffer[p],&IntBuffer[p]) == 1){}
k++;
}
};
while(1)
{
strcpy(min, StringBuffer[0]);
for(j=0 ; j < R-1; j++){
if(strcmp(StringBuffer[j+1],StringBuffer[j]) <= 0)
{
strcpy(min,StringBuffer[j+1]);
p = j+1;
}
}
fprintf(f,"%s %d\n",min, p);
if(fscanf(temp2[p],"%s %d",StringBuffer[p],&IntBuffer[p]) == 1)
{}
k++;
}
That while loop has a number of different problems
1) p needs to be initialized to 0 before the for loop
2) the strcmp should compare min to StringBuffer[j], which also means that
2a) the for loop should be for(j=1;j<R;j++), and
2b) strcpy(min,StringBuffer[j+1]); should be strcpy(min,StringBuffer[j]);, and
2c) the line p=j+1 should be p=j
3) k is not used for anything and should be removed
But the most important thing is the fscanf. You should be checking that fscanf returns 2. If not then the file is done, and you need to keep track of the fact that the file is done, and that file should not be checked in the for loop any more.

C - Nested for loops not printing multiple elements

My nested loops only print one char, 'c', which is the correct first char to print, but I cannot figure out why my loop won't keep looping through the alphabet. Any assistance in determining my loop error would be great.
#include <stdio.h>
#include <stdlib.h>
void problem_1_function();
int main(){
problem_1_function();
return (0);
}
void problem_1_function(){
FILE *the_cipher_file;
the_cipher_file = fopen("cipher.txt", "r");
FILE *the_message_file;
the_message_file = fopen("message.txt", "r");
FILE * the_decode_file;
the_decode_file = fopen("decode.txt", "w");
int the_letter_counter = 0;
int the_alphabet_array[100];
int size_of_alphabet = 0;
int size_of_message = 0;
int the_message_counter = 0;
int the_message_array[100];
char the_decode_array [15];
char the_letter_char[26] = {'a','b','c','d','e','f','g','h','i','j','k','l','m','n','o','p','q','r','s','t','u','w','x','y','z'};
if(the_decode_file == NULL){
printf("Error opening file!\n");
}
if(!the_cipher_file){
printf("Error: Filename \"cipher.txt\" not found!\n");
}
while(fscanf(the_cipher_file, " %d%*[,] ", &size_of_alphabet) > 0 && the_letter_counter < 100){
the_alphabet_array[the_letter_counter] = size_of_alphabet;
//printf("%d ", size_of_alphabet);
the_letter_counter++;
}
if(!the_message_file){
printf("Error: Filename \"cipher.txt\" not found!\n");
}
while(fscanf(the_message_file, " %d%*[,] ", &size_of_message) > 0 && the_message_counter < 100){
the_message_array[the_message_counter] = size_of_message;
//printf("%d ", size_of_message);
the_message_counter++;
}
int message_equals_cipher = 0;
int message_equals_cipher2 = 0;
for(message_equals_cipher; message_equals_cipher < sizeof(the_message_array); message_equals_cipher++){ //these nested loops go through the alphabet to print letters corresponding to arrays...
for(message_equals_cipher2; message_equals_cipher2 < 26; message_equals_cipher2++){
if(the_message_array[message_equals_cipher] == the_alphabet_array[message_equals_cipher2]){
the_decode_array[message_equals_cipher] = the_letter_char[message_equals_cipher2];
fprintf(the_decode_file, "%c", the_decode_array[message_equals_cipher]);
}
}
}
fclose(the_cipher_file);
fclose(the_message_file);
fclose(the_decode_file);
}
int message_equals_cipher = 0;
int message_equals_cipher2 = 0;
for(message_equals_cipher; ...
for(message_equals_cipher2; ...
You're setting these to 0 outside the loops .. the initialization expressions of your for statements don't do anything -- if you set your warning level high enough, your compiler should tell you that. Because you don't reset message_equals_cipher2, your inner loop will only run once total. You want
for(message_equals_cipher = 0; ...
for(message_equals_cipher2 = 0; ...
If you are compiling C99 or higher, you can do
for(int message_equals_cipher = 0; ...
for(int message_equals_cipher2 = 0; ...
and get rid of the previous definitions of those variables.
Yes, the problem in your nested for loop is that you are not initializing your message_equals_cipher2 variable to 0 in your second for loop.
The nested code should be like :
for(message_equals_cipher; message_equals_cipher < sizeof(the_message_array); message_equals_cipher++)
{
for(message_equals_cipher2=0; message_equals_cipher2 < 26; message_equals_cipher2++)
{
// Your stuff
}
}
I will agree with jim, instead of initializing your variables message_equals_cipher and message_equals_cipher2 before nested for loops. You can do it as jim specified.

Resources