I have this function that communicates with a tcp server
char write_buffer[128];
char read_buffer[128];
char hint_status[4];
char Fsize[10];
FILE *score;
char lnk[1024];
int Fsize_max = 1024*1024*1024;
int hint(){
if (connect(tcpfd, tcpres->ai_addr, tcpres->ai_addrlen) < 0) {
printf("\n Error : Connect Failed \n");
return 0;
}
sprintf(write_buffer,"GHL %s\n",PLID);
n=write(tcpfd, write_buffer,strlen(write_buffer));
n=read(tcpfd, read_buffer, 128);
sscanf(read_buffer, "%s %s %s %s %s\n", message_type, hint_status, Fname, Fsize, lnk);
if(strcmp(hint_status, "NOK") == 0){
return 0;
};
if (atoi(Fsize) > Fsize_max){
printf("size_overflow\n");
return 0;
}
score = fopen(Fname, "w+");
fwrite(lnk, 1, sizeof(lnk), score);
fclose(score);
return 0;
}
That sends information to the server and in return is supposed to receive "RHL status [Fname Fsize Fdata]" in what status is to check if the it return a file or not, and
the filename Fname (it comes in .PNG or .JPG)
the file size Fsize, in bytes;
the contents of the selected file (Fdata).
I am supposed to receive RHL OK something.PGN 99123(for example) data and I am receiving RHL OK 5 12 or some times segmentation fault.
I know I am doing something wrong but I am not surely what.
Does any body have a clue on what is wrong with it?
Does any body have a clue on what is wrong with it?
Yes
Missing null character
n=write(tcpfd, write_buffer,strlen(write_buffer)); does not write a string as no null character is sent.
Consider
n=write(tcpfd, write_buffer,strlen(write_buffer) + 1);
sscanf(read_buffer... expects a string, yet read_buffer[] is not certainly null character terminated.
Use return value n to examine read_buffer[] and determine and append a '\0' as needed.
Candidate problem: no width
Without widths, code risks buffer overflow and undefined behavior (UB).
char Fsize[10]; cannot save as text, Fsize_max, or "1073741824", which needs size 11.
Use widths to prevent buffer overflow.
Use better scan checking
// sscanf(read_buffer, "%s %s %s %s %s\n",
// message_type, hint_status, Fname, Fsize, lnk);
char message_type[10]; // True size is unknown as not posted by OP.
char Fname[100]; // True size is unknown as not posted by OP.
int n = 0;
sscanf(read_buffer, "%9s %3s %99s %9s %1023s %n",
message_type, hint_status, Fname, Fsize, lnk, &n);
if (n == 0 || read_buffer[n]) {
TBD_CODE_Handle_Error():
}
For error checking, do not assume text in int range.
// if (atoi(Fsize) > Fsize_max){
if (atoll(Fsize) > Fsize_max){
Related
so Im writing a code to get scanf a text file and return a format text message log. I'm stuck wondering how to scan strings from file at a certain point and print every string beyond that point E.X When the file scans the line
"332982000 2055552002 2055551001 7 Mr Webb, can I ask you a question?" I scan the first 4 numbers as integers and scan the rest of the written text into an char array starting at "Mr. Webb".
I tried using a for loop with fscanf to scan into an array but it didnt work. I was also thinking I could use malloc just to save space but I dont know what to put in the sizeof argument. Any help would be GREATLY appreciated!
int posix;
int phone1;
int phone2;
int textsize;
int val, val2;
char line[256];
char text[3000];
int len=strlen(line);
int i=0;
printf("\n\nTime %s %s", argv[2], argv[3]);
printf("\n======================================================================================\n\n\n");
FILE* textfile= fopen(argv[1],"r");
fscanf(textfile, "%d %d %d %d %s", &posix, &phone1, &phone2, &textsize, text);
while( fgets(line, sizeof(line), textfile) ) {
val= atoi(argv[2]);
val2=atoi(argv[3]);
if ( (val==phone1) && (val2==phone2) ) {
printf(" %s ", text); //only prints Mr
text=(char*)malloc(sizeof())//tried malloc but not too sure how to use it correctly
for (i=0; i<len; i++) { //tried using for loop here didnt work.
fscanf("%s", text);
}
sortText(phone1, phone2, textsize, text);
//readableTime(posix);
}
else if ( (val2==phone1) && (val==phone2) ) {
printf(" %s ", text);
sortText(phone1, phone2, textsize, text);
//readableTime(posix);
}
fscanf(textfile, "%d %d %d %d %s", &posix, &phone1, &phone2, &textsize, text);
}
fclose(textfile);
return 0;
}
At first, read the entire file into a malloc'd char array. The fseek and ftell give you the file size:
// C99
FILE *fp = fopen("file", "r");
size_t filesize;
fseek(fp, 0, SEEK_END);
filesize = ftell(fp);
fseek(fp, 0, SEEK_SET);
char *filetext = malloc(filesize + 1);
fread(filetext, 1, filesize, fp);
filetext[filesize] = 0;
Then use a buffer for a single line with the size of the entire file so you surely have enough size. sscanf() can be used to read stuff from a string.
int readbytes;
for(int i=0; i < filesize; i+=readbytes) {
char line[filesize];
int posix, phone1, phone2, textsize;
if(EOF == sscanf(
&filetext[i], "%d%d%d%d%[^\n]%n", &posix, &phone1,
&phone2, &textsize, line, &readbytes))
{
break;
}
printf("%d %d %d %d '%s' %d\n", posix, phone1, phone2, textsize, line, readbytes);
}
The format specifier '%[^\n]' means: every character until the next newline character. The format specifier '%n' gives you the number of bytes that have been read with this sscanf call so far, effectively your line size, that you can use to advance the iterator.
I am currently learning reading from files in C.
Anyway, cutting to the chase:
Text file content:
123456 James Doakes; 0
987987 Dexter Morgan; 0
010203 Masuka Perv; 0
int main()
{
char accountNr[ACCOUNTNRSIZE], ownerName[NAMESIZE], enter[3];
int accountBalance = 0;
char filename[] = "breg.txt";
FILE *file = fopen(filename, "r");
if (file != NULL) {
char line[128];
while (fgets(line, sizeof(line), file) != NULL) {
sscanf(line, "%s %[^;] %d ", accountNr, ownerName, &accountBalance);
printf("%s", ownerName);
//fflushstdin();
}
fclose(file);
} else {
perror(filename);
}
return 0;
}
I wrote this to check if the name for instance James Doakes was registered correctly :
printf("%s", ownerName);
But when it prints that out it's like the stdout is still active and I can push Enter and it will type the name again. My goal is to of course be able to sscanff the number, the full name, and the last number as seperate variables. But it obviously doesn't work. I am guessing a \n gets registered as well. Dunno, I am just speculating.
What am I doing wrong? Why? And how do I solve this?
Much appreciated,
Mif
%s %[^;] %d
means a string terminated by white space, optional white space, a sequence of characters that are not ;, optional white space, then a number.
You appear to be not scanning for the actual ; character itself so that, when you try to get the number, the ; in the input stream will cause it to fail. You can see this with:
#include <stdio.h>
#define ACCOUNTNRSIZE 100
#define NAMESIZE 100
int main (void) {
char accountNr[ACCOUNTNRSIZE], ownerName[NAMESIZE], enter[3];
int accountBalance = 0;
char filename[] = "breg.txt";
FILE *file = fopen(filename, "r");
if (file != NULL) {
char line[128];
while (fgets(line, sizeof(line), file) != NULL) {
int count = sscanf(line, "%s %[^;] %d ", accountNr, ownerName, &accountBalance);
printf ("%d [%s] [%s] [%d]\n", count, accountNr, ownerName, accountBalance);
}
fclose(file);
} else {
perror(filename);
}
return 0;
}
which outputs:
2 [123456] [James Doakes] [0]
2 [987987] [Dexter Morgan] [0]
2 [010203] [Masuka Perv] [0]
In fact, even if you change the breg.txt file to be:
123456 James Doakes; 314159
987987 Dexter Morgan; 271828
010203 Masuka Perv; 42
you still get 0 for the account balance because the scanning only successfully reads two items.
Whenever you use one of the scanf-family functions, you should check the return code to ensure it's scanning the correct number of items, as in:
int count = sscanf (line, "%s %[^;] %d ", accountNr, ownerName, &accountBalance);
if (count != 3) {
fprintf (stderr, "Catostrophic failure, count is %d\n", count);
return 1;
}
The fix here is relatively simple, just use %s %[^;]; %d as the format string.
With that change, the output you see is:
3 [123456] [James Doakes] [314159]
3 [987987] [Dexter Morgan] [271828]
3 [010203] [Masuka Perv] [42]
Keep in mind you don't actually need a space before the %d (though it causes no harm). That particular format specifier skips white space before attempting to scan the number.
I'm really new to Sqlite and I want to write a text file (xml actually) from an sqlite database table automatically using C. How can I do that? I got these to select some data from database and print in terminal:
int callback(void * ptr, int resultados, char ** STR1, char **STR2) {
int i;
for(i = 0; STR1[i] != NULL; i++) {
printf("%s = %s\n", STR2[i], STR1[i]);
}
return 0;
}
and inside of main:
/* Open database */
rc = sqlite3_open("test.db", &db);
if( rc ){
fprintf(stderr, "Can't open database: %s\n", sqlite3_errmsg(db));
exit(0);
}else{
fprintf(stderr, "Opened database successfully\n");
}
/* Create SQL statement */
sql = "SELECT * from COMPANY";
/* Execute SQL statement */
rc = sqlite3_exec(db, sql, callback, (void*)data, &zErrMsg);
if( rc != SQLITE_OK ){
fprintf(stderr, "SQL error: %s\n", zErrMsg);
sqlite3_free(zErrMsg);
}else{
fprintf(stdout, "Operation done successfully\n");
}
sqlite3_close(db);
and then I tried to change the callback, to get STR1 and STR2 to write a text file, something like this:
int callback(void * ptr, int resultados, char ** STR1, char **STR2) {
int i;
char teste[1024];
FILE *pFile;
pFile = fopen ("test.txt", "a+");
for(i = 0; STR1[i] != NULL; i++) {
printf("%s = %s\n", STR2[i], STR1[i]);
snprintf (teste, sizeof(teste), "%s %s\n", STR2[i], STR1[i]);
fwrite (teste, 1, sizeof(teste), pFile);
fflush(pFile);
}
return 0;
}
but when I try to open the test.txt, gedit says 'There was a problem opening the file /home/kdan/test/test.txt. The file you opened has some invalid characters', and the text contains a bunch of random characters, numbers and symbols. So I'm not being able to get the selected data and convert to string D: should I try to use something like sqlite_mprintf, sqlite_vmprintf, sqlite_exec_printf or sqlite_get_table_printf? Would it be right? Or is there another way to select the data and format it to a variable char? Sorry for my rusty english.
Edited: It is working now, just needed to use fputs instead of fwrite, here is the code working:
int callback(void * ptr, int resultados, char ** STR1, char **STR2) {
int i;
char teste[1024];
FILE *pFile;
pFile = fopen ("test.txt", "a");
for(i = 0; STR1[i] != NULL; i++) {
printf("%s = %s\n", STR2[i], STR1[i]);
snprintf (teste, sizeof(teste), "%s %s\n", STR2[i], STR1[i]);
fputs (teste, pFile);
fflush(pFile);
}
return 0;
}
Haven't tested your code but I think the problem is with the fwrite() call.
From the linux manpages:
NAME
fread, fwrite - binary stream input/output
SYNOPSIS
[...]
size_t fwrite(const void *ptr, size_t size, size_t nmemb,
FILE *stream);
DESCRIPTION
[...]
The function fwrite() writes nmemb elements of data, each size bytes
long, to the stream pointed to by stream, obtaining them from the loca‐
tion given by ptr.
STR2[i] and STR1[i] may have a total length less than sizeof teste. For illustrative purpose, let's say STR2[i] is "foo" and STR1[i] is "bar". After the snprintf() call, teste will have the following contents:
teste[0] 'f'
teste[1] 'o'
teste[2] 'o'
teste[3] ' '
teste[4] 'b'
teste[5] 'a'
teste[6] 'r'
teste[7] '\n'
teste[8] '\0'
teste[9] onwards uninitialised
Since fwrite is for writing to a binary stream, it will NOT stop writing after reaching the '\0' byte. Instead it will keep writing all the uninitialised characters in teste. In this case it will write 1015 uninitialised characters.
The proper way to write to a text stream is to use either fputs() (in which case you should remove the '\n' in your string) or fprintf(). Or, if you really want to use fwrite(), ask it to print strlen(teste) bytes (which will be 8 in this case) instead of sizeof teste which is 1024.
Finally, although not related to your problem, if you are not reading from the file you should fopen() it with "a" instead of "a+".
I just want to output 3 integers from the file. Why this doesn't work? I get -1079184140 and similar.
int main(int argc, char *argv[])
{
FILE* stream = fopen(argv[2], "r");
char line[80];
for (int i = 0; i < 3; i++)
{
fgets(line, 80, stream);
printf("%d \n", line);
}
fclose(streamForInput);
}
I would use sscanf.
int number;
sscanf (line, "%d", &number);
printf ("%d \n", number);
That will pull the first integer on a line. This is not the most secure or robust way, but that is out of scope.
PS:
fclose(streamForInput);
Should be:
fclose(stream);
Hmm. The first problem is:
printf("%d \n", line);
because line is a char[]. But you use a %d to output it, so you output line, which is an address. So printf prints the address of line... instead you coud use printf ("%d", atoi(line));
To print a string, which line is, use %s:
printf("%s \n", line);
Now, if it really were an integer, you could use %d:
int num = atoi(line);
printf("%d \n", num );
What you're seeing is the result of treating a pointer type (which is what a string in C basically is) as an integer type. Since pointers hold memory addresses, that -1079184140 is the actual address the pointer holds, represented as a 32 bit signed integer.
If you know exactly the content of the file (three numbers separated by white space), why not directly read it?
if (fscanf(stream, "%d%d%d", &foo, &bar, &baz) < 3)
// handle error
printf("%d\n%d\n%d\n", foo, bar, baz);
But if you want to read lines, there are already other good answers.
To read a file line by line for integers
void read_file(char *filename, int *readbuff, int size)
{
FILE *fp = fopen(filename,"r");
if(fp == NULL){
printf("Failed to open file %s \n", filename);
return;
}
/*the condition in for loop checks if the integer was read into
readbuff[i] and the readbuff is not overflown*/
for(int i = 0 ; fscanf(fp,"%d\n",&readbuff[i]) == 1 && i < size; ++i);
fclose(fp);
return;
}
I have a file of simply tab-separated integers (a .txt file) and I wish to read them in with just C, line by line. So, say each line has 5 integers. How can I accomplish this?
My first attempt was as follows. It was just to read in a single integer, but even that didn't work:
FILE *fp;
char blah[255];
int *some_int;
fp = fopen("test.txt", "rt");
while (fgets(blah, 255, fp) != NULL)
{
sscanf(blah, "%d", some_int);
printf("%d\n", *some_int);
}
Here's a way no one else suggested, that doesn't use fscanf so you can have sane error handling:
char buffer[BUFSIZE];
size_t size = 5;
int *data = malloc(size * sizeof *line);
if(line == NULL) error();
while(fgets(buffer, sizeof buffer, fp)
{
size_t i = 0;
char *next = buffer;
while(*next && *next != '\n')
{
data[i++] = strtol(next, &next, 0);
// check for errors
}
}
Basically, instead of trying to use *scanf's "%d" to read characters, use the function it (probably) calls to do the conversion: strtol. Where *scanf goes through the string to match the format string but doesn't let you "save your place" in between function calls, strtol does, which is what you need to read an arbitrary number of integers.
I haven't written all your code for you - you have to do the hard error handling. Possible errors include:
i == size, in which case you can try to make data bigger with realloc. Alternately, you could loop through the buffer and count how many numbers there are beforehand, then allocate that many so you don't need to reallocate later.
fgets didn't read the entire line (check that the last character before '\0' is '\n'). In this case you'll probably want to refill the buffer and keep reading numbers. Be careful in this case - you'll likely need to go back and recalculate the last number - fgets might have cut it off. (This is one disadvantage to using fgets.)
Erroneous input - handle however you like.
#include <stdio.h>
int main(){
FILE *fp;
int scanned = 0;
int some_ints[5];
fp = fopen("test.txt", "r");
while ((scanned = fscanf(fp, "%d %d %d %d %d", some_ints, some_ints+1, some_ints+2, some_ints+3, some_ints+4)) != EOF) {
if(scanned ==5){
printf("%d %d %d %d %d\n", some_ints[0], some_ints[1], some_ints[2], some_ints[3], some_ints[4]);
}
else {
printf("Whoops! Input format is incorrect!\n");
break;
}
}
}
I'd do something like this:
int storedVals[MAX_STORED_VALS];
int bf;
int ii=0;
while (!feof(fp) && ii<MAX_STORED_VALS) {
if (fscanf(fp," %d",&bf)) {
storedVals[ii++]=bf;
}
}
fscanf automatically does white space trimming. So as long as there's a space in your scan string, it'll get rid of zero or more \t (tabs) and \n (newlines) to find the next integer. Of course, this doesn't do much by way of error correction.