I have to read from a txt file these lines:
1 334.5909245845 161.7809319139
2 397.6446634067 262.8165330708
3 503.8741827107 172.8741151168
4 444.0479403502 384.6491809647
5 311.6137146746 2.0091699828
6 662.8551011379 549.2301263653
7 40.0979030612 187.2375430791
From here I have to extract the second and third values of each line because they're the coordinates for my cities.
My piece of code is the following one (I will show only the part where the program has to read the values):
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <time.h>
#include <stdlib.h>
#include <ctype.h>
#include <stdlib.h>
struct city {
double x;
double y;
};
int main(int argc, const char *argv[])
{
FILE *f;
f = fopen(argv[1], "r");
if (f == NULL)
{
printf("cannot read file or inexistant file.\n");
return 1;
}
char lines[2000][150];
int i = 0;
int j = 0;
int c = 0;
// read file's lines
while (c != EOF)
{
while ((c = getc(f)) != EOF && c != '\n')
{
lines[i][j] = c;
j++;
}
lines[i][j] = '\n';
i++;
j = 0;
}
strcpy(lines[i - 2], "\n");
struct city * cities = malloc(sizeof(double) * 10 + 1);
if (cities == NULL)
{
printf("cannot allocate memory");
return 1;
}
int counter = 0;
for (int y = 0; strcmp(lines[y], "\n") != 0; y++)
{
// don't need this check
if (isdigit(lines[y][0]))
{
char * tok;
struct city *new_city = malloc(sizeof(struct city));
if (new_city == NULL)
{
printf("cannot allocate memory");
free(cities);
return 1;
}
//read first number, not used
tok = strtok(lines[y], " ");
//read coordinate x
tok = strtok(NULL, " ");
printf("tok1: %s\n", tok);
new_city -> x = atof(tok);
//read coordinate y
tok = strtok(NULL, " ");
printf("tok2: %s\n", tok);
new_city -> y = atof(tok);
printf("inserted: %lf\n", new_city -> y);
cities[counter] = *new_city;
counter++;
}
}
fclose(f);
Simply I open the file, read char by char all lines, and then I use strtok() to take the coordinates written (second and third numbers of each line). The problem is that I have to store them into x and y of my city struct, and as I read here atof() must be used, but it approximate the number and then it return segmentation fault, as I printed here (inserted is city->y that is approximated but it is wrong, while tok1 and tok2 are the two correct strings read form the file):
tok1: 334.5909245845
tok2: 161.7809319139
inserted: 161.780932
tok1: 397.6446634067
tok2: 262.8165330708
inserted: 262.816533
tok1: 503.8741827107
tok2: 172.8741151168
inserted: 172.874115
tok1: 444.0479403502
tok2: 384.6491809647
zsh: segmentation fault ./Travelling_salesman_problem ch130.tsp
As you can see comparing the inserted value and tok2, inserted is approximated and then the code breaks. There is a way without changing the code but only the atof() function to have the precise value (because the rest of the code works)?
So many problems.
It is unclear why all the lines are read into char lines[][]; first and then parsed. It makes more sense to read 1 line, parse it into the data structure and then read the next line, etc. Then only one line buffer needed.
Yet assuming there is need to read the entire file first, some code to fix input:
// Avoid naked magic numbers
// char lines[2000][150];
#define LINES_N 2000
#define LINE_SIZE 150
char lines[LINES_N][LINE_SIZE];
int i = 0; // Maybe line_count instead?
int j = 0; // Maybe ch_index instead?
int c = 0; // Good use of int here.
// Append a '\0' at the end to form a _string_.
// Use 1 while loop
// Do not iterate to far, add limits tests
// read file's lines
while (i < LINES_N && (c = getc(f)) != EOF) {
if (j < LINE_SIZE) {
lines[i][j] = c;
j++;
} else {
fprintf(stderr, "Line %d too long\n", i);
}
if (c == '\n') {
lines[i][j] = '\0';
i++;
j = 0;
}
}
// Might as well close the file now, not later.
fclose(f); // and remove later one.
// lines[i - 2] is very bad if i < 2
//strcpy(lines[i - 2], "\n");
// I think all you want here is
// strcpy(lines[i], "\n");
// Since you have `i`, later iterate to `i`,
// no need for strcpy(lines[i], "\n")
//
// for (int y = 0; strcmp(lines[y], "\n") != 0; y++)
for (int y = 0; y < i; y++)
If helpful, later I'll look over the rest.
Related
I want to get from user multiple line strings.
How I can do that?
User doesn’t know beforehand how many “paragraphs” wants.
User Input (example_1):
Hello! (clicks Enter button)
World! (clicks Enter button)
(clicks Enter button)
Output:
Hello!
World!
User Input (example_2):
(clicks Enter button)
Output:
(nothing)
There are some notes here:
1. You could have used getline() function instead of scanning characters one by one.
2. Assuming that for now we want to use scanf, you might not now the paragraph's length beforehand, so its better to use a linked list of lines in which you allocate memory dynamically. Here is a working example:
#include <stdio.h>
#include <stdlib.h>
typedef struct _line{
char * chars_in_line;
struct _line * next_line;
}line;
void fill_paragraph_lines(line * first_line , int max_size){
first_line->chars_in_line = (char *)malloc(max_size * sizeof(char));
first_line->next_line = NULL;
line * current_line = first_line;
int i;
char aux = '\0';
while(1){
for(i = 0 ; i < max_size ; i++){
if(aux == '\0'){
printf("enter a character: ");
scanf(" %c" , &aux);
}
// if the received character is not '\n' put that in line
if(aux != '\n'){
current_line->chars_in_line[i] = aux;
aux = '\0';
}
// if you receive \n as an input character, set the ending \0 and break from for loop
else{
current_line->chars_in_line[i] = '\0';
aux = '\0';
break;
}
// reset aux character to its initial value
aux = '\0';
// if you reach max_size also end the string with '\0', no matter what character you received from user
if(i == max_size - 1){
current_line->chars_in_line[i] = '\0';
printf("\nmax line characters reached\n");
aux = '\0';
}
}
// the user can end a paragraph by inputting \n, when previous line is completed
char possible_paragraph_ending;
printf("enter a character: ");
scanf(" %c" , &aux);
if(aux == '\n')
return;
// if the user inputs another character, start a new line
line * new_line = (line*)malloc(sizeof(line));
new_line -> chars_in_line = (char *)malloc(max_size * sizeof(char));
new_line ->next_line = NULL ;
// chain the new line to the previous lines and move the pointer current line to the
// newly created line
current_line->next_line = new_line;
current_line = new_line;
}
}
void destroy_paragraph(line * first_line){
if(first_line == NULL)
return ;
line * traverse_line = (line *)first_line->next_line;
line * dealloc_line = first_line;
while(1){
free(dealloc_line->chars_in_line);
free(dealloc_line);
if(traverse_line == NULL)
return;
dealloc_line = traverse_line;
traverse_line = dealloc_line->next_line;
}
}
void print_paragraph(line * first_line){
line * traverse_line = first_line;
while(traverse_line != NULL){
printf("%s\n" , traverse_line->chars_in_line);
traverse_line = traverse_line->next_line;
}
}
int main() {
line * first_line = (line *)malloc(sizeof(line));
fill_paragraph_lines(first_line , 10) ;
print_paragraph(first_line);
destroy_paragraph(first_line);
return 0 ;
}
In the code above, you need to hit enter after each character in a line. If you want to end a line, you have to press Return 2 times consecutively and you need to press Return 3 times to end a paragraph.
When a new line needs to be generated, memory is dynamically allocated. destroy_paragraph() needs to be called to free memory.
This code does what you are expected to do. I simplified the signature of the function get_string (not sure if the signature you provided was required or not). To the function we pass the array paragraphs (for proof of concept I am using an array with 300 positions, however if you should use malloc and realloc to adjust the size as needed) and the number of strings read in the function.
NOTE: Updated code to count words per paragraph in array as requested by OP.
#include <stdio.h>
#include <string.h>
void get_string(char *paragraphs, int *n) {
char aux[30], i = 0, parg_cur_length = 0;
do{
fgets(aux, sizeof(aux), stdin);
if(aux[0] == '\n')
break;
for(i=0; i< strlen(aux); i++){
paragraphs[parg_cur_length + i] = aux[i];
}
parg_cur_length += strlen(aux);
paragraphs[parg_cur_length] = '\0';
parg_cur_length++;
(*n)++;
}while(aux[0] != '\n');
}
int main()
{
char paragraphs[300];
char * iter_paragraphs = paragraphs;
int n_times = 0, n_chars = 0;
get_string(paragraphs, &n_times);
// let's print what we have
for(int i = 0; i< n_times; i++) {
n_chars = printf("%s", iter_paragraphs);
iter_paragraphs += n_chars+1;
}
// reset pointer
iter_paragraphs = ¶graphs[0];
// let's counts the words per paragraph
int j = 0, word_cnt = 0;
for(int i = 0; i< n_times; i++) {
while(*(iter_paragraphs + j) != '\0') {
if( *(iter_paragraphs + j) == ' ')
word_cnt++;
j++;
}
// assuming last word does not have space but \n instead
n_chars = printf("paragraph %d has %d words\n", i+1, word_cnt+1);
word_cnt = 0;
// move to next pos in array due to \0
j++;
}
}
Nevertheless, IMO a cleaner approach for this would be to use a matrix (char **) as user3121023 suggested.
I have a textfile of numbers written in words, with spaces between like..
zero three five two one .. etc there are 3018 words in total.
This is my code:
#include <stdio.h>
int main(void)
{
int i = 0;
int d = 0;
int j = 0;
char array[9054][5];
char hi[9054];
FILE *in_file;
in_file = fopen("message.txt", "r");
while (!feof(in_file))
{
fscanf(in_file, "%s", array[i]);
i++;
}
printf(array[9049]);
while (1);
return 0;
}
so the 9049th worth in my textfile is the number three.. but when I run this script, it prints "threethreezero"instead?? i thought the fscanf ignored whitespace (spaces) so why does accept another three and zero into this string?
OP figured things out with the help of comments, so here is a cumulative fix.
#include <stdio.h>
int main(void)
{
int i = 0;
int d = 0;
int j = 0;
// Make room for the null character
char array[9054][5+1];
char hi[9054];
FILE *in_file;
in_file = fopen("message.txt", "r");
//check `fscanf()`'s return value rather than using feof()
// Limit input put with 5
while (fscanf(in_file, "%5s", array[i]) == 1);
i++;
}
// Check that code read enough input
if (i >= 9049) {
// Do not use `printf()` on uncontrolled strings that may contain %
fputs(array[9049], stdout);
} else {
puts("Oops");
}
while (1);
return 0;
}
Can any one explain to me how to make a C program to read input from a file according to the following scenario:
12
2-4,7,9;
1,4,11-12;
1,4,10,12;
1,4-8,10-12;
1,8;
1,3-6,8,10-12;
1,3,5-6,8,11;
1,8,10-12;
1-8;
;
2;
2-4,7-10,12;
The first number (on the first line) describes what size the grid should be, in this case a 12x12 grid. The following lines describe how many cells are occupied on each row of the grid. For example, in the first row the cells from 2 to 4 and 7 and 9 are occupied; in the second row, the cells 1, 4 and from 11 to 12 are occupied and so on.
Right now I have this code, but it is not solving my problem ...
#include <stdio.h>
#include <stdlib.h>
void main()
{
char content[3000];
int value;
FILE *ptr_file = fopen("data.txt", "r");
if(!ptr_file)
return 1;
int j;
while(fgets(content, 3000, ptr_file)!=NULL){
printf("%s", content);
value = atoi(content);
for(j=0; j<3000; j++){
value = content[j];
printf("%i", value);
}
}
return 0;
}
Console throws just a bunch of random numbers ...
Pseudo-code:
Open your file
Read the first line
Extract the value N
Allocate your grid
Loop N times
Read a line
If not an empty line, ie. semi-colon only
Split into tokens by comma
Check for a range or a single digit
Extract numbers
Set cells accordingly
The "random" numbers are the byte values from your file and you forgot to stop at end of line.
Dave's solution is not quite right for c.
After read a line:
while not semicolon
strtoul a number
if no number
exit error
if next char is hyphen
shift to next char
strtoul end of range
if no number
exit error
set cells
else
set cell
if next char is not semicolon
shift to next char
You should not use atoi for anything ever. Use sscanf or strto….
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <ctype.h>
enum { EOD = -1, EOL = -2, ERR = -3, OFF = 0, ON = 1 };//End Of Data, End Of Line
int getValue(FILE *fp){
static int on_yield = OFF, prev, end;
if(on_yield == ON && prev < end){
return ++prev;
}
on_yield = OFF;
int n, ch = fgetc(fp);
if(ch == EOF)
return EOD;
else if(ch == ';')
return EOL;
else if(ch == ',' || ch == '\n')
return getValue(fp);//or change to using loop
else if(isdigit(ch)){
ungetc(ch, fp);
fscanf(fp, "%d", &n);
return prev=n;
} else if(ch == '-'){
on_yield = ON;
fscanf(fp, "%d", &n);
end = n;
return getValue(fp);
}
fprintf(stderr, "(%c) invalid format in file\n", ch);
return ERR;
}
int main(void){
FILE *ptr_file = fopen("data.txt", "r");
if(!ptr_file){
perror("fopen");
return 1;
}
int size;
fscanf(ptr_file, "%d", &size);//check omitted
char (*cell)[size] = malloc(size * sizeof(*cell));
memset(&cell[0][0], ' ', size*size);
int r = 0, c, value;
while((value=getValue(ptr_file))!=EOD){
if(value == EOL){
++r;
continue;
}
if(value > 0)
cell[r][value-1] = '*';
}
fclose(ptr_file);
for(r = 0; r < size; ++r){
for(c = 0; c < size; ++c){
putchar(cell[r][c]);
}
putchar('\n');
}
free(cell);
return 0;
}
I've been having some problems with this code below...
The main idea of the code is to read line by line and convert chars strings into floats and save the floats in a array called nfloat.
The input is a .txt containing this: n = the number of strings, in this case n = 3
3
[9.3,1.2,87.9]
[1.0,1.0]
[0.0,0.0,1.0]
The first number, 3 is the number of vectors as we can see in the image, but that number isn't static, the input can be 5 or 7, etc instead of 3.
So far, I've started doing the following, (for only 1 vector case) but the code has some memory errors I think:
int main(){
int n; //number of string, comes in the input
scanf("%d\n", &n);
char *line = NULL;
size_t len = 0;
ssize_t read;
read = getline(&line,&len,stdin); //here the program assigns memory for the 1st string
int numsvector = NumsVector(line, read);//calculate the amount of numbers in the strng
float nfloat[numsvector];
int i;
for (i = 0; i < numsvector; ++i)
{
if(numsvector == 1){
sscanf(line, "[%f]", &nfloat[i]);
}
else if(numsvector == 2){
if(i == 0) {
sscanf(line, "[%f,", &nfloat[i]);
printf("%f ", nfloat[i]);
}
else if(i == (numsvector-1)){
sscanf((line+1), "%f]", &nfloat[i]);
printf("%f\n", nfloat[i]);
}
}
else { //Here is where I think the problems are
if(i == 0) {
sscanf(line, "[%f,", &nfloat[i]);
printf("%f\n", nfloat[i]);
}
else if(i == (numsvector-1)) {
sscanf((line+1+(4*i)), "%f]", &nfloat[i]);
printf("%f\n", nfloat[i]);
}
else {
sscanf((line+1+(4*i)), "%f,", &nfloat[i]);
printf("%f\n", nfloat[i]);
}
}
}
Well, the problems come with the sscanf instructions I think, in the case of a string with two floats or one, the code works fine but in the case of 3 or more floats, the code doesn't work well and I can't understand why...
Here I attach the function too, but It seems to be correct... the focus of the problem remains on the main.
int NumsVector(char *linea, ssize_t size){
int numsvector = 1; //minimum value = 1
int n;
for(n = 2; n<= size; n++){
if (linea[n] != '[' && linea[n] != ']'){
if(linea[n] == 44){
numsvector = numsvector + 1;
}
}
}
return numsvector;
}
Please could someone help me understand where is the problem?
Ok - if you replace your current for loop with this, your nfloat array should end up with the right numbers in it.
/* Replaces the end ] with a , */
line[strlen(line) - 1] = ',';
/* creates a new pointer, pointing after the first [ in the original string */
char *p = line + 1;
do
{
/* grabs up to the next comma as a float */
sscanf(p, "%f,", &nfloat[i]);
/* prints the float it's just grabbed to 2 dp */
printf("%.2f\n",nfloat[i]);
/* moves pointer forward to next comma */
while (*(p++) != ',');
}
while (++i < numsvector); /* stops when you've got the expected number */
I have written a small program which takes input of a file such as:
13,22,13,14,31,22, 3, 1,12,10
11, 4,23, 7, 5, 1, 9,33,11,10
40,19,17,23, 2,43,35,21, 4,34
30,25,16,12,11, 9,87,45, 3, 1
1,2,3,4,5,6,7,8,9,10
and outputs the largest sum of numbers on each line that is less than 50.
However if the inputted file has a trailing newline character the loop runs one too many times and hence another line is added to the array with random data. So I'm looking for a better way to do this comparison to avoid this issue. I'm also assuming all lines have 10 integers on at the moment as i cannot think of a better way to do the end of line loop comparison.
#include <stdio.h>
#include <stdlib.h>
void readLineData(int lineNo, int val[][10], FILE *fp);
int findSum(int lineNo, int val[][10], FILE *fp);
int main(int argc, char *argv[]) {
FILE *fp;
int val[5][10];
// Open file.
if ((fp = fopen(argv[1], "r")) == NULL)
{
perror("Cannot open file ");
exit(EXIT_FAILURE);
}
for (int i = 0; !feof(fp); i++) // runs too many times if file ends with '\n'
{
readLineData(i, val, fp);
printf("%d\n", findSum(i, val, fp));
}
fclose(fp);
return EXIT_SUCCESS;
}
void readLineData(int lineNo, int val[][10], FILE *fp) {
char c;
for (int i = 0; i < 10; i++) // assuming line contains 10 integers
{
fscanf(fp, "%d,", &val[lineNo][i]);
}
}
int findSum(int lineNo, int val[][10], FILE *fp) {
int highVal = 0;
int value1 = 0;
int value2 = 0;
for(int i = 0; i < 10; i++) //each letter
{
for(int j = 0; j < 10; j++)// every other letter
{
if((val[lineNo][i] + val[lineNo][j]) > highVal && i != j && (val[lineNo][i] + val[lineNo][j]) <= 50)
{
highVal = val[lineNo][i] + val[lineNo][j];
value1 = val[lineNo][i];
value2 = val[lineNo][j];
}
}
}
printf("Line %d: largest pair is %d and %d, with a total of: ", lineNo+1, value1, value2);
return highVal;
}
any help with those loop comparisons and general notation tips is most welcome.
Thanks
The posted code does not distinguish between two lines that have five integers and (the expected) one line that has 10 integers. Suggest reading in a line at a time, using fgets() and then using sscanf() on the read line to ensure that all the read integers belong to the same line.
Check the return value of input operations. For example, sscanf() (and fscanf()) return the number of assignments made. Only process lines that have the expected 10 integers, which would detect invalid lines including the trailing empty line.
For example:
/* Returns 1 on success and 0 on failure. */
int readLineData(int lineNo, int val[][10], FILE *fp)
{
char line[1024]; /* Arbitrarily large. */
if (fgets(line, sizeof(line), fp))
{
/* %n records position where processing ended. */
int pos;
const int result = sscanf(line,
"%d,%d,%d,%d,%d,%d,%d,%d,%d,%d%n",
&val[lineNo][0],
&val[lineNo][1],
&val[lineNo][2],
&val[lineNo][3],
&val[lineNo][4],
&val[lineNo][5],
&val[lineNo][6],
&val[lineNo][7],
&val[lineNo][8],
&val[lineNo][9],
&pos);
/* 10 integers and full line processed,
except if new-line character present. */
return 10 == result &&
(pos == strlen(line) ||
(pos + 1 == strlen(line) && '\n' == line[pos]));
}
return 0;
}
You could simply consume the newline character yourself:
for (int i = 0; !feof(fp); i++) // runs too many times if file ends with '\n'
{
readLineData(i, val, fp);
printf("%d\n", findSum(i, val, fp));
fscanf(fp, "%*c"); // read a character without storing it in a variable
}
Note that there are undoubtedly better ways that involve reading an entire line at once and simply examining its contents; but this is the easiest way that will fit with what you already have.
you could check if fscanf fails in your readLineData function:
int readLineData(int lineNo, int val[][10], FILE *fp) {
for (int i = 0; i < 10; i++) {// assuming line contains 10 integers
if (fscanf(fp, "%d,", &val[lineNo][i]) != 1) {
return 1;
}
}
return 0;
}