Improper reading of file in C - c

I am doing a socket programming for hospital chanelling.
I am trying to read a text file like this
1 Kavi card 0 0 0
2 Anparasanesan gene 0 0 0
3 Thilak card 0 0 0
4 Akilanesan immu 0 0 0
5 Aravinthanesan derm 0 0 0
6 Akalya derm 0 0 0
7 Vishvapriya derm 0 0 0
8 Kavinga immu 0 0 0
9 Anjalie andr 0 0 0
10 Tom andr 0 0 0
but when i am reading that file it gives me the output as :
1 Kavi cardgenecardimmudermdermdermimmuandrandr
2 Anparasanesan genecardimmudermdermdermimmuandrandr
3 Thilak cardimmudermdermdermimmuandrandr
4 Akilanesan immudermdermdermimmuandrandr
5 Aravinthanesan dermdermdermimmuandrandr
6 Akalya dermdermimmuandrandr
7 Vishvapriya dermimmuandrandr
8 Kavinga immuandrandr
9 Anjalie andrandr
10 Tom andr
Here is my code segment
char line[MAXCHAR];
int x = 0;
while (fgets(line, sizeof(line), fp)){
sscanf(line,"%d\t%s\t%s\t%d\t%d\t%d",&dno,&dname,&dspl,&ti1,&ti2,&ti3);
id[x]=dno;
strncpy(name[x], dname, 50);
strncpy(spl[x], dspl, 4);
times[x][0]=ti1;
times[x][1]=ti2;
times[x][2]=ti3;
x++;
}
int z=0;
for(z=0;z<10;z++)
{
snprintf(line, sizeof(line),"%d\t%s\t%s\n",id[z],name[z],spl[z]);
n = strlen(line);
Writen(sockfd,line,n);
}

Let us look at one of the problems.
evil strncpy
Code is using strncpy with a magic number 4. This does not insure spl[x] is a string as the characters may lack a final null character.
strncpy(spl[x], dspl, 4); // Avoid code like this
Later code tries to print a string with "%s" and spl[z] and gets "cardgene..." rather than the expected "card". When spl[z] is not a string, the result is undefined behavior (UB) - anything may happen.
// Alternative: could limit output with
snprintf(line, sizeof(line),"%.*s\n",(int) (sizeof spl[z]), spl[z]);
How to fix?
Do not use sscanf(line,"%s",&dspl); as it lacks either a width limit, or it is not known that dspl is about the same size of line. I'd expect
char dspl[4+1];
sscanf(line,"%4s", dspl);
Better to insure the source string and destination array are sufficient than use strncpy() without tests.
char spl[X_N][4+1];
char dspl[sizeof spl[0]];
// strncpy(spl[x], dspl, 4);
strcpy(spl[x], dspl);
Others fixes include make certain the sscanf() completed as expected. A simple approach uses " %n" to record the scan offset, if it got that far and then look for extra garbage. Unnecessary "\t" removed.
// Insure dname is at least 50+1, dspl is 4+1 or as big as the line
char dname[sizeof line];
char dspl[sizeof line];
// sscanf(line,"%d\t%s\t%s\t%d\t%d\t%d",&dno,&dname,&dspl,&ti1,&ti2,&ti3);
int n = 0;
sscanf(line,"%d%50s%4s%d%d%d %n",&dno,dname,dspl,&ti1,&ti2,&ti3, &n);
if (n==0 || line[n]) {
puts("Bad Input"); // Handle bad input in some fashion
exit(RETURN_FAILURE);
}

Related

Why isn't my use of ncurses alternative charset working properly?

I'm trying to write a program that generates a crossword grid, so I'm using the ncurses library because I just need a simple interface to display the grid, the problem is when I use box() function with ACS_VLINE and ACS_HLINE, it doesn't work; it writes 'q' and 'x' instead of the box lines. It worked at the beginning but suddenly it stopped working; I don't know why.
I'm simply initializing ncurses with initscr() and noecho().
Here's the part of the code where I draw the box:
int crossword(char ***grid, WINDOW **win, WINDOW ****c, int x, int y)
{
int i;
int j;
int ch;
t_word_list *wrdlist;
clear();
(void)x;
(void)y;
if (!(wrdlist = get_words("data/words.list")))
return (-1);
box(*win, ACS_VLINE, ACS_HLINE);
i = -1;
while ((*c)[++i])
{
j = -1;
while ((*c)[i][++j])
mvwaddch((*c)[i][j], 0, 0, (*grid)[i][j]);
}
wrefresh(stdscr);
while ((ch = getch()))
if (ch == 27)
{
nodelay(stdscr, TRUE);
ch = getch();
nodelay(stdscr, FALSE);
if (ch < 0)
break ;
}
return (endwin());
}
Output:
lqqqqqqqqqqqqqqqqqqqqqk
x 0 0 0 0 0 0 0 0 0 0 x
x 0 0 0 0 0 0 0 0 0 0 x
x 0 0 0 0 0 0 0 0 0 0 x
x 0 0 0 0 0 0 0 0 0 0 x
x 0 0 0 0 0 0 0 0 0 0 x
x 0 0 0 0 0 0 0 0 0 0 x
x 0 0 0 0 0 0 0 0 0 0 x
x 0 0 0 0 0 0 0 0 0 0 x
x 0 0 0 0 0 0 0 0 0 0 x
x 0 0 0 0 0 0 0 0 0 0 x
mqqqqqqqqqqqqqqqqqqqqqj
EDIT: I recreated the problem with minimal code:
#include <curses.h>
int main(void)
{
WINDOW *win;
initscr();
win = subwin(stdscr, 10, 10, 1, 1);
box(win, ACS_VLINE, ACS_HLINE);
wrefresh(stdscr);
getch();
return (0);
}
Output:
lqqqqqqqqk
x x
x x
x x
x x
x x
x x
x x
x x
mqqqqqqqqj
The flags I use for compilation: gcc main.c -lcurses
Converting parts of comments into an answer.
What did you change between when it worked and when it stopped working? … Can you recreate the steps you would have used while creating the working version in a new MCVE (Minimal, Complete, Verifiable Example
— or MRE or whatever name SO now uses)
or an
SSCCE (Short, Self-Contained, Correct Example).
This would allow you to find out what breaks the working code with the bare minimum of code?
… I just edited my atoi function that I just use in the main for the sizeX and sizeY; I didn't touch anything else and it suddenly stopped working. I tried to undo what I did after it wasn't working and it still doesn't work.
So you changed something else as well, whether or not you realized it. It's possible that the terminal settings are screwed up — funnier things have been known. Have you tried creating a new terminal window and trying again in the new window?
Oh yes! It was the terminal! It worked after a 'reset', thank you! I don't know why I didn't think about that earlier.
Until curses (ncurses) programs have proved themselves reliable, always consider the possibility that a flawed version of the program under test messed up the terminal settings. Use stty -g to generate a string when the terminal is working properly (when first created, before you run your program). You can then use that string to reset the terminal to the same known state (assuming it is stty settings that are the problem). Sometimes, a new terminal window is necessary even so.
good_stty=$(stty -g)
…testing program under development…
stty "$good_stty"
Sometimes, you may need to type control-J and then stty "$good_stty" (or stty sane) and another control-J because the line ending settings have been modified and not restored correctly.
The problem may be the console encoding for your console. Also if you access from putty you must follow the following steps.
Verif console configuration is UTF
dpkg-reconfigure console-setup

C Writing into file stop working after use it as function?

I wrote a function that sets every number of a line in a .txt file to zero and clears the other file.
I originally wrote this logic in main and it worked perfectly fine. But now I need to make a menu for my program, so I need to put this logic into a function.
That's where the things go wrong. Once I move the logic into a function, it doesn't set the numbers to zero, it just clears the file, and I didn't changed anything.
Expected result:
Workers.txt : Adam Washington Monday Friday --(use function)--> {clear}
days.txt: 1 0 0 0 1 0 0 --(use function)--> 0 0 0 0 0 0 0
Actual result:
It's clear in both files.
void ResetOwnData(){
printf("--------------------------------------------------------------------------\n");
FILE* freset = fopen ("workers.txt", "w");
close(freset);
FILE* freset2 = fopen ("days.txt", "w");
for(int i = 0; i < 7; i++){
fprintf(freset2,"%d ",i+1);
}
fprintf(freset2,"\n");
for(int i = 0; i < 7; i++){
fprintf(freset2,"%d ",0);
}
close(freset2);
printf("Everything get reset!\n");
printf("--------------------------------------------------------------------------\n");
}
There are two main things that appear to be incorrect.
You are using close rather than fclose. fclose is used with file streams (like you are using)
Your function is overwriting the one line that you want (e.g., 0 0 0 0 0 0 0) with two lines because you have two for loops
Here is a CodingGround link to the corrections that I believe you are seeking.
You should add some error checking to ensure that you truly have opened the file and that you release any allocated memory

VLA works on gcc-4.9.2 but not on gcc-6.2.0

A very simple code to test VLA on gcc works fine on gcc-4.2.9 (Raspbian), but not on gcc-6.2.0 (Ubuntu). I am surprised. Though it compile without error, the output is not proper.
Code:
int len, i;
int test[len];
scanf("%d",&len);
for(i=0;i<=len;i++){
test[i]=i*i;
printf("%d\t",test[i]);}
printf("\n");
return 0;
Argument:
8
Output:
With 4.2.9 (Raspbian),
0 1 4 9 16 25 36 49 64
With 6.2.0 (Ubuntu),
0 1 4 9 16 1
It doesn't even reach to the count of 8. I am surprised. The same code works if I hard code the value of len.
0 1 4 9 16 25 36 49 64
Any idea about what is possibly going wrong?
int len, i;
int test[len];
You're doing test[len], but at this point len hasn't been initialized. Reading from an uninitialized variable has undefined behavior.
To fix this, initialize len before using it:
if (scanf("%d",&len) != 1) {
// handle error
}
int test[len];
And in the rest of your code, use i<len instead of i<=len because otherwise you'd access len+1 elements where only len exist.

MPI IO - MPI_FIle_seek - How to calculate correct offset size for shared file

Update. Now the junk is removed from the end of the shared file, but ther is still som "junk" in the middle of the file where process 0 ends writing and process 1 starts writing:
10 4 16 16 0 2 2 3 1 3 4 2 4 5 1 0 4 6 2 8 5 3 8 10 4 9 5 4 ^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#^#10 4 16 16 1 2 6 0 3 5 2 2 2 8 1 5 6 5 6 6 4 8 9 7 6 2 1 3 6 4 10 2 5 7 7 6 10 6 5 9 9 10 6 7 5 8
However if i count the the jiberish, i get to 40. When i try to do;
offset = (length-40)*my_rank;
It works, but it is not a very scalable and robust solution. Therfor i need to compute this number for a more generell solution. Does anybody see how can be done, here is my current function:
#define MAX_BUFF 50
int write_parallel(Context *context, int num_procs, int my_rank, MPI_Status status){
int written_chars = 0;
int written_chars_accumulator = 0;
int n = context->n;
void * charbuffer = malloc(n*MAX_BUFF);
if (charbuffer == NULL) {
exit(1);
}
MPI_File file;
MPI_Offset offset;
MPI_File_open(MPI_COMM_WORLD,"test_write.txt",
MPI_MODE_CREATE|MPI_MODE_WRONLY,
MPI_INFO_NULL, &file);
written_chars = snprintf((char *)charbuffer, n*MAX_BUFF, "%d %d %d %d\n", n, context->BOX_SIDE, context->MAX_X, context->MAX_Y);
if (written_chars < 0){ exit(1); }
written_chars_accumulator += written_chars;
int i,j;
for(i=0;i<n;i++){
if(context->allNBfrom[i]>0){
written_chars = snprintf((char *)charbuffer+written_chars_accumulator, (n*MAX_BUFF - written_chars_accumulator), "%d %d %d ", i, context->x[i], context->y[i]);
if (written_chars < 0){ exit(1); }
written_chars_accumulator += written_chars;
for(j=0;j<context->allNBfrom[i];j++){
written_chars = snprintf((char *)charbuffer+written_chars_accumulator, (n*MAX_BUFF - written_chars_accumulator), "%d ", context->delaunayEdges[i][j]);
if (written_chars < 0){ exit(1); }
written_chars_accumulator += written_chars;
}
written_chars = snprintf((char *)charbuffer+written_chars_accumulator, (n*MAX_BUFF - written_chars_accumulator), "\n");
if (written_chars < 0){ exit(1); }
written_chars_accumulator += written_chars;
}
}
int length = strlen((char*)charbuffer);
offset = (length-40)*my_rank; //Why is this correct? the constant = 40 needs to be computet in some way...
//printf("proc=%d:\n%s",my_rank,charbuffer);
MPI_File_seek(file,offset,MPI_SEEK_SET);
MPI_File_write(file,charbuffer,length,MPI_CHAR,&status);
MPI_File_close(&file);
return 0;
}
Her is my current result, with this solution which is also correct: 10 4 16 16 0 2 2 3 1 3 4 2 4 5 1 0 4 6 2 8 5 3 8 10 4 9 5 4 10 4 16 16 1 2 6 0 3 5 2 2 2 8 1 5 6 5 6 6 4 8 9 7 6 2 1 3 6 4 10 2 5 7 7 6 10 6 5 9 9 10 6 7 5 8
But it will not scale because, I dont know how to compute number of jiberish elemtens. Does anybody have a clue ?
If I understand your code your goal is to remove the NULL-chars in between your text blocks. In this parallel writing approach there is no way to solve this without violating the safe boundaries of your buffers. None of the threads now how long the output of the other threads is going to be in advance. This makes it hard (/impossible) to have dynamic ranges for the write offset.
If you shift your offset then you will be writing in a aria not reserved for that thread and the program could overwrite data.
In my opinion there are two solutions to your problem of removing the nulls from the file:
Write separate files and concatenate them after the program is finished.
Post-process your output-file with a program that reads/copy chars form your output-file and skips NULL-bytes (and saves the result as a new file).
offset = (length-40)*my_rank; //Why is this correct? the constant = 40 needs to be computet in some way...
The way you compute this is with MPI_Scan. As others have pondered, you need to know how much data each process will contribute.
I'm pretty sure I've answered this before. Adapted to your code, where each process has computed a 'length' of some string:
length = strlen(charbuffer);
MPI_Scan(&length, &new_offset, 1, MPI_LONG_LONG_INT,
MPI_SUM, MPI_COMM_WORLD);
new_offset -=length; /* MPI_Scan is inclusive, but that
also means it has a defined value on rank 0 */
MPI_File_write_at_all(fh, new_offset, charbuffer, length, MPI_CHAR, &status);
The important feature of MPI_Scan is that it runs through your ranks and applies an operation (in this case, SUM) over all the preceding ranks. Afte r the call, Rank 0 is itself. Rank 1 holds the sum of itself and rank 0; rank 2 holds the sum of itself, rank 1 and rank 0... and so on.

how do I generate set of all tokens of length exactly equal to 8

I need to generate complete set of tokens of size exactly equal to 8.Each bit in the token can assume values from 0 - 9 and A -Z. For example-
The following are valid tokens:
00000000
0000000A
000000H1
Z00000XA
So basically i want to generate all tokens from 00000000 to ZZZZZZZZ.
How do i do this in C
You caught me on a day where I don't want to do what I'm supposed to be doing1.
The code below only generates token output; it doesn't attempt to store tokens anywhere. You can redirect the output to a file, but as others have pointed out, you're going to need a bigger boat hard drive to store 368 strings. There's probably a way to do this without the nested loops, but this method is pretty straightforward. The first loop updates the counter in each position, while the second maps the counter to a symbol and writes the symbol to standard output.
You can set LEN to a smaller value like 3 to verify that the program does what you want without generating terabytes of output. Alternately, you could use a smaller set of characters for your digits. Ideally, both LEN and digs should be command-line parameters rather than constants, but I've already spent too much time on this.
Edit
Okay, I lied. Apparently I haven't spent too much time on this, because I've cleaned up a minor bug (the first string isn't displayed correctly because I was doing the update before the display) and I've made the length and character set command-line inputs.
Note that this code assumes C99.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define DEFAULT_LEN 8
int main( int argc, char **argv )
{
const char *default_digs="0123456789ABCDEFGHIJKLMNOPQRSTUVWXYZ";
size_t len = DEFAULT_LEN;
const char *digs = default_digs;
if ( argc > 2 )
digs = argv[2];
if ( argc > 1 )
len = strtoul( argv[1], NULL, 10 );
int idx[len];
memset( idx, 0, sizeof idx );
size_t diglen = strlen( digs );
for(;;)
{
int j = len;
while( j )
putchar( digs[idx[--j]] );
putchar( '\n' );
while ( j < len && idx[j] == diglen - 1 )
idx[j++] = 0;
if ( j == len )
break;
idx[j]++;
}
return 0;
}
Sample output:
[fbgo448#n9dvap997]~/prototypes/tokgen: ./tokgen 2 01
00
01
10
11
[fbgo448#n9dvap997]~/prototypes/tokgen: ./tokgen 3 01
000
001
010
011
100
101
110
111
[fbgo448#n9dvap997]~/prototypes/tokgen: ./tokgen 2 012
00
01
02
10
11
12
20
21
22
1. Which, to be fair, is pretty much any day ending in a 'y'.
You don't need recursion or a nested loop here at all.
You just need a counter from 0 through 368-1, followed by converting the results to an output in base 36.
That said, 368 strings, each with a length of 8 bytes is 22,568,879,259,648 bytes, or approximately 20.5 terabytes of data.
Assuming a sustained rate of 100 megabytes per second, it'll take approximately 63 hours to write all that data to some hard drives.

Resources