Home Upgrade Search Memberlist Extras Hacker Tools Award Goals Help Wiki Contact

C 

Programming Challenge

Here's a simple programming challenge that should get the rookies thinking.

Writing a program which will take a mutable c-string and remove characters from it. You are free to do this any way you want but you should be able to defend your solution and recognize any possible short-comings.

Here's some code to start with:
Code
int main(int argc, char** argv) {
    char s[]="The C string to work with";
    return 0;
}

Now take some time and think about a solution. Why is your solution good? Why is your solution bad?

Please post your solutions and the pros and cons and we'll comment on them.
Code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
  size_t n = 4; /* index of the 'C' */
  char s[] = "The C string to work with";
  char *p = s;
  memmove(p + 1, p, n); ++p; /* remove 'C' */
  memmove(p + 1, p, n); ++p; /* remove extra space which was after 'C' */
  puts(p);
  exit(0);
}

Pros:
- no reallocations (removing chars means the buffer always shrinks -- no need to realloc really)
- no string concatenation of lower and upper halves to "remove" a char

Cons:
- original chars not preserved, NOTE: A fix for that might look something like below
Code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
  char ch;
  size_t n = 4; /* index of the 'C' */
  char s[] = "The C string to work with";
  char *p = s;

  ch = p[n];
  memmove(p + 1, p, n); ++p; /* remove 'C' */
  *(p - 1) = ch;

  ch = p[n];
  memmove(p + 1, p, n); ++p; /* remove extra space which was after 'C' */
  *(p - 1) = ch;

  puts(p);

  fputs("Junked chars -> '", stdout);
  fwrite(s, 1, p - s, stdout);
  putc('\'', stdout);
  exit(0);
}
Getting Started: C/C++
[C/C++/.NET/x86 ASM - Automation Programmer]
(Aug 15, 2015 11:37 AM)0xDEAD10CC Wrote:  
Code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
  size_t n = 4; /* index of the 'C' */
  char s[] = "The C string to work with";
  char *p = s;
  memmove(p + 1, p, n); ++p; /* remove 'C' */
  memmove(p + 1, p, n); ++p; /* remove extra space which was after 'C' */
  puts(p);
  exit(0);
}

Pros:
- no reallocations (removing chars means the buffer always shrinks -- no need to realloc really)
- no string concatenation of lower and upper halves to "remove" a char

Cons:
- original chars not preserved, NOTE: A fix for that might look something like below
Code
#include <stdio.h>
#include <stdlib.h>
#include <string.h>

int main(void)
{
  char ch;
  size_t n = 4; /* index of the 'C' */
  char s[] = "The C string to work with";
  char *p = s;

  ch = p[n];
  memmove(p + 1, p, n); ++p; /* remove 'C' */
  *(p - 1) = ch;

  ch = p[n];
  memmove(p + 1, p, n); ++p; /* remove extra space which was after 'C' */
  *(p - 1) = ch;

  puts(p);

  fputs("Junked chars -> '", stdout);
  fwrite(s, 1, p - s, stdout);
  putc('\'', stdout);
  exit(0);
}

So I'm a little confused. Isn't it easier to use
Code
string s = "The C string to work with";
? Also, why did you put void inside of the main function? Leaving it blank does the same thing, doesn't it? Unless it's more of a style decision.
Actually can you help me with something, I practically made something that removes the beginning character from the string somehow...

It's kinda on topic.
Code
#include "stdafx.h"
#include <iostream>

int _tmain(int argc, _TCHAR* argv[])
{
    for (int i = 0; i < 100; i++) {
        std::cout << "The current number " + i << std::endl;
    }
    std::cin.ignore();
    return 0;
}

[Image: 3c7d7665b7fc269f1be5a15da7fbd8e7.png]d on topic lolz.
Hi
(Aug 15, 2015 01:29 PM)Blender Wrote:  Also, why did you put void inside of the main function? Leaving it blank does the same thing, doesn't it? Unless it's more of a style decision.

Your main should always be declared as a void, as it "returns" nothing. On that note, you should always have a return 0 at the end of main ;)
(Aug 15, 2015 02:53 PM)_B1N4RY_ Wrote:  Your main should always be declared as a void, as it "returns" nothing. On that note, you should always have a return 0 at the end of main ;)

I've never had to declare it as a void. It does this automatically if you leave it empty. Only time I've ever had to declare a void was when I created a function that had no return type. But with parameters, never.


And why isn't anyone doing

using namespace std ?

It saves the time to do std::cout(unless you're using something with multiple libraries that has the potential to conflict with the functions in either library, but I haven't seen that in the code presented on this thread anyway)


(Aug 15, 2015 02:48 PM)sdk Wrote:  Actually can you help me with something, I practically made something that removes the beginning character from the string somehow...

It's kinda on topic.
Code
#include "stdafx.h"
#include <iostream>

int _tmain(int argc, _TCHAR* argv[])
{
    for (int i = 0; i < 100; i++) {
        std::cout << "The current number " + i << std::endl;
    }
    std::cin.ignore();
    return 0;
}

Code
#include "stdafx.h"
#include <iostream>

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    string s = "The current number";

    for(int i = 0; i < 100; i++)
    {
        cout << s << ": " << i << endl;
    }
    cin.ignore();
    return 0;
}

That will fix it.
(Aug 15, 2015 02:53 PM)_B1N4RY_ Wrote:  Your main should always be declared as a void, as it "returns" nothing. On that note, you should always have a return 0 at the end of main ;)

You are confused:

1. int main(void) means that main is declared as integer without arguments passed. And that is exactly right if you don't plan to pass options via the command line.

2. main() always returns something. The return 0 is optional, because by default main() - and only main() - returns zero. You may return a non-zero value to flag an error, which you can test (under Windows at least) with echo %errorlevel%.
Your main really doesn't need arguments so long as you're not planning to make it do that which in my opinion would be pretty messy and makes things too complicated, because you're most likely not going to be doing console applications for the rest of your life.
(Aug 15, 2015 02:53 PM)_B1N4RY_ Wrote:  Your main should always be declared as a void, as it "returns" nothing. On that note, you should always have a return 0 at the end of main ;)

int _tmain is the way Visual Studio makes the default main method. Also I know I as told to return 0 or something to avoid memory leaks.
Hi
(Aug 15, 2015 01:29 PM)Blender Wrote:  So I'm a little confused. Isn't it easier to use
Code
string s = "The C string to work with";
? Also, why did you put void inside of the main function? Leaving it blank does the same thing, doesn't it? Unless it's more of a style decision.

You are clearly confused yes. The whole point of the challenge was C strings, not C++ strings. And void means that no arguments can be passed to the function, it's not about style.


(Aug 15, 2015 02:53 PM)_B1N4RY_ Wrote:  Your main should always be declared as a void, as it "returns" nothing. On that note, you should always have a return 0 at the end of main ;)

That's not what he was asking, and main does return an int, which is why it's declared to return int. :S

(Aug 15, 2015 02:48 PM)sdk Wrote:  Actually can you help me with something, I practically made something that removes the beginning character from the string somehow...

It's kinda on topic.
Code
#include "stdafx.h"
#include <iostream>

int _tmain(int argc, _TCHAR* argv[])
{
    for (int i = 0; i < 100; i++) {
        std::cout << "The current number " + i << std::endl;
    }
    std::cin.ignore();
    return 0;
}

[Image: 3c7d7665b7fc269f1be5a15da7fbd8e7.png]d on topic lolz.

If it's not a solution to the challenge, it's off topic, get out of this thread.

(Aug 15, 2015 04:32 PM)Blender Wrote:  I've never had to declare it as a void. It does this automatically if you leave it empty. Only time I've ever had to declare a void was when I created a function that had no return type. But with parameters, never.


And why isn't anyone doing

using namespace std ?

It saves the time to do std::cout(unless you're using something with multiple libraries that has the potential to conflict with the functions in either library, but I haven't seen that in the code presented on this thread anyway)



Code
#include "stdafx.h"
#include <iostream>

using namespace std;

int _tmain(int argc, _TCHAR* argv[])
{
    string s = "The current number";

    for(int i = 0; i < 100; i++)
    {
        cout << s << ": " << i << endl;
    }
    cin.ignore();
    return 0;
}

That will fix it.

Because 'using namespace std;' or 'using namespace' in general defeats the whole point of namespaces, and it's bad to be doing that. Lastly, this thread is not even about C++.

Can we lose the skids in this thread please?? 🤨

(Aug 15, 2015 05:24 PM)sdk Wrote:  int _tmain is the way Visual Studio makes the default main method. Also I know I as told to return 0 or something to avoid memory leaks.

Honestly, what are you talking about? return 0 at the end of main()'s scope can be omitted as per the C++ standard, and reaching the terminating } of main() will have the same effect as 0. There's nothing even remotely related to memory leaks with the return of main(). Additionally, you should never omit the return type to any function, including main(). void main() is old, and now also, very poor practice, and so is main() without a return type.

(Aug 15, 2015 04:44 PM)Blender Wrote:  Your main really doesn't need arguments so long as you're not planning to make it do that which in my opinion would be pretty messy and makes things too complicated, because you're most likely not going to be doing console applications for the rest of your life.

And you don't think GUI applications take command line arguments? I can tell you that you're wrong.

Internet Explorer, Google Chrome, Firefox, Notepad, and pretty much 90% of all other programs I know, allow command line arguments for various things.

Proof: Open cmd.exe and invoke this ->
Code
notepad "file.txt"
Getting Started: C/C++
[C/C++/.NET/x86 ASM - Automation Programmer]
@dead

I would have done something like yours using memmove, however I don't really understand what your code is doing (im high as fuck so thats probably why)

Like I would have thought to do
Code
memmove(p + n - 1, p + n, strlen(p+n) + 1);

basically shifting the rest of the string past the character to be removed to the left but idk
[img]http://66.media.tumblr.com/acfffd664b499bccaea0a5bcfd0debf0/tumblr_of816spRTW1twdas2o1_400.jpg[/img]

(Aug 15, 2015 11:57 PM)Kantos Wrote:  @dead

I would have done something like yours using memmove, however I don't really understand what your code is doing (im high as fuck so thats probably why)

Like I would have thought to do
Code
memmove(p + n - 1, p + n, strlen(p+n) + 1);

basically shifting the rest of the string past the character to be removed to the left but idk

I shift everything before the character to be moved to the right by one space, and keep a pointer to the first character of the string. Every time I move the left side to the right to "overwrite" the one character, I increment a pointer which starts at the beginning of the string so that we end up with "JUNK HERE|String we want here|\0"

The pointer would be set to the 'S' after everything is said and done.

This way I don't need to call strlen() every time either, I didn't feel the need to--we know that removing one character makes the string length less by one each time. I think what you are meaning to do is just the reverse of what I did, and having junk past the null terminator instead.
Getting Started: C/C++
[C/C++/.NET/x86 ASM - Automation Programmer]
(Aug 15, 2015 07:01 PM)0xDEAD10CC Wrote:  You are clearly confused yes. The whole point of the challenge was C strings, not C++ strings. And void means that no arguments can be passed to the function, it's not about style.



That's not what he was asking, and main does return an int, which is why it's declared to return int. :S

If it's not a solution to the challenge, it's off topic, get out of this thread.

Because 'using namespace std;' or 'using namespace' in general defeats the whole point of namespaces, and it's bad to be doing that. Lastly, this thread is not even about C++.

Can we lose the skids in this thread please?? 🤨

Honestly, what are you talking about? return 0 at the end of main()'s scope can be omitted as per the C++ standard, and reaching the terminating } of main() will have the same effect as 0. There's nothing even remotely related to memory leaks with the return of main(). Additionally, you should never omit the return type to any function, including main(). void main() is old, and now also, very poor practice, and so is main() without a return type.

And you don't think GUI applications take command line arguments? I can tell you that you're wrong.

Internet Explorer, Google Chrome, Firefox, Notepad, and pretty much 90% of all other programs I know, allow command line arguments for various things.

Proof: Open cmd.exe and invoke this ->
Code
notepad "file.txt"

Listen m8 calm down I can see your pantalooms are ruffled. No need to call people names.

In C++ I never had to put void inside of a parentheses to indicate that there were no arguments because leaving it blank did that for me.

I've never had to put characters inside of the int main() parentheses because in C++, that isn't needed anymore to pass characters to the console. That's seriously some old-style C shit, m8. If you don't believe me, fire up a new cpp application in Visual Studio and create an app without using those characters.

Damn bruh chill out :(
Quote:In C++ I never had to put void inside of a parentheses to indicate that there were no arguments


Also, my code is C not C++. And there is a difference between a the void being there and being omitted if you do some research.

Quote:That's seriously some old-style C shit, m8


Maybe because my code IS C?...

Other than that, I don't know what you're talking about here:
Quote:I've never had to put characters inside of the int main() parentheses because in C++, that isn't needed anymore to pass characters to the console.


It doesn't make sense to me.
Getting Started: C/C++
[C/C++/.NET/x86 ASM - Automation Programmer]
(Aug 17, 2015 04:14 PM)0xDEAD10CC Wrote:  Also, my code is C not C++. And there is a difference between a the void being there and being omitted if you do some research.

Maybe because my code IS C?...

Other than that, I don't know what you're talking about here:

It doesn't make sense to me.

Sometimes in old C++ to input into the console people would need to do like int main(char(mander)*something) but it isnt required any longer because C++ is now upgraded into the cyberdalek form of happy. So, hopefully that clears everyting up sirs and sirs.


Possibly Related Threads...
Thread / Author Replies Views Last Post
[C] by myselfandiAug 11, 2019 03:34 AM 12 272 Aug 11, 2019 03:34 AM
Last Post: YouthInAsia
[.NET] by zerocool1245Feb 6, 2017 10:18 AM 3 247 Feb 6, 2017 10:18 AM
Last Post: Ninja
[Python] by REPmeansNothingSkidsDec 20, 2015 12:56 AM 16 777 Dec 20, 2015 12:56 AM
Last Post: casruf