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.
Related
I have the below function which when called from main, returns a formatted filename (000.jpg) as a string when given an int. (I know we can use sprintf for this)
Initialising char fn[8] = "000.jpg" in main works.
When passed into function getfilename(), assigning indiv chars e.g. fn[4] = 'p'; works,
but it won't work if I assign fn = "000.gif"; I get a Bus error: 10
What am I doing wrong?
(The rest of the code works fine, and output is correct so long as I don't do the line: fn = "000.gif";
But I want to learn how to be able to manipulate the string when passed across functions)
#include <stdio.h>
#include <stdlib.h>
#include <math.h>
char *getfilename(int counter, char *fn);
int main(void) {
int counter=14;
char fn[8]= "000.jpg"; // this is fine
getfilename(counter, fn);
printf("%s\n", fn);
}
char *getfilename(int counter, char *fn) {
fn[7] = '\0';
fn[4] = 'p'; // this is fine
fn[5] = 'n';
fn[6] = 'g';
//fn = "000.gif"; // this will return Bus error: 10
// ITOA IMPLEMENTATION FOR 3-DIGIT FILENAME
int numOfDigits = log10(counter) + 1;
for (int i=numOfDigits-1; i>=0; i--, counter/=10) {
if (numOfDigits==1) {
fn[i+2] = (counter % 10) + '0';
fn[0] = fn[1] = '0';
}
else if (numOfDigits==2) {
fn[i+1] = (counter % 10) + '0';
fn[0] = '0';
}
else {
fn[i] = (counter % 10) + '0';
}
}
//////////
return fn;
}
Change fn = "000.gif" to strcpy(fn, "000.gif")
And a word of advice. It could be a good thing to change char fn[8]="000.jpg" to char fn[]="000.jpg". What if you use a longer string in the future. Will you remember to increase the size of the array?
On the other hand, if you know for certain that the size will never change, you could make the code a bit more robust with something like this:
struct filename {
char fn[8];
};
char *getfilename(int counter, struct filename *arg) {
char *fn = arg->fn;
// Keep the rest the same
}
int main(void) {
int counter = 14;
struct filename f = { "000.jpg" };
getfilename(counter, &f); // Note the &
printf("%s\n", f.fn);
That way, you would get warnings if you're trying to pass a random string to the function. Note that . and -> is basically doing the same thing, but the latter is used with pointers to struct. Also note that - unlike arrays - you don't have to pass structs via pointers. You can choose to pass the directly, just like variables. Same goes for returning and assigning them. I chose pointers in this case for no other reason than that I have to choose one.
Another option that's more convenient, although the syntax may seem a bit scary is this:
char *getfilename(int counter, char (*arg)[8]) {
char *fn = *arg;
// Keep the rest of the function
I actually wrote a question about that method right now: How do I force a warning from using an array of wrong size when passed to function?
Both methods have their pros and cons.
In this statement
fn = "000.gif";
you assigned the local pointer fn (function parameters are function local variables) with the address of the first character of the string literal "000.gif". And then you are trying to change the string literal as for example
fn[0] = fn[1] = '0';
Any attempt to change a string literal results in undefined behavior.
From the C Standard (6.4.5 String literals)
7 It is unspecified whether these arrays are distinct provided their
elements have the appropriate values. If the program attempts to
modify such an array, the behavior is undefined.
What you need is to change the content of the original array fn declared in main instead of changing the pointer fn declared as a parameter of the function getfilename. You can do it the following way
strcpy( fn, "000.gif" );
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 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;
}
I have this function
int rt_exist(struct route_entry* prev_rte) {
prev_rte = rte_head; //This doen't assigns rte_head to prev_rte
return 0;
}
where rte_head is an initialized struct route_entry* pointer variable.
But in the above case "prev_rte" is not assigned the value of rte_head.
By the way ,I if I do something like this
int rt_exist(struct route_entry* prev_rte) {
struct route_entry* rte_new;
rte_new = rte_head; //But this can
return 0;
}
The above assignment occurs smoothly . The problem arises when pointer variable is passes as function argument.
It's a weird question with little details ,but can someone point me to a possible direction or something wrong I might be doing.
Consider this:
void foo (int j)
{
j = 7;
}
foo (8);
What do you expect to happen here? A function can't change a value in the caller this way.
What should happen here:
rt_exist (NULL);
For C++, you can use references:
int rt_exist(struct route_entry*& prev_rte) {
prev_rte = rte_head; //This doen't assigns rte_head to prev_rte
return 0;
}
For C, you need to pass a pointer to the thing you want to change:
int rt_exist(struct route_entry** prev_rte_ptr) {
*prev_rte_ptr = rte_head; //This doen't assigns rte_head to prev_rte
return 0;
}
Yes! in first case you are using temporary portion of a stack. But in the second case you are using allocating. Which means that you are using a portion of memory which is from heap. It will obviously affect the value. This is like a new variable in a new block. In this scope it will have the assigned value.
But in rt_exist the copy of the variable is passed. So any change in that will not affect the actual one. But you can pass it's address and change it easily like this.
int rt_exist(struct route_entry** prev_rte)
{
*prev_rte = rte_head; //This does assign rte_head to prev_rte.
return 0;
}
First off, I know this should have been answered somewhere on SO but I just can't seem to find the correct post. So if it is a duplicate please point me to the post that answers this question and I will delete this.
I have a function that copies a string:
static int read_ad_content(json_t * root, char* content)
{
[.. stuff happens]
const char* tmp = json_string_value(json_content);
unsigned int size = strlen(tmp);
content = (char*)malloc(size + 1);
memcpy(content, tmp, size);
content[size] = '\0'; // <= I checked and content is NOT null here!
return 0;
}
And I call it like this in my main function:
char *ad_content;
if (read_ad_content(ad_json, ad_content) != 0)
{
log_err(argv, "Failed to extract information");
}
if (ad_content == NULL)
{
// <= I always end up here
}
I know this should be easy but I just don't know how to solve this.
In C, parameters are passed by value. What you're doing isn't any different from:
void brokenMethod(int a){
a = 10;
}
int a = 0;
brokenMethod(a);
if(a == 0)
{
//always end up here!
}
Of course you'll always end up there. a was never modified! The value of a was passed to brokenMethod, which could've done anything it wanted but that's not going to affect the value of a in your outer scope.
If I want the method to fill in an int, I have to pass it a pointer to an int.
void fixedMethod(int* a)
{
*a = 10;
//Remember, you want to modify the thing being pointed at, not the thing doing the pointing!
//a = something; is going to have the exact same problem as the first example
}
int a = 0;
fixedMethod(&a);
if(a == 0)
{
//Better
}
The above example sticks a value into an int. In your case, if you want the method to fill in a pointer to an int then you'll have to pass it a pointer to a pointer to an int.
Sidebar:
You may also find that methods which return values via parameters are difficult to reason about and more likely to contain bugs. If you're trying to return an pointer to an int, just have a method that returns a pointer to an int.
int* HonestMethod()
{
return pointer to whatever.
}