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.
Related
I'm pretty new to C, and I'm trying to write a function that takes a user input RAM size in B, kB, mB, or gB, and determines the address length. My test program is as follows:
int bitLength(char input[6]) {
char nums[4];
char letters[2];
for(int i = 0; i < (strlen(input)-1); i++){
if(isdigit(input[i])){
memmove(&nums[i], &input[i], 1);
} else {
//memmove(&letters[i], &input[i], 1);
}
}
int numsInt = atoi(nums);
int numExponent = log10(numsInt)/log10(2);
printf("%s\n", nums);
printf("%s\n", letters);
printf("%d", numExponent);
return numExponent;
}
This works correctly as it is, but only because I have that one line commented out. When I try to alter the 'letters' character array with that line, it changes the 'nums' character array to '5m2'
My string input is '512mB'
I need the letters to be able to tell if the user input is in B, kB, mB, or gB.
I am confused as to why the commented out line alters the 'nums' array.
Thank you.
In your input 512mB, "mB" is not digit and is supposed to handled in commented code. When handling those characters, i is 3 and 4. But because length of letters is only 2, when you execute memmove(&letters[i], &input[i], 1);, letters[i] access out of bounds of array so it does undefined behaviour - in this case, writing to memory of nums array.
To fix it, you have to keep unique index for letters. Or better, for both nums and letters since i is index of input.
There are several problems in your code. #MarkSolus have already pointed out that you access letters out-of-bounds because you are using i as index and i can be more than 1 when you do the memmove.
In this answer I'll address some of the other poroblems.
string size and termination
Strings in C needs a zero-termination. Therefore arrays must be 1 larger than the string you expect to store in the array. So
char nums[4]; // Can only hold a 3 char string
char letters[2]; // Can only hold a 1 char string
Most likely you want to increase both arrays by 1.
Further, your code never adds the zero-termination. So your strings are invalid.
You need code like:
nums[some_index] = '\0'; // Add zero-termination
Alternatively you can start by initializing the whole array to zero. Like:
char nums[5] = {0};
char letters[3] = {0};
Missing bounds checks
Your loop is a for-loop using strlen as stop-condition. Now what would happen if I gave the input "123456789BBBBBBBB" ? Well, the loop would go on and i would increment to values ..., 5, 6, 7, ... Then you would index the arrays with a value bigger than the array size, i.e. out-of-bounds access (which is real bad).
You need to make sure you never access the array out-of-bounds.
No format check
Now what if I gave an input without any digits, e.g. "HelloWorld" ? In this case nothin would be written to nums so it will be uninitialized when used in atoi(nums). Again - real bad.
Further, there should be a check to make sure that the non-digit input is one of B, kB, mB, or gB.
Performance
This is not that important but... using memmove for copy of a single character is slow. Just assign directly.
memmove(&nums[i], &input[i], 1); ---> nums[i] = input[i];
How to fix
There are many, many different ways to fix the code. Below is a simple solution. It's not the best way but it's done like this to keep the code simple:
#define DIGIT_LEN 4
#define FORMAT_LEN 2
int bitLength(char *input)
{
char nums[DIGIT_LEN + 1] = {0}; // Max allowed number is 9999
char letters[FORMAT_LEN + 1] = {0}; // Allow at max two non-digit chars
if (input == NULL) exit(1); // error - illegal input
if (!isdigit(input[0])) exit(1); // error - input must start with a digit
// parse digits (at max 4 digits)
int i = 0;
while(i < DIGITS && isdigit(input[i]))
{
nums[i] = input[i];
++i;
}
// parse memory format, i.e. rest of strin must be of of B, kB, mB, gB
if ((strcmp(&input[i], "B") != 0) &&
(strcmp(&input[i], "kB") != 0) &&
(strcmp(&input[i], "mB") != 0) &&
(strcmp(&input[i], "gB") != 0))
{
// error - illegal input
exit(1);
}
strcpy(letters, &input[i]);
// Now nums and letter are ready for further processing
...
...
}
}
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);
This question already has answers here:
What does void* mean and how to use it?
(10 answers)
Closed 5 years ago.
I'm trying to make a calculator that takes a void pointer called yourVal, look at the first byte and decide if it's a '*' or '/'. Based on the sign, i multiply bytes 3+4, 5+6, and 7+8. say i have *1234567. I multiply 23 * 45 * 67. With the division, I divide byte 5(45) by byte 3(23). I'm a novice with pointers in C, and I really have no idea how to even set a value to a void pointer. When I do the following in main
void *yourVal;
*yourVal = "*1234567";
printf("%s\n", yourVal);
I'm not able to dereference a void pointer. But I tried with a char pointer, and I have the same issue.
This is my code for the calculator function. Based on whether I use printf or not, I get different results.
int calculator(void *yourVal){
char *byteOne;
short int *byteThree, *byteFive, *byteSeven;
int value;
byteOne = (char *)yourVal;
byteThree = (short int *)yourVal+2;
byteFive = (short int *)yourVal+4;
byteSeven= (short int *)yourVal+6;
if(*byteOne == '*') {
value = *byteThree * *byteFive * *byteSeven;
printf("You multiplied\n");
}
else if(*byteOne == '/') {
if (*byteThree == 0) {
value = 0xBAD;
printf("Your input is invalid\n");
}
else {
value = *byteFive / *byteThree;
printf("You divided\n");
}
}
else {
value = 0xBAD;
printf("Your input is invalid\n");
}
}
The division isn't working at all, and the multiplication only grabs one digit. Any tips would be appreciated. I looked at various sources but I'm not seeing how to work with void pointers efficiently. Also, I can't use any library functions other than printf, and this is a school assignment, so try not to give too many spoilers or do it for me. We were given one hint, which is to cast yourVal to a structure. But I'm lost on that. Thanks
byteOne = (char *)payload;
byteThree = (short int *)yourVal+2;
byteFive = (short int *)yourVal+4;
byteSeven= (short int *)yourVal+6;
This doesn't do what you think it does. If you want to read the numbers at these positions, you need to do something like.
char* Value = yourValue;
unsigned byteOne, byteThree, byteFive, byteSeven;
byteOne = Value[0] - '0';
byteThree = Value[2] - '0';
byteFive = Value[4] - '0';
byteSeven = Value[6] - '0';
What I have done here is read the byte at that position and subtract the ASCII value of '0' to get the numerical value of that character. But again this will work only for a single character.
If you need to read more characters you will have to use library functions like sscanf or atoi.
The void pointer adds no functionality you need to solve this problem, it just complicates things. Use a char pointer instead.
"*1234567" is a string, not an array of integers. You cannot treat it as an array of integers. Each character would have to be converted to an integer before you do arithmetic. The easiest way to do that is to subtract by the ASCII character '0'.
"...i multiply bytes 3+4..." When counting bytes, you always start at 0. In the string "*1234567", the 2 is the byte with index 2 not 3.
"Based on the sign, i multiply bytes 3+4, 5+6, and 7+8. say i have *1234567. I multiply 23 * 45 * 67. With the division, I divide byte 5(45) by byte 3(23)"
I fail to see how this algorithm makes any sense. What is the 1 there for? Why aren't you using some conventional formatting such as prefix, postfix or just plainly typed-out equations?
Example:
int calculator (const char* yourVal)
...
int byte2 = yourVal[2] - '0';
Hi i came across with this simple c program but i cant understand how this code works:
#include <string.h>
#include <stdio.h>
char *a = "\0hey\0\0"; /* 6 */
char *b = "word\0up yo"; /* 10 */
char *c = "\0\0\0\0"; /* 4 */
int main(void)
{
char z[20];
char *zp = z;
memcpy(zp, a, strlen(a)+1);
memcpy(zp, b, strlen(b)+1);
memcpy(zp, c, strlen(c)+1);
/* now z contains all 20 bytes, including 8 NULLs */
int i;
for(i = 0; i < 20; i++){
if (z[i] == 0){
printf("\\0");
}
printf("%c", z[i]);}
return 0;
}
I was expecting that printing z the output would be :
\0hey\0\0\0word\0up yo\0\0\0
But instead I am getting :
\0ord\0\0\0\0\0\0\0\0\0\0\0\0???Z
Finally , when i print a instead of z i get the right output.
Can anyone explain to me why this happens ? Thanks in advance.
EDIT: How i could concatenate such strings?
Strings in C are zero-terminated; the functions in the standard C library assume this property. In particular, the function strlen returns the number of non-zero characters from the start of the string. In your example, strlen(a) is equal to 0, already as the first character of a is zero.
The code will have the following effect:
memcpy(zp, a, strlen(a)+1);
Now zp still contains \0, because strlen(a) is 0, so 1 character is copied.
memcpy(zp, b, strlen(b)+1);
Now zp contains word\0: five characters copied.
memcpy(zp, c, strlen(c)+1);
Now just the first character of zp is overwritten, so it contains \0ord\0.
Finally , when i print a instead of z i get the right output. Can anyone explain to me why this happens ? Thanks in advance.
That's because a, b, and c happen to be allocated sequentially in the memory. When you print "20 bytes starting from the start of a", you're actually looking at the memory past the latest byte of a. This memory happens to contain b. So you actually start reading b. Same goes for b and c. Note that this is by no means guaranteed. Looking past the memory allocated for a char * is in fact an instance of undefined behaviour.
How i could concatenate such strings?
In general, there is no way how to find the length of such "strings" in the runtime. I would not call them strings as such, since "string" has a specific meaning in the C language - it refers to zero terminated strings, while your's are simply regions of memory.
However, since you know the size at compile time, you can use that. To avoid magic numbers in the code, it's better to use char arrays instead of char pointers, because then you can use the sizeof operator. However, note that all string literals in C are implicitly zero terminated! To fit the result in the 20-byte buffer, you'll want to use sizeof(x) - 1:
char a[] = "\0hey\0\0"; /* 6 */
char b[] = "word\0up yo"; /* 10 */
char c[] = "\0\0\0\0"; /* 4 */
memcpy(zp, a, sizeof(a) - 1);
zp += sizeof(a) - 1;
memcpy(zp, b, sizeof(b) - 1);
zp += sizeof(b) - 1;
memcpy(zp, c, sizeof(c) - 1);
I'm experiencing some troubles with my code written in C. It's all about an int * vector intially declared and dynamically allocated but when it comes to filling it with data it stuck on the first element and won't increment the counter to fill the rest of the vector
my header file : instance.h
struct pbCoupe
{
int tailleBarre;
int nbTaillesDem;
int nbTotPcs;
int * taille;
int * nbDem;
};
my code : coupe.c
pb->taille = (int*) malloc (pb->nbTaillesDem * sizeof(int));
pb->nbDem = (int*) malloc (pb->nbTaillesDem * sizeof(int));
while (i < pb->nbTaillesDem)
{
fscanf_s(instanceFile,"%s",data,sizeof(data));
pb->taille[i] = atoi(data); //<-- here is the problem !! it only accept the first value and ignore all the rest
printf("%s\n",data);
fscanf_s(instanceFile,"%s",data,sizeof(data));
pb->nbDem[i] = atoi(data); //<-- the same problem here too !!
printf("%s\n",data);
i++;
}
Your interpretation of sizeof is wrong, since data is the buffer that the string is being parsed into.
It returns the size of the the variable, not the size of the the what the variable (or namely a pointer) points to
Strings in C are all pointer to the size would be 4 bytes on a 32-bit system, 8 on a 64-bit.
Since it prints all the number it reading more numbers that intended with each loop iteration 4 bytes = 4 characters, atoi on parses the first integer and returns,
EDIT: If it is a buffer array, sizeof returns the size of the array.
You need to make sure you are only reading in a single number per iteration of the loop to solve this issue.
If you don't care for the literal string, best thing you can do is use:
fscanf(instanceFile, "%d", ((pb->taille) + i)));
//and store the integer into the index right away
//last param same as &pb->taille[i]