2

We have two simple function.

#include <stdio.h>

 /* first approach */
int power1(int *ptr)
{
     return *ptr * *ptr;    
}

/* second approach */
int power2(int *ptr)
{
    int tmp = *ptr;
    return tmp*tmp;    
}

int main()
{
    int val = 5;

    printf("%d\n", power1(&val));
    printf("%d\n", power2(&val));

    return 0;
}

Which one is better? power1 is a little bit faster, but I have heard that power2 is more safety. I do not remember why? As far as I remember there is one case when power1(first approach) has bottleneck. Could you explain it? Does safety critical systems use second approach?

user3483899
  • 103
  • 1
  • 5
  • 1
    *power1 is a little bit faster* – If you claim that, where is your code that tests that? No-nonsense-compilers should generate the same code for both functions. – Swordfish Feb 21 '19 at 08:01
  • 2
    What is the reason you want to pass pointers? In this specific case it is pointless (pun not intended). – Some programmer dude Feb 21 '19 at 08:02
  • the only reason to pass pointer is to achieve val = val*val without using any more variables in your main code. In that case you can use void power(int * a){*a = *a * *a;} – com Feb 21 '19 at 08:54

4 Answers4

6

None is good. You want this:

#include <stdio.h>

/* second approach */
int power(int operand)
{
    return operand*operand;    
}

int main(void)
{
    int val = 5;    
    printf("%d\n", power(val));
}

Now concerning your two approaches:

power2 is in no way "safer" than power1.

BTW:

A correct way to declare main is int main(void) and the return 0; at the end of main is not necessary, if main doesn't containt a return statement, there is an implicit return 0; at the end of main.

Jabberwocky
  • 48,281
  • 17
  • 65
  • 115
2

Which one is better?

They are equally good/bad

power1 is a little bit faster

If you compile without any optimization then "yes, power1 may be a little faster" but as soon as you turn on compiler optimization, they will (for any decent compiler) be equal.

but I have heard that power2 is more safety

That's wrong. Using the variables from the argument list is just as safe as using local variables.

Does safety critical systems use second approach?

No reason for doing that. However, use of pointers are banned in some safety critical systems. In you particular case it would be better to pass the integer directly instead of passing a pointer.

Another thing related to "safety" is integer overflow. Your code doesn't protect against integer overflow and integer overflow is undefined behavior. So that could be something to consider for safety critical systems.

Support Ukraine
  • 42,271
  • 4
  • 38
  • 63
1

I wish I knew what "safety" is supposed to mean here (I saw your comment that you got this from an interview, and that the interviewer did not explain what he meant by that).

There are only 4 reasons why a function should receive a pointer as a parameter:

  1. The function is meant to update the parameter;
  2. The parameter is an array expression, which is automatically converted to a pointer expression when passed as a function argument;
  3. The parameter is a very large struct or similar aggregate type, and creating a local copy is deemed too expensive;
  4. The parameter was created via malloc, calloc, or realloc.

None of these should apply to the snippets you posted. The "safest" option for them is to not use a pointer at all.

One "unsafe" aspect of using a pointer is that you may intend for the input to be read-only, but because you've been passed a pointer, you are able to modify the input. For those cases, you want to const-qualify that parameter:

void foo ( const char *str ) // we cannot modify what str points to
{
  ...
}

Another "unsafe" aspect of using a pointer is accidentally (or deliberately) updating the pointer value itself to access memory you shouldn't:

while ( *ptr )
  do_something_with( ptr++ );

You can mitigate against this by declaring the pointer as const:

void bar( int * const ptr ) // we cannot update the value in ptr

This doesn't stop you from using the [] subscript operator, though:

while( ptr[i] )
  do_something_with( ptr[i++] );

Now, if your interviewer was thinking of multiple threads or some machine-level issue with respect to interrupts or volatility, then maybe he has a point - if there's something that that can modify the thing ptr points to outside of the current thread of execution's control, then yes, the second method is "safer" in that respect (the pointed-to value won't change in the middle of the computation).

However, if the code is multithreaded and ptr can be modified in different threads, access to it should be synchronized via a mutex or something. If ptr can be updated outside of your program's control, it should have been declared volatile:

int power1( volatile int *ptr ) { ... }
int power2( volatile int *ptr ) { ... }
John Bode
  • 119,563
  • 19
  • 122
  • 198
-1

In power1 there will dereferencing 2 times - there will be 2 memory look ups related to dereferencing.

In power2 There will be dereferencing, but only once. Only in the statement int tmp = *ptr;.

So, power1 might be inefficient if looking this way in terms of speed.

This is based on assumption if you have compiler optimisations turned off.

Syed Waris
  • 1,056
  • 1
  • 11
  • 16
  • 1
    You really cannot make those kinds of assumptions about the code without inspecting the compiler's output. There is no requirement in the language that the code results in any particular number of memory "look ups". Also, caches. – unwind Feb 21 '19 at 09:34
  • The memory lookup is not an assumption. I meant this: When dereferencing a pointer, first you take the variable's value from the variable's identifier. And then next you take this value as the address and again go to fetch the value at that address – Syed Waris Feb 21 '19 at 09:37
  • 1
    There is no requirement that this code results in a memory lookup. An optimizing compiler can make that go away. – unwind Feb 21 '19 at 10:02