res = PQexec(db, "SELECT username, msg, ts, lat, lon FROM tweet");
rows = PQntuples(res);
cols = PQnfields(res);
printf("Getting %d rows\n", rows);
for (i = 0; i < rows; i++)
{
for (j = 0; j < cols; j++)
{
msg = PQgetvalue(res, i, j);
printf("%s\t", msg);
}
putchar(10);
}
PQclear(res);
.
username
msg
ts (lat, lon)
I want the printed table to be in the format I have above, but it gets printed out all on a single line. How do I add newlines and format column queries to be wrapped in parenthesis or be between commas, etc.
Simply change the \t to a \n like so
printf("%s\n", msg);
If you want to change the formatting, you can do something like this:
Assign each result to variables:
char *uname, *msg, *ts, *lat, *lon;
Then, use a temporary:
char *res = malloc(/*pick a safe size*/);
sprintf(res, "%s\n%s\n%s (%s, %s)\n", uname, msg, ts, lat, lon);
printf(res);
Alternatively, you can skip the assigning to res and use
printf("%s\n%s\n%s (%s, %s)\n", uname, msg, ts, lat, lon);
instead
Related
I am printing a vary large dataset to a text file using fprintf:
FILE *ff23=fopen("parts_in_cell_dript_part.txt","wa");
if (ff23 == NULL)
error("Error opening text file");
int N=e->s->nr_parts;
fprintf (ff23,"%d\n",N);
for (int k = 0; k < N; k++) {
struct part *restrict p = &parts[k];
float xx=p->x[0];
float yy=p->x[1];
float zz=p->x[2];
int id;
id=p->id;
fprintf(ff23,"%d %f %f %f %d\n",k+1,xx,yy,zz,id);
}
fprintf(ff23,"Finished func\n");
fclose(ff23);
exit(1);
The output suffers from several problems:
lines overwrite other lines. The first column is should go consecutively from 1 to N.
more/less numbers are printed to the file than expected.
I have try to use only append but results stay the same.
EDIT:
I tried adding "t" mode, it did not help
I need to do this in two separate steps but so far I am not finding a way of doing this.
First, I need to convert a double variable, into a char variable (and to be saved in that variable). I have noticed type casting doesnt work the same in C as Java / other languages. How do I cast a variable to be a string / char?
Second, I need to concatenate the strings, there will be a total of 6 string variables that will need concatenating, I have only found the strcat function which only takes 2 arguments.
These are the strings I am trying to build:
char *queryOne = "INSERT INTO location (id, carid, ownerid, lat, long, speed) VALUES (,2, 1, ";
char *queryTwo = lat; // lat is a double
char *queryThree = ",";
char *queryFour = longatude; // longatude is a double
char *queryFive = ",";
char *querySix = speed; // speed is a double
And then I need the concatenated string to work in: (mysql_query(conn, query)) as one long string
Edit: So possibly, this should convert the datatype I think?
char buffer [50];
char *queryOne = "INSERT INTO location (id, carid, ownerid, lat, long, speed) VALUES (,2, 1, ";
char *queryTwo = sprintf (buffer, "%d", lat);
char *queryThree = ",";
char *queryFour = sprintf (buffer, "%d", longatude);
char *queryFive = ",";
char *querySix = sprintf (buffer, "%d", speed);
fprintf(stderr, "Dta: %s\n", queryOne);
fprintf(stderr, "Dta: %s\n", *queryTwo);
fprintf(stderr, "Dta: %s\n", queryThree);
fprintf(stderr, "Dta: %s\n", *queryFour);
fprintf(stderr, "Dta: %s\n", queryFive);
fprintf(stderr, "Dta: %s\n", *querySix);
In your case, you could use:
#define MAXSQL 256
char sql[MAXSQL];
snprintf(sql, MAXSQL, "%s %f , %f , %f", queryOne, lat, longatude, speed);
The snprintf function writes onto the buffer, that is its first argument. http://www.cplusplus.com/reference/cstdio/snprintf/?kw=snprintf
Now you can use the sql string as you please.
Note that I used snprintf rather than sprintf. This is to avoid potential buffer overflows.
Also, don't use strcat so repeatedly, because that causes a Shlemiel the Painter algorithm, and every next call to strcat gets slower, because strcat has to start from the beginning and find the null terminator. See http://www.joelonsoftware.com/articles/fog0000000319.html for more info.
I am trying to format a string and then print it out to an LCD during an ISR. The ISR functions correctly with sprintf() commented out; but when it is introduced the program crashes during the ISR.
void __ISR(_CHANGE_NOTICE_VECTOR, IPL1) CNIntHandler(void) {
//more of my code later
LATBINV = LEDC; //invert LEDC to a 1
hw_msDelay(20);
int buttons = read_buttons();
decode_buttons(buttons, &g_step_mode, &g_step_dir, &g_motor_delay);
LATBINV = LEDC; //reinvert LEDC to 0
mCNClearIntFlag(); //clear the CN flag
}
The sprintf() occurs within the decode_buttons() fucntion:
void decode_buttons(int f_buttons, int *f_step_mode, int *f_step_dir, int *f_motor_delay) {
char f_mode_str;
char f_dir_str;
int f_RPM;
char f_LCD_str;
switch(f_buttons) {
case 0x0000: //none pressed
*f_step_mode = HS;
f_mode_str = "HALF";
*f_step_dir = CW;
f_dir_str = "CW";
*f_motor_delay = 20; // semipermanent value
f_RPM = 15;
break;
case 0x0040: //BTN 1 pressed
*f_step_mode = FS;
f_mode_str = "FULL";
*f_step_dir = CW;
f_dir_str = "CW";
*f_motor_delay = 40;
f_RPM = 15;
break;
case 0x0080: // BTN 2 pressed
*f_step_mode = HS;
f_mode_str = "HALF";
*f_step_dir = CCW;
f_dir_str = "CCW";
*f_motor_delay = 30;
f_RPM = 10;
break;
case 0x00C0: //Both pressed
*f_step_mode = FS;
f_mode_str = "FULL";
*f_step_dir = CCW;
f_dir_str = "CCW";
*f_motor_delay = 24;
f_RPM = 25;
break;
default:
break;
}
sprintf(f_LCD_str, "%s %s %d", f_dir_str, f_mode_str, &f_RPM);
LCD_puts(f_LCD_str); //output string to LCD
return;
}
I'm working on a PIC32 Cerebot board, and the goal is to update an LCD with the current mode, direction, and RPM of a stepper motor. I'll clarify what I can and post anything needed.
sprintf composes a string and stores it in an array that must be big enough: http://www.cplusplus.com/reference/cstdio/sprintf/
In your code, the output buffer you pass to sprintf is declared as
char f_LCD_str;
which is not an array but a single character. sprintf will inevitable overflow.
A good declaration would be
char f_LCD_str[30];
(same remark for your other char arrays: f_mode_str and f_dir_str)
It is always safer to use snprintf in order to avoid overflow risks. In which case the call would be:
sprintf(f_LCD_str, 30, "%s %s %d", f_dir_str, f_mode_str, f_RPM);
note: &f_RPM will print the address of the variable, where f_RPM will print out the variable value, depending on what you want.
How can I replace the use of (FILE) and (fopen) with (scanf) to get the input values and send in these 2 functions?
I want to use this function in Objective-c code.
For more info you can see the whole code here link
static void stemfile(FILE * f)
{ while(TRUE)
{ int ch = getc(f);
if (ch == EOF) return;
if (LETTER(ch))
{ int i = 0;
while(TRUE)
{ if (i == i_max) increase_s();
ch = tolower(ch); /* forces lower case */
s[i] = ch; i++;
ch = getc(f);
if (!LETTER(ch)) { ungetc(ch,f); break; }
}
s[stem(s,0,i-1)+1] = 0;
/* the previous line calls the stemmer and uses its result to
zero-terminate the string in s */
printf("%s",s);
}
else putchar(ch);
}
}
int main(int argc, char * argv[])
{ int i;
s = (char *) malloc(i_max+1);
for (i = 1; i < argc; i++)
{ FILE * f = fopen(argv[i],"r");
if (f == 0) { fprintf(stderr,"File %s not found\n",argv[i]); exit(1); }
stemfile(f);
}
free(s);
return 0;
}
The scanf() function cannot be a direct replacement for the existing code. The existing code (which is not very well written IMO), splits up the input character stream into letters (defined by the LETTER() macro to be either uppercase or lowercase characters), and non-letters, and converts these letter sequences into lowercase before applying the stem() function to them.
The scanf() function, on the other hand extracts primitive types (int, char, double, etc.) and explicitly delimited strings from the input stream. The delimiters in the given code (i.e. anything that is not LETTER()) is too vague for scanf() (though not for a regular expression). scanf() needs a specific character on each end of a substring to look for. Also, scanf() cannot convert to lowercase automatically.
Assuming your input continues to be files, I think the easiest solution might be to leave the code as-is and use it, convoluted as it may be. There is nothing about it that shouldn't run as part of a larger Objective-C program. Objective-C, after all, still provides access to the C standard library, at least within the limits that the operating system sets (iOS is far more limiting than MacOS, if your are on an Apple platform).
The general problem here is that of tokenization: breaking an input sequence of unclassified symbols (like characters) into sequence of classified tokens (like words and spaces). A common approach to the problem is to use a finite state machine/automaton (FSA/FSM) to apply parsing logic to the input sequence and extract the tokens as they are encountered. An FSA can be a bit hard to set up, but it is very robust and general.
I'm still not sure why you would want to use scanf() in main(). It would presumably mean changing the interface of stemfile() (including the name since it would no longer be processing a file) to take a character string as input. And scanf() is going to make life difficult; it will read strings separated by blanks, which may be part of its attraction, but it will include any punctuation that is included in the 'word'.
As Randall noted, the code in the existing function is a little obsure; I think it could be written more simply as follows:
#include <stdio.h>
#include <ctype.h>
#define LETTER(x) isalpha(x)
extern int stem(char *s, int lo, int hi);
static void stemfile(FILE * f)
{
int ch;
while ((ch = getc(f)) != EOF)
{
if (LETTER(ch))
{
char s[1024];
int i = 0;
s[i++] = ch;
while ((ch = getc(f)) != EOF && LETTER(ch))
s[i++] = ch;
if (ch != EOF)
ungetc(ch, f);
s[i] = '\0';
s[stem(s, 0, i-1)+1] = 0;
/* the previous line calls the stemmer and uses its result to
zero-terminate the string in s */
printf("%s", s);
}
else
putchar(ch);
}
}
I've slightly simplified things by making s into a simple local variable (it appears to have been a global, as does imax), removing imax and the increase_s() function. Those are largely incidental to the operation of the function.
If you want this to process a (null-terminated) string instead, then:
static void stemstring(const char *src)
{
char ch;
while ((ch = *src++) != '\0')
{
if (LETTER(ch))
{
int i = 0;
char s[1024];
s[i++] = ch;
while ((ch = *src++) != '\0' && LETTER(ch))
s[i++] = ch;
if (ch != '\0')
src--;
s[i-1] = '\0';
s[stem(s,0,i-1)+1] = 0;
/* the previous line calls the stemmer and uses its result to
zero-terminate the string in s */
printf("%s",s);
}
else
putchar(ch);
}
}
This systematically changes getc(f) into *src++, EOF into \0, and ungetc() into src--. It also (safely) changes the type of ch from int (necessary for I/O) to char. If you are worried about buffer overflow, you have to work a bit harder in the function, but few words in practice will be even 1024 bytes (and you could use 4096 as easily as 1024, with correspondingly smaller - infinitesimal - chance of real data overflowing the buffer. You need to judge whether that is a 'real' risk for you.
The main program can become quite simply:
int main(void)
{
char string[1024];
while (scanf("%1023s", string) == 1)
stemstring(string);
return(0);
}
Clearly, because of the '1023' in the format, this will never overflow the inner buffer. (NB: Removed the . from "%.1023s" in first version of this answer; scanf() is not the same as printf()!).
Challenged: does this work?
Yes - this code below (adding a dummy stem() function and slightly modifying the printing) works reasonably well for me:
#include <stdio.h>
#include <ctype.h>
#include <assert.h>
#define LETTER(x) isalpha(x)
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
static int stem(const char *s, int begin, int end)
{
assert(s != 0);
return MAX(end - begin - 3, 3);
}
static void stemstring(const char *src)
{
char ch;
while ((ch = *src++) != '\0')
{
if (LETTER(ch))
{
int i = 0;
char s[1024];
s[i++] = ch;
while ((ch = *src++) != '\0' && LETTER(ch))
s[i++] = ch;
if (ch != '\0')
src--;
s[i-1] = '\0';
s[stem(s,0,i-1)+1] = 0;
/* the previous line calls the stemmer and uses its result to
zero-terminate the string in s */
printf("<<%s>>\n",s);
}
else
putchar(ch);
}
putchar('\n');
}
int main(void)
{
char string[1024];
while (scanf("%1023s", string) == 1)
stemstring(string);
return(0);
}
Example dialogue
H: assda23
C: <<assd>>
C: 23
H: 3423///asdrrrf12312
C: 3423///<<asdr>>
C: 12312
H: 12//as//12
C: 12//<<a>>
C: //12
The lines marked H: are human input (the H: was not part of the input); the lines marked C: are computer output.
Next attempt
The trouble with concentrating on grotesquely overlong words (1023-characters and more) is that you can overlook the simple. With scanf() reading data, you automatically get single 'words' with no spaces in them as input. Here's a debugged version of stemstring() with debugging printing code in place. The problem was two off-by-one errors. One was in the assignment s[i-1] = '\0'; where the -1 was not needed. The other was in the handling of the end of a string of letters; the while ((ch = *src++) != '\0') leftsrcone place too far, which led to interesting effects with short words entered after long words (when the difference in length was 2 or more). There's a fairly detailed trace of the test case I devised, using words such as 'great' and 'book' which you diagnosed (correctly) as being mishandled. Thestem()` function here simply prints its inputs and outputs, and returns the full length of the string (so there is no stemming occurring).
#include <stdio.h>
#include <ctype.h>
#include <assert.h>
#define LETTER(x) isalpha(x)
#define MAX(x, y) (((x) > (y)) ? (x) : (y))
static int stem(const char *s, int begin, int end)
{
int len = end - begin + 1;
assert(s != 0);
printf("ST (%d,%d) <<%*.*s>> RV %d\n", begin, end, len, len, s, len);
// return MAX(end - begin - 3, 3);
return len;
}
static void stemstring(const char *src)
{
char ch;
printf("-->> stemstring: <<%s>>\n", src);
while ((ch = *src++) != '\0')
{
if (ch != '\0')
printf("LP <<%c%s>>\n", ch, src);
if (LETTER(ch))
{
int i = 0;
char s[1024];
s[i++] = ch;
while ((ch = *src++) != '\0' && LETTER(ch))
s[i++] = ch;
src--;
s[i] = '\0';
printf("RD (%d) <<%s>>\n", i, s);
s[stem(s, 0, i-1)+1] = '\0';
/* the previous line calls the stemmer and uses its result to
zero-terminate the string in s */
printf("RS <<%s>>\n", s);
}
else
printf("NL <<%c>>\n", ch);
}
//putchar('\n');
printf("<<-- stemstring\n");
}
int main(void)
{
char string[1024];
while (scanf("%1023s", string) == 1)
stemstring(string);
return(0);
}
The debug-laden output is shown (the first line is the typed input; the rest is the output from the program):
what a great book this is! What.hast.thou.done?
-->> stemstring: <<what>>
LP <<what>>
RD (4) <<what>>
ST (0,3) <<what>> RV 4
RS <<what>>
<<-- stemstring
-->> stemstring: <<a>>
LP <<a>>
RD (1) <<a>>
ST (0,0) <<a>> RV 1
RS <<a>>
<<-- stemstring
-->> stemstring: <<great>>
LP <<great>>
RD (5) <<great>>
ST (0,4) <<great>> RV 5
RS <<great>>
<<-- stemstring
-->> stemstring: <<book>>
LP <<book>>
RD (4) <<book>>
ST (0,3) <<book>> RV 4
RS <<book>>
<<-- stemstring
-->> stemstring: <<this>>
LP <<this>>
RD (4) <<this>>
ST (0,3) <<this>> RV 4
RS <<this>>
<<-- stemstring
-->> stemstring: <<is!>>
LP <<is!>>
RD (2) <<is>>
ST (0,1) <<is>> RV 2
RS <<is>>
LP <<!>>
NL <<!>>
<<-- stemstring
-->> stemstring: <<What.hast.thou.done?>>
LP <<What.hast.thou.done?>>
RD (4) <<What>>
ST (0,3) <<What>> RV 4
RS <<What>>
LP <<.hast.thou.done?>>
NL <<.>>
LP <<hast.thou.done?>>
RD (4) <<hast>>
ST (0,3) <<hast>> RV 4
RS <<hast>>
LP <<.thou.done?>>
NL <<.>>
LP <<thou.done?>>
RD (4) <<thou>>
ST (0,3) <<thou>> RV 4
RS <<thou>>
LP <<.done?>>
NL <<.>>
LP <<done?>>
RD (4) <<done>>
ST (0,3) <<done>> RV 4
RS <<done>>
LP <<?>>
NL <<?>>
<<-- stemstring
The techniques shown - printing diagnostic information at key points in the program - is one way of debugging a program such as this. The alternative is stepping through the code with a source code debugger - gdb or its equivalent. I probably more often use print statements, but I'm an old fogey who finds IDE's too hard to use (because they don't behave like the command line I'm used to).
Granted, it isn't your code any more, but I do think you should have been able to do most of the debugging yourself. I'm grateful that you reported the trouble with my code. However, you also need to learn how to diagnose problems in other people's code; how to instrument it; how to characterize and locate the problems. You could then report the problem with precision - "you goofed with your end of word condition, and ...".
void max_min(sqlite3 *db)
{
//call back*********
int i, ncols;
sqlite3_stmt *stmt;
char *sql;
const char *tail;
char *zErrMsg = 0;
int rc;
//******************
//min/max variables
char min[20];
char max[20];
//we want only the min and max value of this table
sql = "SELECT MIN(Start),MAX(End)FROM GMTI;"; //doesn't extract but works in GUI tool?
//sql = "SELECT * FROM GMTI WHERE Start<16;"; //works?
rc = sqlite3_prepare(db, sql, strlen(sql), &stmt, &tail);
if(rc != SQLITE_OK){
fprintf(stderr, "SQL error: %s\n", sqlite3_errmsg(db));
}
rc = sqlite3_step(stmt);
ncols = sqlite3_column_count(stmt);
printf("Number of columns: %d and row status: %d", ncols, rc);
while(rc == SQLITE_ROW){
for(i=0; i<ncols; i++){
if (strncmp("Start", sqlite3_column_name(stmt,i), strlen("Start")) == 0)
{
strncpy(min, sqlite3_column_text(stmt,i), strlen(sqlite3_column_text(stmt,i)));
strcpy(min + strlen(sqlite3_column_text(stmt,i)), "\0");
printf("min is: %s\n", min);
printf("<br>");
}
if (strncmp("End", sqlite3_column_name(stmt,i), strlen("End")) == 0)
{
strncpy(max, sqlite3_column_text(stmt,i), strlen(sqlite3_column_text(stmt,i)));
strcpy(max + strlen(sqlite3_column_text(stmt,i)), "\0");
printf("max: %s\n", max);
printf("<br>");
}
}//end for
fprintf(stderr, "\n");
rc = sqlite3_step(stmt);
}//end while
sqlite3_finalize(stmt);
}
When I use the sql query above with the MIN and MAX functions, nothing prints out for min and max. If I use one of the other statements commented out there, it works as expected, printing the selected query.
What is different about the max and min in the query, that it can't extract the values? Is it not in table format?
Also, I tested the problem query string in an SqLite database browser on the same database and it works, displaying the two - min and max values.
Any suggestions would be greatly appreciated.
Thanks.
Try printing out the returned column names. Maybe they don't equal "Start" and "End" as you assumed?
Maybe you should add a space between MAX(End) and FROM ?