LinuxQuestions.org
Welcome to the most active Linux Forum on the web.
Home Forums Tutorials Articles Register
Go Back   LinuxQuestions.org > Forums > Non-*NIX Forums > Programming
User Name
Password
Programming This forum is for all programming questions.
The question does not have to be directly related to Linux and any language is fair game.

Notices


Reply
  Search this Thread
Old 03-19-2023, 11:17 PM   #1
timl
Member
 
Registered: Jan 2009
Location: Sydney, Australia
Distribution: Fedora,CentOS
Posts: 750

Rep: Reputation: 156Reputation: 156
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;
}
 
Old 03-20-2023, 12:34 AM   #2
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 4,862
Blog Entries: 1

Rep: Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869
> 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?
 
Old 03-20-2023, 12:55 AM   #3
timl
Member
 
Registered: Jan 2009
Location: Sydney, Australia
Distribution: Fedora,CentOS
Posts: 750

Original Poster
Rep: Reputation: 156Reputation: 156
Quote:
Originally Posted by NevemTeve View Post
> 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
 
Old 03-20-2023, 02:21 AM   #4
NevemTeve
Senior Member
 
Registered: Oct 2011
Location: Budapest
Distribution: Debian/GNU/Linux, AIX
Posts: 4,862
Blog Entries: 1

Rep: Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869Reputation: 1869
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');
 
1 members found this post helpful.
Old 03-20-2023, 08:45 AM   #5
sundialsvcs
LQ Guru
 
Registered: Feb 2004
Location: SE Tennessee, USA
Distribution: Gentoo, LFS
Posts: 10,659
Blog Entries: 4

Rep: Reputation: 3939Reputation: 3939Reputation: 3939Reputation: 3939Reputation: 3939Reputation: 3939Reputation: 3939Reputation: 3939Reputation: 3939Reputation: 3939Reputation: 3939
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.

Last edited by sundialsvcs; 03-20-2023 at 08:48 AM.
 
1 members found this post helpful.
Old 03-20-2023, 11:25 AM   #6
rtmistler
Moderator
 
Registered: Mar 2011
Location: USA
Distribution: MINT Debian, Angstrom, SUSE, Ubuntu, Debian
Posts: 9,882
Blog Entries: 13

Rep: Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930Reputation: 4930
Quote:
Originally Posted by timl View Post
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.
 
1 members found this post helpful.
Old 03-20-2023, 07:22 PM   #7
sundialsvcs
LQ Guru
 
Registered: Feb 2004
Location: SE Tennessee, USA
Distribution: Gentoo, LFS
Posts: 10,659
Blog Entries: 4

Rep: Reputation: 3939Reputation: 3939Reputation: 3939Reputation: 3939Reputation: 3939Reputation: 3939Reputation: 3939Reputation: 3939Reputation: 3939Reputation: 3939Reputation: 3939
(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 ..."

Last edited by sundialsvcs; 03-20-2023 at 07:27 PM.
 
1 members found this post helpful.
Old 03-20-2023, 08:14 PM   #8
timl
Member
 
Registered: Jan 2009
Location: Sydney, Australia
Distribution: Fedora,CentOS
Posts: 750

Original Poster
Rep: Reputation: 156Reputation: 156
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
 
1 members found this post helpful.
Old 03-24-2023, 09:45 AM   #9
GazL
LQ Veteran
 
Registered: May 2008
Posts: 6,897

Rep: Reputation: 5018Reputation: 5018Reputation: 5018Reputation: 5018Reputation: 5018Reputation: 5018Reputation: 5018Reputation: 5018Reputation: 5018Reputation: 5018Reputation: 5018
Quote:
Originally Posted by sundialsvcs View Post
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.

Last edited by GazL; 03-24-2023 at 05:44 PM. Reason: fix missing leading underscore on _POSIX_C_SOURCE macro
 
1 members found this post helpful.
Old 03-24-2023, 12:27 PM   #10
sundialsvcs
LQ Guru
 
Registered: Feb 2004
Location: SE Tennessee, USA
Distribution: Gentoo, LFS
Posts: 10,659
Blog Entries: 4

Rep: Reputation: 3939Reputation: 3939Reputation: 3939Reputation: 3939Reputation: 3939Reputation: 3939Reputation: 3939Reputation: 3939Reputation: 3939Reputation: 3939Reputation: 3939
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.)

Last edited by sundialsvcs; 03-24-2023 at 12:38 PM.
 
1 members found this post helpful.
Old 03-24-2023, 02:33 PM   #11
Racho
Member
 
Registered: Oct 2021
Posts: 59

Rep: Reputation: Disabled
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.

Last edited by Racho; 03-24-2023 at 02:45 PM. Reason: Just to make next_string[] longer
 
Old 03-24-2023, 02:41 PM   #12
EdGr
Member
 
Registered: Dec 2010
Location: California, USA
Distribution: I run my own OS
Posts: 998

Rep: Reputation: 470Reputation: 470Reputation: 470Reputation: 470Reputation: 470
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
 
2 members found this post helpful.
Old 03-24-2023, 06:01 PM   #13
sundialsvcs
LQ Guru
 
Registered: Feb 2004
Location: SE Tennessee, USA
Distribution: Gentoo, LFS
Posts: 10,659
Blog Entries: 4

Rep: Reputation: 3939Reputation: 3939Reputation: 3939Reputation: 3939Reputation: 3939Reputation: 3939Reputation: 3939Reputation: 3939Reputation: 3939Reputation: 3939Reputation: 3939
@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 "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.

Last edited by sundialsvcs; 03-24-2023 at 06:04 PM.
 
Old 03-28-2023, 12:17 AM   #14
chrism01
LQ Guru
 
Registered: Aug 2004
Location: Sydney
Distribution: Rocky 9.2
Posts: 18,358

Rep: Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751Reputation: 2751
Perhaps strtok() could be used https://www.tutorialspoint.com/c_sta...ion_strtok.htm
 
1 members found this post helpful.
Old 03-28-2023, 12:52 AM   #15
scasey
LQ Veteran
 
Registered: Feb 2013
Location: Tucson, AZ, USA
Distribution: CentOS 7.9.2009
Posts: 5,727

Rep: Reputation: 2211Reputation: 2211Reputation: 2211Reputation: 2211Reputation: 2211Reputation: 2211Reputation: 2211Reputation: 2211Reputation: 2211Reputation: 2211Reputation: 2211
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.

Last edited by scasey; 03-28-2023 at 12:56 AM.
 
  


Reply



Posting Rules
You may not post new threads
You may not post replies
You may not post attachments
You may not edit your posts

BB code is On
Smilies are On
[IMG] code is Off
HTML code is Off



Similar Threads
Thread Thread Starter Forum Replies Last Post
[SOLVED] RHCSA learning... RHEL6 or CENT OS for learning shejin983 Linux - Server 4 10-27-2012 09:16 AM
In a 5 - 6 year span, would this be a good plan for Linux development and learning? theif519 Linux - Newbie 5 05-31-2011 12:48 PM
E-learning learning, VLS want to help other learn? scheidel21 General 0 04-06-2010 11:19 AM
Where would a good place to start learning basic programing and scripting? Game Pro Programming 10 03-04-2008 07:06 PM
Any good Slackware 9 reviews? h1tman Linux - Distributions 12 11-12-2003 03:23 PM

LinuxQuestions.org > Forums > Non-*NIX Forums > Programming

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

Main Menu
Advertisement
My LQ
Write for LQ
LinuxQuestions.org is looking for people interested in writing Editorials, Articles, Reviews, and more. If you'd like to contribute content, let us know.
Main Menu
Syndicate
RSS1  Latest Threads
RSS1  LQ News
Twitter: @linuxquestions
Open Source Consulting | Domain Registration