I have a little problem with PostgreSQL results and integer in C language. So I have a simple table with this structure :
ID(pk int) | name (text) | values (int)
1 | apple | 100
2 | banana | 9
I use this code :
PGconn *conn = PQconnectdb("user=un password=pw dbname=db hostaddr=1.2.3.4 port=5432");
res = PQexec(conn, "SELECT * FROM fruits WHERE name='banana'");
int *banan_count;
banana_count = (int)PQgetvalue(res, 0, 2);
printf ("Banana values : %u\n", banana_count);
PQclear(res);
do_exit(conn);
The problem is that my results isn't '9' when I try print out with 'banana_count', but when I print out 'PQgetvalue(res, 0, 2)' then I got '9', so I think I have a conversion problem, but I can't find a solution. So my question is that how can I convert 'PQgetvalue(res, 0, 2)' to integer variable in C proramming language? (I use Ubuntu 18.04 and for compile my fruits.c with gcc).
Thank you for the supports and helps.
In C, text is technically an array of chars, followed with a null-term. Roughly, array is a pointer to allocated memory of known size (syntax may vary widely). So let's see the code.
PGconn *conn = PQconnectdb("user=un password=pw dbname=db hostaddr=1.2.3.4 port=5432"); //No doubts. It's your professional area.
res = PQexec(conn, "SELECT * FROM fruits WHERE name='banana'"); //same thing.
//int *banan_count; //Aside the typo (banana_count), you don't need a pointer to int! PQgetvalue returns a pointer to char (roughly equal to array of chars, roughly equal to text, you'll learn differences later). This array keeps ONE int value in text form.
int banana_count_2; //That's what you need: a single int value. Not a pointer.
//banana_count = (int)PQgetvalue(res, 0, 2); //Wrong: you take the pointer to char, convert it few times and assign to your int* pointer. Pointer becomes technically valid, but it points to first group of characters, reading them as an integer value (probably char1 + char2*256 + char3*65536 ... depending on your platform). Of course, actual integers are not represented in text form in computer memory, so you get an absurdly huge value (even '0' character has code 48).
banana_count_2 = atoi(PQgetvalue(res,0,2)); //PQgetvalue allocates memory by itself, so the char* it returns points to a valid, allocated memory area. We can say it's an array filled with null-terminated text line, and give this line to atoi();
printf ("Banana values : %u\n", banana_count_2);
PQclear(res); //Good thing you didn't forget to unallocate the char array!
do_exit(conn);
Related
I've run across this problem: I implemented a function whish converts a string into a structure. I've got this structure:
typedef struct {
unsigned a, b;
unsigned c, d;
} struct_t;
The heading of the function is the following:
struct_t * string_to_struct (char * g)
\retval p pointer to new structure created; \retval NULL if the conversion is not successful. The convertion is not successful for strings such as "5 8 10 10" (I'm given a segmentation fault error) but is successful for strings such as "5 6 6 7" or "4 5 6 8". I think the problem lies within the allocation of memory for pointer to structure p.
I thought about first allocating memory for p in this way:
p = (struct_t*)malloc(sizeof(struct_t));
And then I thought about reallocating memory for p due to make it room for the string (some strings are about 8 bytes and everything works fine, but if the string is about 10 bytes I get a segmentation fault, because by allocating memory for p as above I make room for only 8 bytes), using function realloc() to enlarge the memory where to put the structure and make it the size of the string, but I don't know how to do it properly.
Here it is how I attempted to implement the function, not using realloc():
struct_t * string_to_struct (char * g){
struct_t * p; /* pointer to new structure*/
int n;
n = sizeof(g);
if(sizeof(g) > sizeof(struct_t))
p = (struct_t*)malloc(n*sizeof(struct_t));
else
p = (struct_t*)malloc(sizeof(struct_t));
if(g[0] == '\0' ) /* trivial */
return NULL;
else
(*p).a = g[0];
(*p).b = g[2];
(*p).c = g[4];
(*p).d = g[6];
if((*p).a <= (*p).c && (*p).b <= (*p).d) /* check, the elements of the structure must satisfy those relations.*/
return p;
else
return NULL; /* convertion not successful */
}
But it's not working. Thanks in advance for any help.
First, this bit of logic is unnecessary:
int n;
n = sizeof(g);
if(sizeof(g) > sizeof(struct_t))
p = (struct_t*)malloc(n*sizeof(struct_t));
else
p = (struct_t*)malloc(sizeof(struct_t));
The correct amount of memory to allocate for one instance of your struct is always sizeof(struct_t). The length of the string doesn't matter. Also, sizeof(g) is giving you the size of the pointer, not the length of the string. You get the string length with strlen(g). You can replace the above with:
p = malloc(sizeof(struct_t));
The main problem is here:
(*p).a = g[0];
(*p).b = g[2];
(*p).c = g[4];
(*p).d = g[6];
What this does is store the ASCII value (assuming your system uses ASCII) of a particular character in the string into your struct as an integer. Given your example input of "5 6 6 7", g[0] contains the character '5'. This has an ASCII value of 53, so p->a has the value 53. When your input is all single digit numbers, the indexes you use correspond to where the digits are in the string, so you end up with the ASCII values of each digit. And because the ASCII values of the characters '0' to '9' are consecutive, the comparisons you do work as expected.
When you use a string like "5 8 10 10", the above assumption about the location of the digits breaks. So a gets '5' (53), b gets '8' (56), c gets '1' (49), and d gets a space (ASCII 32). Then your comparison (*p).b <= (*p).d) fails because 56 is not less than 32, so your function returns NULL. You're probably getting a segfault because the calling function isn't checking if NULL was returned.
To parse the string correctly, use strtok to break the string up into tokens, then use atoi or strtol to convert each substring to an integer.
I was tried to print values of a float array with 7 elements. I assigned only 3 values and they are belong to float, double and integer.
Code:
#include <stdio.h>
int main(){
float array [7];
float f = 3.24;
double d = 23.5;
int i = 4;
array[0] = f;
array[1] = i;
array[2] = d;
int n = sizeof(array)/sizeof(float);
printf("Number of Elements : %d \n\n\n",n);
for(int j = 0; j < n ; j++){
printf("%.2f ,",array[j]);
}
printf("\b ");
}
I got an output as follows :
Number of Elements : 7
3.24 ,4.00 ,23.50 ,-1.#R ,96627196995476105000000000000000.00 ,96629547147269436000000000000000.00 ,0.00
I want to clear is my code correct? And why last four values are different to each other. What are these values?
The last values are known as garbage values in C.
If you do not initialize a variable explicitly in C, it's value could be anything before you explicitly assign something to it. This anything could be garbage; the language standard does not specify what it should be.
You can read this blog for How C compiler decides garbage values: http://blog.aditech.info/2008/02/how-c-compiler-decides-garbage-values.html.
First.
Yes, your code is correct (add return 0 command at the end of your main() function though). However, it needs to be more specific, which leads to your second question.
Second.
C is a language that allows a programmer to do lots of things, but it also requires the programmer to do lots of manual coding.
So, when you declare an array of 7 items, C compiler marks a region of memory to accommodate those items (in this case of the type of float). But it doesn't actually check what that region of memory contains until you explicitly assign the values. In your case the last four values (which you have not assigned yourself) are just garbage left in the region of memory marked for your array.
Once again, compiler does not clear the memory for you when you declare the array, it just marks the region of memory. It's your responsibility to assign default values to the array.
Your possible solution is to manually initialize all of the elements of your array to some default value (for example, a 0), like this:
float array[7] = {0}
I have programming exam soon, and I still can't understand some things, could you guys help me?
Basically, we got:
char *nap[]= {"Reklamacja","Perspektywa","Reinkarnacja","Hermengilda","Audytorium","Mineralogia","Frustracja"}
Those are bunch of words in Polish language, but they doesn't matter at all.
So moving on, we have:
Size of char type on this PC : 1
Size of long type on this PC : 4
Address of beginning nap array (char type): 0x22ff20
Address of R letter in word "Reklamacja": 0x47575d,
Address of P letter in word "Perspektywa": 0x475768,
Address of R letter in word "Reinkarnacja": 0x475774,
Address of H letter in word "Hermengilda": 0x475781,
Address of A letter in word "Audytorium": 0x47578e,
Address of M letter in word "Mineralogia": 0x475799,
Address of F letter in word "Frustracja": 0x4757a5
The question is: what is the effect of the following line of code?
printf("%#lx", nap+5);
The correct answer is: 0x22ff34
Why is it like so and not like 0x22ff20 + 5 which is 0x22ff25?
The answer is the same for any typed pointer value in C, and uses a language feature called pointer arithmetic.
What is the byte-width of the element type, including padding if a struct or union type?
Multiply by the index N you're using
Add to the base address of the array.
The result should be the address of the N'th element in the sequence. Note you cannot portably do this with void*, and any cast you perform on the pointer prior to performing the operation will affect the outcome.
In your case, the element type of your array is char *. Assuming sizeof(char*) == 4 on your platform then
4 bytes
4 * 5 = 20 bytes (0x14)
0x22ff20 + 0x14 = 0x22ff34
Remember, an array expresses as pointer-to-type with a value of the array base-address when used in the above calculation. It may seem trivial, but that is routinely the part of this that is missed.
Best of luck
nap is a pointer to the first item of the array: nap == &(nap[0]).
nap+5 is a pointer to the sixth item of the array: nap+5 == &(nap[5]).
Each item of your array is 4 bytes long (test for sizeof(char *)), so the numerical value of nap+5 is a numerical value of nap plus 5 times 4:
0x22ff20 + 4*5 = 0x22ff20 + 0x14 = 0x22ff34
Your nap variable is declared as a pointer to an array of strings. So when you are using nap+5 you are really moving the pointer 5 elements down the array (which will point to Mineralogia). In order to retrieve the result that you were expecting, you will have to cast the pointer so it will point to the first string, then add 5 to it to move the pointer 5 characters down. Here is a test application that I wrote up to demonstrate this (my code usually explains better than I can verbally lol):
#include <stdio.h>
int main()
{
char* nap[] = {"Reklamacja","Perspektywa","Reinkarnacja","Hermengilda","Audytorium","Mineralogia","Frustracja"};
//Returns the beginning address of nap
printf("%#lx\r\n", nap);
//Returns the sixth string in nap (aka nap[5] since arrays are 0-based index)
//and the address
printf("%s %#lx\r\n", *(nap+5), nap+5);
//Returns the first string in the array (aka nap[0]) and the address
printf("%s %#lx\r\n", *nap, *nap);
//Returns the 1st string in the array starting at the 6th letter and the address
printf("%s %#lx\r\n", *nap+5, *nap+5);
return 0;
}
Also remember that a char is 4 bytes so the last printf statement moved the pointer 20 bytes down the string.
Well , I was actually looking at strcmp() , was confused about its working . Anyways I wrote this code
#include <stdio.h>
main()
{
char a[5] = "ggod";
char b[5] = "ggod";
int c = 0;
c = b - a;
printf("%d value", c);
}
and I get the output as
16
Can anyone explain Why is it 16 ?
What you have subtracted there are not two strings, but two char *. c holds the memory address difference between a and b. This can be pretty much anything arbitrary. Here it just means that you have 16 bytes space between the start of the first string and the start of the second one on your stack.
c = b - a;
This is pointer arithmetic. The array names it self points to starting address of array. c hold the difference between two locations which are pointed by b and a.
When you print those values with %p you will get to know in your case
if you print the values looks like this a==0x7fff042f3710 b==0x7fff042f3720
c= b-a ==>c=0x7fff042f3720-0x7fff042f3710=>c=0x10 //indecimal the value is 16
Try printing those
printf("%p %p\n",a,b);
c=b-a;
if you change size of array difference would be changed
char a[120]="ggod";
char b[5]="ggod";
b is an array object
a is also an array object
an array object is a static address to an array.
so b-a is adifference between 2 addresses and not between the 2 strings "ggod"-"ggod"
If you want to compare between 2 string you can use strcmp()
strcmp() will return 0 if the 2 strings are the same and non 0 value if the 2 strings are different
here after an example of using strcmp()
I am trying to do a function that will store in a char array some information to print on it:
int offset = 0;
size_t size = 1;
char *data = NULL;
data = malloc(sizeof(char));
void create(t_var *var){
size_t sizeLine = sizeof(char)*(strlen(var->nombre)+2)+sizeof(int);
size = size + sizeLine;
realloc(data, size);
sprintf(data+offset,"%s=%d\n",var->name,var->value);
offset=strlen(data);
}
list_iterate(aList, (void *)create);
t_var is a struct that has two fields: name (char*) and value (int).
What's wrong with this code? When running it on Valgrind it complains about the realloc and sprintf.
Without knowing the specific valgrind errors, the standout one is:
realloc(data, size); should be data = realloc(data, size);
I'm sorry to say that, but almost EVERYTHING is wrong with your code.
First, incomplete code.
You say your t_var type has two members, name and value.
But your code refers to a nombre member. Did you forget to mention it or did you forget to rename it when publishing the code?
Second, misused sizeof.
You use a sizeof(int) expression. Are you aware what you actually do here?!
Apparently you try to calculate the length of printed int value. Alas, operator sizeof retrieves the information about a number of bytes the argument occupies in memory. So, for example, for 32-bits integer the result of sizeof(int) is 4 (32 bits fit in 4 bytes), but the maximum signed 32-bit integer value is power(2,31)-1, that is 2147483647 in decimal. TEN digits, not four.
You can use (int)(2.41 * sizeof(any_unsigned_int_type)+1) to determine a number of characters you may need to print the value of any_unsigned_int_type. Add one for a preceding minus in a case of signed integer types.
The magic constant 2.41 is a decimal logarithm of 256 (rounded up at the 3-rd decimal digi), thus it scales the length in bytes to a length in decimal digits.
If you prefer to avoid floating-point operations you may use another approximation 29/12=2.41666..., and compute (sizeof(any_unsigned_int_type)*29/12+1).
Third, sizeof(char).
You multiply the result of strlen by sizeof(char).
Not an error, actually, but completely useless, as sizeof(char) equals 1 by definition.
Fourth, realloc.
As others already explained, you must store the return value:
data = realloc(data, size);
Otherwise you risk you loose your re-allocated data AND you continue writing at the previous location, which may result in overwriting (so destroying) some other data on the heap.
Fifth, offset.
You use that value to determine the position to sprintf() at. However, after the print you substitute offset with a length of last printout instead of incrementing it. As a result consecutive sprintfs will overwrite previous output!
Do:
offset += strlen(data);
Sixth: strlen of sprintf.
You needn't call strlen here at all, as all functions of printf family return the number of characters printed. You can just use that:
int outputlen = sprintf(data+offset, "%s=%d\n", var->name, var->value);
offset += outputlen;
Seventh: realloc. Seriously.
This is quite costly function. It may need to do internal malloc for a new size of data, copy your data into a new place and free the old block. Why do you force it? What impact will it have on your program if it needs to print five thousand strings some day...?
It is also quite dangerous. Really. Suppose you need to print 5,000 strings but there is room for 2,000 only. You will get a NULL pointer from realloc(). All the data printed to the point are still at the current data pointer, but what will you do next?
How can you tell list_iterate to stop iterating...?
How can you inform the routine above the list_iterate that the string is incomplete...?
There is no good answer. Luckily you needn't solve the problem — you can just avoid making it!
Solution.
Traverse your list first and calculate the size of buffer you need. Then allocate the buffer — just once! — and go on with filling it. There is just one place where the allocation may fail and you can simply not go into the problem if that ever happens:
int totaloutputlength = 0;
char *outputbuffer = NULL;
char *currentposition = NULL;
void add_var_length(t_var *var){
const int numberlength = sizeof(var->value)*29/12 + 1;
totaloutputlength += strlen(var->name) + 2 + numberlength;
}
void calculate_all_vars_length(t_list *aList){
totaloutputlength = 0;
list_iterate(aList, (void *)add_var_length);
}
void sprint_var_value(t_var *var){
int outputlen = sprintf(currentposition, "%s=%d\n", var->name, var->value);
currentposition += outputlen; // advance the printing position
}
int sprint_all_vars(t_list *aList){
calculate_all_vars_length(aList);
outputbuffer = malloc(totaloutputlength + 1); // +1 for terminating NUL char
// did allocation succeed?
if(outputbuffer == NULL) { // NO
// possibly print some error message...
// possibly terminate the program...
// or just return -1 to inform a caller something went wrong
return -1;
}
else { // YES
// set the initial printing position
currentposition = outputbuffer;
// go print all variables into the buffer
list_iterate(aList, (void *)sprint_var_value);
// return a 'success' status
return 0;
}
}