LinuxQuestions.org

LinuxQuestions.org (/questions/)
-   Programming (https://www.linuxquestions.org/questions/programming-9/)
-   -   Learning C - reviews would be good (https://www.linuxquestions.org/questions/programming-9/learning-c-reviews-would-be-good-4175723233/)

timl 03-19-2023 11:17 PM

Learning C - reviews would be good
 
Hi all, after a career of pascal and fortran I am trying to reinvent myself as a C programmer. I start a new/old fortran job shortly but they do use a bit of C so hoping to get involved and learn.

During my recent job search I tried for a C job which required a test. I failed miserably. I remembered some of the questions and I thought it would be a good idea to work on these.

The first is to remove the first '5' from an integer. So 1525354 becomes 125354 while -1525354 becomes -152534. Assume 5 is included in the input. I came up with the following. Any comments would be appreciated however brutal :)

TIA

Code:

#include <stdio.h>
 #include <stdlib.h>
 #include <string.h>
 #include <stdbool.h>

void strrev(char *str) // turn a character string back to front
{
    char *end, tmp;

    end = str + strlen(str) - 1;

    for (; end > str; --end, ++str) {
        tmp = *end;
        *end = *str;
        *str = tmp;
    }
}
void flipper ()

// remove the first '5' from a number. So 1525354 becomes 125354 while
// -1525354 becomes -152534. Assume 5 is included in the input

{
  int original=1;
  int i, j;
  bool nego;
  bool found;
  char tstr[20];
  char* tptr;
  char* nptr;
  char match[] = "5";

  while (original != 0)              // Some exit criteria
  {
    printf("Enter an integer: ");    // Ask for a number
    scanf("%d", &original);
    sprintf( tstr, "%d", original);  // push the number into a string
    nego=(original < 0);
    if (nego==true)                  // different behaviour for a -ve number
    {
        sprintf( tstr, "%d", abs(original));
        strrev( tstr);              // reverse the digits
    }
    tptr=tstr;

    nptr = (char*)malloc(strlen(tptr)-1); // somewhere to hold the new string

    i=0;
    found=false;
    while (*tptr)                    // search for the digit to be removed
    {
      if ( (strstr(tptr, match) == tptr) &&
            (found==false) )
      {
        found=true;
        tptr++;
      }
      else
      {
        nptr[i++] = *tptr++;        // this is not the digit so save it
      }
    }

    if (nego == true)                // if this was a negative number
    {                                // reverse again and make negative
        strrev( nptr);
    }
    sscanf(nptr, "%d", &j);
    if (nego == true)
    {
        j = (-j);
    }
    printf("and we get %d\n", j);
  }
}
int main()  // declare main as int.
{
 
  flipper();
  return 0;
}


NevemTeve 03-20-2023 12:34 AM

> The first is to remove the first '5' from an integer. So 1525354 becomes 125354 while -1525354 becomes -152534.

What does `first` mean? Leftmost for positive and rightmost for negative?

timl 03-20-2023 12:55 AM

Quote:

Originally Posted by NevemTeve (Post 6418855)
> The first is to remove the first '5' from an integer. So 1525354 becomes 125354 while -1525354 becomes -152534.

What does `first` mean? Leftmost for positive and rightmost for negative?

That's a good way to describe it. Yes

NevemTeve 03-20-2023 02:21 AM

Maybe you could create two functions that work in-place
Code:

void remove_first_occurance(char haystack[], char needle);
void remove_last_occurance (char haystack[], char needle);

calling:
Code:

    sprintf(buff, "%d", num);
    if (num<0) remove_last_occurance (buff, '5');
    else      remove_first_occurance(buff, '5');


sundialsvcs 03-20-2023 08:45 AM

I would pursue @NevemTeve's strategy. You don't actually need to copy the string value somewhere else in order to remove a character from it. You simply use a loop to walk through the string in one direction or the other until you find the '5' which the test-question promises does exist. Then, you use strcpy() to copy the string at "position n+1" to "position n," where "n" is your cursor-position.

The two function calls, which I would keep for clarity, could then be reduced to a single one in which the for-loop parameters (start, end, increment) are supplied as arguments.

rtmistler 03-20-2023 11:25 AM

Quote:

Originally Posted by timl (Post 6418845)
Hi all, after a career of pascal and fortran I am trying to reinvent myself as a C programmer. I start a new/old fortran job shortly but they do use a bit of C so hoping to get involved and learn.

During my recent job search I tried for a C job which required a test. I failed miserably. I remembered some of the questions and I thought it would be a good idea to work on these.

As a career programmer, what's the first thing you do when presented with a programming problem? (And I mean, before you write any code whatsoever) hint, that's likely more why you failed in the interview.

Given your FORTRAN background, that's old, so maybe you know assembler.

What exactly does a program do?

Read/modify memory
Test, and branch
You can have all the bells and whistles you want, but in the end, that's what the ALU is doing.

My humble opinions:
FORTRAN is a step above BASIC.
Pascal is a little more plain language than FORTRAN
C is just a bit further.

It's all syntax differences, nothing more.

sundialsvcs 03-20-2023 07:22 PM

(Shrug ...) "To me, I'm just a programmer. Pascal, FORTRAN, COBOL, C, C++, Java, JavaScript, PHP, Perl, Python, Prolog ... "dear god, I've lost count."

If you have that kind of "industry experience," I would go right back to this prospective employer and tell them: "so what if I 'failed your (online??) test!'" Because I think that this is the most-correct assessment of the situation. Reach out to a human being who will instantly understand that "Pascal and FORTRAN" are extremely relevant and that they should be anxious to hire you.

Always remember that, in the present "on-line environment," companies tend to use "on-line 'assessments'" to screen candidates. But, if you actually have the skills that are actually required, as you very obviously do, "don't take 'no' for an answer."

In any "real world" job situation, "you can never(!) confine yourself to 'just one [programming language][database][web-framework][yada-yada-yada].'" Nor to [just one] anything-else. You seem to have the experience to understand this. "Therefore, I see that you are not twenty-two years old ..." :)

timl 03-20-2023 08:14 PM

Thanks for all the constructive feedback which I am now digesting. When I have worked out a way forward I'll post it up.

Cheers

GazL 03-24-2023 09:45 AM

Quote:

Originally Posted by sundialsvcs (Post 6418935)
Then, you use strcpy() to copy the string at "position n+1" to "position n," where "n" is your cursor-position.

strcpy() can't be used on overlapping buffers. memmove() would work, but depending on how it's implemented it might involve an intermediate buffer anyway.

Unless the buffers are very large, it might be easier and more efficient to just use two buffers.


Here's one solution:
Code:

// remove_digit.c

#define _POSIX_C_SOURCE 200809L

#include <stdlib.h>
#include <stdio.h>
#include <string.h>

int remove_digit( int n, char digit )
{
        // if 'n' is positive: remove the first occurrence of 'digit'.
        // if 'n' is negative: remove the last occurrence of 'digit'.

        char in_buf[16];
        char out_buf[16];
        char *digit_ptr;

        if ( digit < '0' || digit > '9' )
                return n;

        sprintf(in_buf, "%d", n);

        if ( n < 0 )
                digit_ptr = strrchr(in_buf, digit);
        else
                digit_ptr = strchr(in_buf, digit);

        if ( digit_ptr )
        {
                *digit_ptr++ = '\0';

                char *dst = out_buf;
                dst = stpcpy(dst, in_buf);
                dst = stpcpy(dst, digit_ptr);
                n = atoi(out_buf);
        }

        return n;
}


int main( int argc, char *argv[] )
{
        for ( int i = 1 ; i < argc ; i++ )
        {
                int n = atoi(argv[i]);
                printf("Arg: %11d  Result: %11d\n", n, remove_digit(n, '5'));
        }

        return 0;
}

... but they'd probably not give me the job either. ;)

stpcpy() is a POSIX function, not standard C, but it could be replaced with a slightly less efficient strcpy() + strcat() if sticking to standard C is important to you.

sundialsvcs 03-24-2023 12:27 PM

As I've said: "if you have 'a career in Pascal and FORTRAN,'" any on-line test which "disqualifies you" is blowing smoke. Just punch through the outer curtains and talk to the hiring manager(s). These "outer obstacles" very clearly should not apply to you. You could easily adapt yourself to "the new language" within a matter of days upon the job. Because you clearly understand the essentials. As any hiring manager would immediately understand.

In my own long-and-strange experience, I have literally lost count of the "languages" I have used: 6080/6502/8080/Z80/650x0 assembler, Forth, Pardox[for DOS and then for Windows], dBase, FoxPro, C, C++, FORTRAN, COBOL, PHP(x), Perl, Python, Prolog/gnuProlog, Pascal/Delphi, ColdFusion(!), "I must have missed something." But you get the point.

No matter how "different" it may seem, in reality it is very much the same. "In the end, it's only ones and zeros." Give me a problem to solve, and a machine/language to do it with, and I can solve it and guarantee the results. (Hire me.) ;)

Racho 03-24-2023 02:33 PM

Just a word of advice about sprintf and strcpy.

If the input array is longer than the destination these functions will continue overwriting happily whatever they find in memory until the end of the string.

For a safer program use snprintf and strlcpy instead.


Let's see a little program that shows this behavior:

Code:

#include <stdio.h>
char a_short_string[30]="Something to overwrite";
char next_string[150]="Here we have really important information!";
int main()
{     
        char too_long_message[]="123456789012345678901234567890 Oh my God! this"
              " message is too long to fit in that short string!!";
        sprintf(a_short_string, "%s\n", too_long_message);
        printf("short_string %s\n", a_short_string);
        printf("next_string: %s\n", next_string);
        return 0;
}

If the compiler has allocated next_string just after a_short_string (it may do that but you can't be sure) then you will lose your important information.
If you keep your important information that is just because the program has overwritten another information in memory.

Of course there is no problem with strcpy or sprintf if you are really sure that the message will fit in the destination array but this is not often the case.

EdGr 03-24-2023 02:41 PM

Years ago, I wrote a library that does all the string processing that my programs need. The library makes programs immune to off-by-one bugs, buffer overruns, truncation, and read-write collisions on strings. I never have to worry about those. :)

timl - Find or write a good string library.
Ed

sundialsvcs 03-24-2023 06:01 PM

@EdGr: And if at all possible, an excellent place to begin is C++, which has a well-behaved String type. As well as an excellent selection of "container classes."

The "C" language was "a fantastic advance from [necessarily hardware-specific] 'assembler language,'" but really not that much of one. These days, there's not that much "byte-twiddling" that you should expect to have to deal with, just to get things done. Especially if other people have :banghead: "already done it for you."

Incidentally, the C++ language is actually so close to C that its original implementation was a "source-code preprocessor." There is no "performance penalty" to be paid. It's simply better. Cleaner. Easier.

chrism01 03-28-2023 12:17 AM

Perhaps strtok() could be used https://www.tutorialspoint.com/c_sta...ion_strtok.htm

scasey 03-28-2023 12:52 AM

Yes. The last position for which I was hired used a tool I had never even heard of. It (Informatica) was used to define ETL (extract, transform, load) processes (programs). The hiring manager offered me a job because he understood that my extensive experience would make it possible for me to be an asset to his organization. As has been said, it’s all about syntax differences. I became the technical lead and worked for them for about 8 years until I retired.

I once had a youngster ask me how it was that I could “see” the solution to a problem so easily. I told them i had begun learning logic wiring punched card accounting machine (PCAM) boards. Syntax.

So yes. Talk to the hiring manager. You are a programmer and (probably) an analyst. The language doesn’t matter.


All times are GMT -5. The time now is 04:05 PM.