2

I am learning C and have to code a program that:

  • reads an amount of chars from stdin and stores them in an array;
  • substitute any two or more consecutive spaces (' ') for only one;
  • write back the array.

So far I have done the following:

#include <stdio.h>
#define DIM 100

int main(int argc, char **argv)
{
    char mainArray [DIM]={'\0'};
    int auxArray [DIM];
    int i, m, n, c, l;

    printf("Enter a string containing two or more consecutive spaces:\n");

/* Read string from stdin */
    do
    {
        mainArray[i]=getchar();
        ++i;
    } while ((mainArray[i-1] != '\n') && (i < DIM-1));

/* Place the string terminator '\0' */
    if (i < DIM)
        mainArray[i]='\0';
    else
        mainArray[DIM-1]='\0';

    l=i;

/* My substitution algorithm */
    for (i=0 ; mainArray[i] != '\0' ; ++i)
    {
        if (mainArray[i] == ' ')
        {
            if (mainArray[i] == mainArray[i+1])
            {
                auxArray[m]=i;
                ++m;
            }
        }
    }

    for (i=0 ; i < m ; ++i)
    {
        for (c=auxArray[i] ; c < l-1 ; ++c)
            mainArray[n]=mainArray[n+1];
    }

/* Display the corrected string */
    for (i=0 ; mainArray[i] != '\0' ; ++i)
        printf("%c", mainArray[i]);

    return 0;
}

As an example, entering the string "a_long_time_ago___in_a_galaxy__far____,_far_away.." would produce "a_long_time_ago_in_a_galaxy_far_,_far_away.."

For the substitution algorithm I thought that one possiblity could be to store the positions of the spaces in excess, and then delete the spaces in the main array through the auxiliary array.

I am sure I am making some amateaur mistake. Also, how can the code be optimized in your opinion?

Thank you in advance.

Koios
  • 23
  • 5
  • work with 2 pointers, have one pointer (maybe keep using for(i)) to walk the entire Array, and copy to another location of the same array ( call this pointer J and start at 0, at first it will copy over itself) and have a flag to indicate you found an space and copied it (the first space) when you find another space and the flag is set, just 'continue' i, but don't increment j, until you find a non-space which you copy to *j and keep walking the array... don't forget to add the null terminator at the last *j position... – Ryu Oct 29 '15 at 01:20
  • @Ryu Thanks! I will also try the approach you suggested. – Koios Oct 29 '15 at 15:24
  • Try to get used to code loops that use an iteration variable using `for`, and declare the iteration variable (with an initialiser) in its first expression. "Reusing" iteration variables is a mean source of coding errors. (Further simplification would seem possible dropping unwanted space characters instead of writing them to the (limited) buffer - the assignment as presented demands otherwise, if you can't iron out a specification's crinkles, better follow it by the letter.) – greybeard Oct 29 '15 at 18:42
  • @greybeard : What do you mean with "reusing iteration variables"? – Koios Oct 30 '15 at 15:01
  • Never, ever, use an iteration variable after its loop, other than using the value to handle early and regular termination in a single place: if your next access is a read, the language system knows no better than the variable being initialised and can't point you to a missing initialisation. In general, keep scopes as small as possible and prefer suggestive names to short ones. (In my eyes, `i (j, k)`, and, with C, `p` and `q`(, `s` and `d`) for pointers, strongly suggest "iteration variable".) – greybeard Oct 30 '15 at 17:48
  • I see your point. It is the small things I guess...thanks a lot! – Koios Oct 31 '15 at 01:44

2 Answers2

1

its not code review, but you have several obvious problems with the code:

mainArray[i]=getchar(); - you haven't initialized i, so you're writing to some random memory address, probably you're compiling in debug mode, where compiler sets variables to 0, but in general case - don't do this

if (i < DIM) - you don't need it as i after loop will point either to next symbol after \n or it will be equal to DIM-1, so justmainArray[i]='\0';` is enough

auxArray[m]=i; - m is not initialized

for (i=0 ; i < m ; ++i) I cannot understand logic of this loop, especially mainArray[n]=mainArray[n+1]; - you're not changing n. Whole approach with storing spaces indexes is wrong, after you deleted at least one space sequence - all indexes in array become wrong ones.

here is a little bit different version with one array only:

#include <stdio.h>
#include <string.h>
#define DIM 100

int main(int argc, char **argv)
{
    char mainArray [DIM]={'\0'};
    int i, j, k;

    printf("Enter a string containing two or more consecutive spaces:\n");

    fgets(mainArray, DIM, stdin); // note: last symbols of the array will be \n\0
    mainArray[strlen(mainArray)-1] = '\0'; // trimming \n

    printf("[%s]\n", mainArray);

    for (i=0; mainArray[i] != '\0' ; ++i) {
        if (mainArray[i] == ' ') {
            for (j=(i+1); mainArray[j]==' '; ++j) ; // calculate end of space sequence, j will point to the first non space symbol
            for (k=j; mainArray[k]!='\0'; ++k) // copy rest of string to the position after first space
                mainArray[i+1+(k-j)] = mainArray[k];
            mainArray[i+1+(k-j)] = '\0'; // put null-terminator
        }
    }

    printf("[%s]\n", mainArray);
    return 0;
}
Iłya Bursov
  • 23,342
  • 4
  • 33
  • 57
  • Great answer. Concerning the uninitialized variables, it was most certainly an editing mistake as I had them all set to 0 in the original code. Sorry about that. I now understand why the loop did not work when you say that _after you deleted at least one space sequence - all indexes in array become wrong ones_. It also seems that the code could be made simpler by using pointers but I think it was supposed to do this exercise using only array arithmetic. I am at a beginner level and still working on the coding thought process. You were very helpful, thank you! – Koios Oct 29 '15 at 15:08
0

Here's an alternate way using just char* pointers:

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

int
main(void)
{
    char *lhs;
    const char *rhs;
    int chr;
    char mainArray[500];

    fgets(mainArray,sizeof(mainArray),stdin);

    lhs = strchr(mainArray,'\n');
    if (lhs != NULL)
        *lhs = 0;

    printf("INP: '%s'\n",mainArray);

    lhs = mainArray;
    rhs = mainArray;

    for (chr = *rhs++;  chr != 0;  chr = *rhs++) {
        *lhs++ = chr;
        if (chr != ' ')
            continue;

        for (chr = *rhs;  chr != 0;  chr = *++rhs) {
            if (chr != ' ')
                break;
        }
    }

    *lhs = 0;

    printf("OUT: '%s'\n",mainArray);

    return 0;
}

UPDATE: Here's the above recoded to use indexes. Note that it's more verbose for no good effect. But, the logic is still just as simple. That's one of the main points. For future reference, it's important to keep your logic "as simple as possible--and no simpler" because when projects grow, the effect gets magnified for good or for evil.

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

int
main(void)
{
    char *cp;
    int lhs;
    int rhs;
    int chr;
    char mainArray[500];

    fgets(mainArray,sizeof(mainArray),stdin);

    cp = strchr(mainArray,'\n');
    if (cp != NULL)
        *cp = 0;

    printf("INP: '%s'\n",mainArray);

    lhs = 0;
    rhs = 0;

    for (chr = mainArray[rhs++];  chr != 0;  chr = mainArray[rhs++]) {
        mainArray[lhs++] = chr;
        if (chr != ' ')
            continue;

        for (chr = mainArray[rhs];  chr != 0;  chr = mainArray[++rhs]) {
            if (chr != ' ')
                break;
        }
    }

    mainArray[lhs] = 0;

    printf("OUT: '%s'\n",mainArray);

    return 0;
}

Also, see my answer here: Issue implementing dynamic array of structures

It's about arrays of structs [which might seem to be a little advanced] but just pretend that the partition type was typedef int partition or typedef char partition. Also, see the last part about int arrays and pointers being interchangeable.

Craig Estey
  • 30,627
  • 4
  • 24
  • 48
  • Thank you for the alternative, it works just fine. I will keep it in mind for future reference. In this exercise it was supposed to use only array arithmetic and using pointers will be the next step. Thanks – Koios Oct 29 '15 at 15:19
  • Thank you once again @Craig, I´ll soon dive into pointers and dynamic memory due to an assignment and the examples you provide will help me quite a bit. – Koios Oct 31 '15 at 01:57