I am writing two ASCII char arrays to an LCD screen perfectly fine. However I need an if-condition to compare these two values.
Originally I attempted to simply compare them like this:
if(currentTemp < triggTemp)
{
alarmTriggered = true;
}
As this didn't work, I am attempting to convert them to floats from their ASCII strings using atof().
However this doesn't seem to want to work either, am I missing something silly here? Necessary code below:
void main () {
char triggTemp;
int buttonBool = 0;
bool alarmTriggered = false;
char currentTemp;
double f_triggTemp = 0;
double f_currentTemp = 0;
TRISC = 0x00;
init();
Init_lcd();
while(1)
{
//char bufferString[4];
currentTemp = get_temp();
f_currentTemp = atof(currentTemp);
f_triggTemp = atof(triggTemp);
if(f_currentTemp < f_triggTemp)
{
alarmTriggered = true;
}
if(alarmTriggered == true)
{
soundBuzzer();
}
}
The values are being returned from functions in this form:
//some function
char bufferString[4];
sprintf(numberString, "%s.%s", itoa(bufferString,setTemp,10),
itoa(bufferStringDec,setTempDec,10));
return numberString;
In essence, I am trying to compare these char arrays of ASCII characters so I can use an if condition to trigger an alarm.
I tried to keep the code snippets short, I can clarify on request. Thanks for any help.
EDIT: I know I'm using atof into double variables; the prototype in my library is set up like that.
I think this is what you are doing:
char* some_function() {
char temporary_string_buffer[32]; // Or some other fixed size
snprintf(temporary_string_buffer, 32, "some format");
return temporary_string_buffer;
}
You can't do that. OK, you can do that -- you probably just did -- but it has Undefined Behaviour, because the lifetime of temporary_string_buffer ends with the return statement. In the caller, the function will be returning what's colloquially known as a "dangling pointer"; in other words, a pointer whose target no longer has any meaning. So by the time you get around to calling atof on that value, it may have been used for something completely different.
If you want to return a string to the caller, either:
Dynamically allocate the string with malloc and make sure the caller knows that they need to free it; or
Get the caller to give you the address of a buffer and its length (as arguments), and fill in the supplied buffer. You can use the return code for a success indicator, or (like sprintf) as a count of bytes, or whatever.
char currentTemp; ... atof(currentTemp); will not work. double atof(const char *nptr) expects a pointer to a string, not a char.
Create a function to do the compare for you. Here is a complete test program. You just compare the array element one by one.
int is_greater(char a[], char b[], int z, int z1) {
int i = 0;
for( i = 0; i < z; i++ ) {
if( a[i] > b[i] ) return 1;
}
return 0;
}
Related
I'm working on the exercises in K&R's book, and I've run into a weird bug while trying to extend 04-06 to allow for variables with string names. Truthfully, I've actually managed to fix the bug (pretty simple - explained below), but I'd like to know why the error was occuring in the first place.
For those unfamiliar with the problem, you're basically asked to create a command-line calculator (using Polish notation) that can store and recall variables with character names.
Here's the relevant code where the issue occurs:
#define MAXOPLEN 1000
int varCount = 1;
char **keys;
char **values;
// changing the declaration to:
// char strOps[][STROPCOUNT] = { ... };
// fixed the issue
char *strOps[STROPCOUNT] = { "dupe", "swap", "del", "print",
"clr", "sin", "cos", "tan",
"exp", "pow", "ln", "log",
"mem", "re"};
main() {
keys = malloc(varCount * sizeof(char[MAXOPLEN]));
keys[0] = "ans";
values = malloc(varCount * sizeof(char[MAXOPLEN]));
values[0] = "0.0";
... // Other stuff related to the program
}
// flag is unrelated to the problem I'm asking about. It just checks to see
// if the variable name used to store value n is 'ans', which is where
// the last returned value is stored automatically
void memorize(char s[], double n, bool flag) {
... // small conditional block for flag
for (i = 0; i < varCount; i++) {
if (equals(keys[i], s)) {
found = True;
// Next line is where the program actually breaks
snprintf(values[i], MAXOPLEN, "%f", n);
break;
}
}
if (!found) {
i = varCount;
varCount++;
keys = realloc(keys, varCount * sizeof(char*));
keys[i] = malloc(sizeof(char[MAXOPLEN]));
keys[i] = s;
values = realloc(values, varCount * sizeof(char*));
values[i] = malloc(sizeof(char[MAXOPLEN]));
snprintf(values[i], MAXOPLEN, "%f", n);
}
}
After compiling and running, the first time you enter in an equation to calculate, everything seems to run smoothly. However, while debugging, I found out that the first three char* in strOps were oddly made to point to different addresses. When trying to save the return value of the equation to "ans", it enters the for-loop in memorize() that tries to see if string s had been used as a key name already. It correctly finds keys[0] to point to a string matching s's value ("ans"), then attempts to convert double n to a string and save it in values[0].
While inside the snprintf() function, the first three char* in strOps are made to point elsewhere inside this method in corecrt_stdio_config.h:
_Check_return_ _Ret_notnull_
__declspec(noinline) __inline unsigned __int64* __CRTDECL __local_stdio_printf_options(void)
{
// Error occurs after this next line:
static unsigned __int64 _OptionsStorage;
return &_OptionsStorage;
}
As commented in the code above, making strOps a 2D array of characters (rather than an array of char pointers) fixed the issue. This makes sense because arrays of characters can't have the values of individual characters changed, but what I don't understand is why the that method in corecrt_stdio_config.h was changing the values of those three pointers in the first place.
Thanks!
Your initializations are incorrect and are causing the change:
keys[0] = "ans";
values[0] = "0.0";
Both "ans" and "0.0" are string literals and cannot be used to initialize the arrays, you need to use strcpy after you allocate.
strcpy (keys, "ans");
strcpy (values, "0.0");
Your other option is to assign one character at a time:
size_t i;
char *p = "ans";
for (i = 0; i < strlen (p); i++)
keys[i] = p[i]; /* copy to keys */
p[i] = 0; /* nul-terminate */
note: these are examples of your errors, you do the same thing throughout your code.
I'm writing a parser for propositional logic (doesn't matter what that is, main point is I'm parsing a simple language) and initially started out with functions of the following form:
int formula() {
int store = step;
if(compound())
return TRUE;
else {
if(atom())
return TRUE;
else if(negation() && formula())
return TRUE;
else {
step = store;
return FALSE;
}
}
}
int compound() {
int store = step;
if(open() && formula() && binary_operator() && formula() && close())
return TRUE;
else {
step = store;
return FALSE;
}
}
The functions above not mentioned are base cases - these are the important parts. Formulas can have sub-formulas, and these sub-formulas in turn can be compound formulas, which contain sub-formulas, and so on.
Instead of ints though, I'm trying to return char sequences of 1s and 0s (true and false). If you return a sequence, it means that the input can generate a sequence (it must be valid). Otherwise, return null.
The issue is that every time I've tried the pointers keep getting lost - I understand this is to do with the stack(?) and the pointer sort of 'dies' when the function returns whatever. I've not tried arrays because I have been told that arrays work best statically, whereas the size of these arrays would be dynamic (size is determined by number of variables, which is only found at runtime).
Is there any way this approach can be done? I can't malloc anything because I won't be able to free it - the sequence of 1s and 0s needs to be returned before I'd be able to free it. Maybe pass structs with a sequence field, although I'm not sure if that suffers from the same issue.
Any help much appreciated. This is a program using C99. Any advice on clarifications welcome!
I'm not entirely following what you want to do, but there is not a clear reason why you couldn't use malloc. The pointer returned by malloc can be freed by another function later. Consider the following valid code:
char* foo(size_t* length)
{
*length = 3;
char* seq = malloc(*length);
seq[0] = 1;
seq[1] = 0;
seq[2] = 1;
return seq;
}
int main()
{
size_t length;
char* seq = foo(&length);
/* use seq */
free(seq);
}
You can also do it without malloc if you know an upper bound for your sequence. By passing a pointer to space you allocated on the stack from main(), you won't lose the data when the function exits:
void foo(char* seq, size_t total_size, size_t* used_size)
{
*used_size = 3;
seq[0] = 1;
seq[1] = 0;
seq[2] = 1;
}
int main()
{
size_t used_size;
char seq[100];
foo(seq, sizeof(seq), &used_size);
/* use seq */
}
I finally managed to make my regex function work, but I want to know if I can possibly reduce the number of pointer declarations in the main function to one. For example, I want to convert:
int main(){
regex* r=calloc(1,300000);
regex* rr=r;
if (regexmatch("T/2/b","([A-Z]+)/([0-9]+)/([a-z]+)",10,&rr)==0){
printres(r);
}
free(r);
return 0;
}
to something like:
int main(){
regex* r=calloc(1,300000);
if (regexmatch("T/2/b","([A-Z]+)/([0-9]+)/([a-z]+)",10,&r)==0){
printres(r);
}
free(r);
return 0;
}
but as it stands, this won't work because the regexmatch function seems to change the address of the variable which causes the program to crash at free(r);
I even tried adding reg=rp; just before the last return statement in the function in hopes that I reset the struct variable address to what it was when the function was first called, but that didn't work.
What can I do to fix this? or is my only option to use two pointers in my main function?
This is my code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <sys/types.h>
#include <regex.h>
typedef struct{
char str[1000];
} regex;
long regexmatch(const char* str,const char* regexs,const size_t nummatch,regex** rp){
regex** reg=rp;
regex_t r;regmatch_t match[nummatch];
if (regcomp(&r,regexs,REG_EXTENDED) != 0){return -1;}
if (regexec(&r,str,nummatch,match,0)!=0){regfree(&r);return -1;}
regfree(&r);size_t i=0;
for (i=0;i<nummatch;i++){
if (match[i].rm_so > -1){
unsigned long sz=match[i].rm_eo-match[i].rm_so;
if (sz > 0 && sz < 1000){
memcpy((**reg).str,(char*)(str+match[i].rm_so),sz);
(*reg)++;
}
}
}
(**reg).str[0]='\0';
return 0;
}
void printres(regex* r){
printf("Matches\n");
while (r->str[0] != '\0'){
printf("%s\n",r->str);
r++;
}
}
int main(){
regex* r=calloc(1,300000);
regex* rr=r;
if (regexmatch("T/2/b","([A-Z]+)/([0-9]+)/([a-z]+)",10,&rr)==0){
printres(r);
}
free(r);
return 0;
}
Why do you pass rp by reference? You clearly don't want the value in the calling program to change, so it would be simpler to just pass it directly.
In fact, what you really want that parameter to be is an array of regex objects ([Note 1]). So instead of using the prototype
long regexmatch(const char* str,
const char* regexs,
const size_t nummatch, /* This const is pointless */
regex** rp);
it would make more sense to use:
long regexmatch(const char* str,
const char* regexs,
size_t nummatch,
regex rp[nummatch]);
(Effectively, that's the same as using regex* rp as a parameter, but writing it as rp[nummatch] is more self-documenting. Because you use an empty string as a terminator (which means that you can't handle zero-length captures), you actually need nummatch to be at least one greater than the number of captures in the pattern, so it is not 100% self-documenting.
Having made that change to the prototype, you need to remove one level of indirection in the function:
long regexmatch(const char* str,
const char* regexs,
size_t nummatch,
regex reg[nummatch]){
/* Compiling the regex is the same as in your code. I removed
* the assignment of reg from rp, since the parameter is now
* called reg.
*/
size_t i=0;
for (i=0;i<nummatch;i++){
if (match[i].rm_so > -1){
unsigned long sz=match[i].rm_eo-match[i].rm_so;
if (sz > 0 && sz < 1000){
memcpy(reg->str, (char*)(str+match[i].rm_so), sz);
/* The above memcpy doesn't nul-terminate the string,
* so I added an explicit nul-termination.
*/
reg->str[sz] = 0;
/* I think this should be outside the if statement. Personally,
* I'd put it in the increment clause of the for loop.
* See Note 2.
*/
reg++;
}
}
}
reg->str[0] = 0;
return 0;
}
(See it live on ideone.)
Notes
I found it confusing to call regex what is basically a fixed-length string representing a regex capture. Also, I don't see the point of wrapping the fixed-length character allocation in a struct, unless you plan to assign to values of type regex. But all of that is irrelevant to your basic question.
When you're copying captures into your regex array, you simply ignore captures which are empty, unset, or too long. This means that you cannot access capture i by looking at the ith element in the array. If a previous capture happened to be empty, then the capture will be at position i - 1 (or earlier, if more than one capture were empty), and the empty capture won't be accessible at all. I'm not sure exactly what your goal here is, but that seems hard to use. However, since you use empty strings to indicate the end of the capture list, you cannot insert an empty capture into the list. So you really might want to rethink the API.
A much cleaner approach would be to use an array of pointers to strings (like argv.)
In regexmatch add : regex* rp2=*rp;regex** reg=&rp2;
In your code (*reg)++; is modifying the value of rp. Its equivalent of rp++ in your code because regex** reg=rp;
rp is the pointer adress to your calloc set by &r in regexmatch call.
You dont want to change this pointer. So we use another pointer called rp2.
I'm trying to simulate passing by reference and apparently I'm doing something wrong:
long int toNumber(char * input) {
char* pointer;
long int number;
number = strtol(input, &pointer, 10);
if (number == 0L) {
return -1337;
} else {
input = pointer;
return number;
}
}
I'd like for this function to return the value of the input and trim the converted beginning of it, yet when I try calling it, even though the integer conversion is flawless, the string remains the same. Thanks for any kind of help.
Edit:
char* input = "123 456";
long int number = toNumber(input);
Edit 2: Changed back, sorry.
I'd like for it to work something like this:
input = 123 456 -> number = 123, input = 456 -> number = 456, input = NULL
It is not clear about the 1337 thing... however, this code should produce what the question code is attempting with simplified logic.
long int toNumber(char **input)
{
char *pointer;
long int number;
number = strtol(input, &pointer, 10);
if(number)
*input = pointer;
else
number = (1337);
return number;
}
Something like the following call the above function:
{
char *test="123 456";
long int n;
...
n = toNumber(&test);
printf("n[%ld] remainder[%s]\n", n, test);
...
}
Which should print:
n[123] remainder[ 456]
input is a pointer, which is passed by value to your toNumber function. Assigning a value to input merely changes the parameter object, which is local to the function. It has no effect on the caller.
To modify the string, you'd have to modify *input, or input[some_index], or pass input to some other function that will modify the data that it points to.
Note that updating a string in place is not necessarily a good idea. You can modify the characters that make up the string, but you can't increase the size of the array containing the string. And if the caller passes a string literal, then attempting to modify it has undefined behavior (and will likely crash your program).
Im trying to print out the part at the end of this program. I enter C17 and the part comes out as 0 when it should be 1. Why is this?
Kind Regards
Dennis
# include <stdio.h>
int Part;
int getPartType(int Part);
int calcPrice(int Part);
int main(int argc, char * argv[]){
getPartType(Part);
calcPrice(Part);
return 0;
}
// Part1: Asks for input from user for part type
int getPartType(int Part) {
int nvr;
char character_one;
char character_two;
int number;
printf("Enter the part type (C17, F25, DN3, GG7 or MV4): ");
nvr = scanf("%c%c%d",&character_one,&character_two,&number);
if (number==7 && character_two=='1') {
Part=1;
}else if (number==5 && character_two=='2') {
Part=2;
}else if (number==3 && character_two=='N') {
Part=3;
}else if (number==7 && character_two=='G') {
Part=4;
}else if (number==4 && character_two=='V') {
Part=5;
}else{
printf("Wrong Part Type\n");
Part=0;
}
return Part;
}
int calcPrice(int Part) {
printf("%d\n",Part);
return 0;
}
getPartType(Part); returns an int, and doesn't assign to the original Part. So you must change this line:
getPartType(Part);
to
Part = getPartType(Part);
If you want to change the original value of Part you must use pointers. You can read more about this in any decent C book (I recommend K&R). For example:
// takes pointer to integer and sets it to 5
void settofive(int *someInteger) {
*someInteger = 5; // dereference someInteger and set to 5
}
int main(int argc, char *argv[]) {
int test = 0;
int *ptrTotest = &test; // take address of test and store in ptrTotest
printf("%d\n", test); // prints out zero
settofive(ptrTotest);
printf("%d\n", test); // prints out five
return 0;
}
You have a little misunderstanding of function argument passing.
When you call a function like
getPartType(Part);
C will create a copy of Part on the stack and all computations within the function will be made on this copy. Therefore you will not change the variable Part. This is called Call-by-value.
To change this problem, there are two ways. You can either just use:
Part = getPartType(Part);
This will create a copy of Part, the function will work on this copy, and then return something. This something will then get stored in the original Part. In your case you can actually just use int getPartType(void) as the function declaration, because you don't work an Part.
The other way would be to pass a pointer:
getPartType(&Part);
This passes a pointer to the original Part, so you can manipulate the original part (using the *-operator). This would mean that your declaration shoudl like like void getPartType(int *). But I would say the first method is preferable if you are dealing with just one basic variable
C is call by value. This means that the function can't change the value of a variable in the caller's context, unless the caller passes the address of that value.
Since your function doesn't really need an input argument, it should be removed. All you need is the return value.
Also, you could consider using multiple return statements, changing the if-ladder to look like so:
if (number==7 && character_two=='1') {
return 1;
}else if (number==5 && character_two=='2') {
return 2;
and so on.
Further, the use of "magical" numerical constants is generally a bad idea. It would be better to introduce an enumeration before main(), like this:
enum Part { PART_C17 = 1, PART_F25, PART_DN3, PART_GG7, PART_MV4 };
Then change the function to return a value of this new type:
enum Part getPartType(void)
{
/* ... */
}
and update the code in the if-ladder accordingly:
if (number==7 && character_two=='1') {
return PART_C17;
}else if (number==5 && character_two=='2') {
return PART_F25;
and so on.