Removing the Rest of a String - arrays

Just started experimenting with C, coming from a Java background and I am having an issue trying to remove a section of a string. The basic logic to this one is I have a String (which I found out is an array of chars in C, Very cool!), and once a certain condition is met while going through this string, I want to delete the rest of the String. so for example, if My string was "hello world!", and I set the condition as a blank space, I would like to delete everything following that blank space, so just return "hello ". I had an idea of noting the index where the condition was met, and creating a second array and filling it, then deleting the previous one, however I'm certain there is a better way of doing this. If anyone can help, that would be greatly appreciated, Thank you all in advance!
edit:
The Idea is I want to take in user input, the specific case I have is if there is a single dot "." which has a "next line" as the previous and next element, or a "next line" as the previous element and a null as the next argument. so basically:
(if string[n] == ".")
{
if((string[n-1]==\n && string[n+1]==\n) || (string[n-1]==\n && string[n+1]==
null)
{ Then remove everything past this point}
}
input:
hello world
this is ok.
.
Everything here will be deleted.
Output:
hello world
this is ok.
.
Edit 2:
Thank you all for some great advice so far, I am still running into issues with he program however, So here I will post the code for the main method so far (just testing the delete rest of string part (have not added user input yet).
//main method
int main(void)
{
char test = "This is a sample text.\
The file will be terminated by a single dot: .\
The program continues processing the lines because the dot (.)\
did not appear at the beginning.\
. even though this line starts with a dot, it is not a single dot.\
The program stops processing lines right here.\
.\
You wont be able to feed any more lines to the program.";
int n =0;
while(test[n] != NULL)
{
if (test[n]=='.')
{
if ((test[n-1]=='\n' && test[n+1]=='\n') || (test[n-1]=='\n' && test[n+1]==NULL))
{
test[n] = '\0';
}
}
n++;
}
printf("%c\n",test);
return 0;
}
The idea here is that I will eventually send the string word by word to an insertion sort linked list function and sort the string alphabetically after removing everything after the dot as specified. The problem now is I am encountering errors for some reason, If anybody could help sort them out, I would greatly appreciate the help.
Errors in main:
345500375/source.c: In function ‘main’:
345500375/source.c:64:17: warning: initialization makes integer from pointer without a cast [-Wint-conversion]
char test = "This is a sample text.\
^~~~~~~~~~~~~~~~~~~~~~~~
The file will be terminated by a single dot: .\
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The program continues processing the lines because the dot (.)\
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
did not appear at the beginning.\
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
. even though this line starts with a dot, it is not a single dot.\
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
The program stops processing lines right here.\
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
.\
~~
You wont be able to feed any more lines to the program.";
~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~~
345500375/source.c:73:15: error: subscripted value is neither array nor pointer nor vector
while(test[n] != NULL)
^
345500375/source.c:75:17: error: subscripted value is neither array nor pointer nor vector
if (test[n]=='.')
^
345500375/source.c:77:21: error: subscripted value is neither array nor pointer nor vector
if ((test[n-1]=='\n' && test[n+1]=='\n') || (test[n-1]=='\n' && test[n+1]==NULL))
^
345500375/source.c:77:40: error: subscripted value is neither array nor pointer nor vector
if ((test[n-1]=='\n' && test[n+1]=='\n') || (test[n-1]=='\n' && test[n+1]==NULL))
^
345500375/source.c:77:61: error: subscripted value is neither array nor pointer nor vector
if ((test[n-1]=='\n' && test[n+1]=='\n') || (test[n-1]=='\n' && test[n+1]==NULL))
^
345500375/source.c:77:80: error: subscripted value is neither array nor pointer nor vector
if ((test[n-1]=='\n' && test[n+1]=='\n') || (test[n-1]=='\n' && test[n+1]==NULL))
^
345500375/source.c:79:19: error: subscripted value is neither array nor pointer nor vector
test[n] = '\0';
^

This would do the trick (assuming all indices are in bounds):
if (string[n]=='.') {
if (string[n-1]=='\n' && string[n+1]=='\n') {
string[n+1] = '\0';
}
}

I presume that you are using char* as your "string." In truth, this is not a string that is comparable to Java's strings at all or most languages in general.
A number of developers and libraries (and languages, except maybe Pascal) use something closer to a struct in order to store a string, ex:
struct string {
char * pointer;
unsigned short length;
};
This offers a few advantages, namely O(1) time complexity length lookups.
In your case, it would allow you to quickly create substrings or slices from your old string, while not modifying memory at all.
If we were to use that very rudimentary struct that I had provided as an example:
// note: you need the keyword struct behind every usage of a struct, many times structs are type aliased solely because of that
struct string userInput = {
.pointer = "words in str.ing",
.length = 16
};
// ...
unsigned short whereDotIs = 13;
struct string result = {
.pointer = userInput.pointer,
.length = whereDotIs
};
At this point, you could read past the dot (.), but it's not apart of the abstract idea of a "string" that we have now established, it is just random memory.
Although, there are cases in which you would need to work with null-terminated character pointers, in which #Mustafa Quraish's answer will suffice, unless the string is const qualified, in which you would have to stick to your original solution: copying the array into a new one.

First of all, your compilation errors depart from the fact that you have declared a char variable, not a char array. You can declare a char array with char variable[] and initialize it with a string (in this case you get an array of n elements, where n is the string size in characters, plus one for the final \0 char) Or you can specify a length (in between the brackets) and then initialize also (the unused part of the array is filled with \0 chars, as in char variable[30] = "hello"; /* the five chars of "hello" plus 25 '\0' chars */)
In java, Strings are immutable. You can extract a substring from them, but they become different instances of the class String. In C, a string is simply an array of chars. For C functions dealing with strings, a string extends until the function encounters a character '\0', and all the processing of the array (that continues to be the same length) terminates when the '\0' is found. So the best way to cut a string at some point is to put there a '\0' character.
BTW, don't use the final \ to continue a string at the next line, it is obsolete by the new C syntax (which is older than some of the readers here, and the compiler will eliminate the newline and the backslash from the input source, making the continuation line to continue the string literal as if you had written it stuck to the end of the previous line --this is, IMHO, not what you want). The new syntax allows a string to continue in the next line by just terminating it (with ") and start again in the next line (again with ") as below (so this code is equivalent to what you have written):
char test[] = /* now test is a char array, you need the pair of [] brackets */
"This is a sample text."
"The file will be terminated by a single dot: ."
"The program continues processing the lines because the dot (.)"
"did not appear at the beginning."
". even though this line starts with a dot, it is not a single dot."
"The program stops processing lines right here."
"."
"You wont be able to feed any more lines to the program.";
and also equivalent to this one:
char test[] = /* now test is a char array, you need the pair of [] brackets */
"This is a sample text.The file will be terminated by a single dot: .The program continues processing the lines because the dot (.)did not appear at the beginning.. even though this line starts with a dot, it is not a single dot.The program stops processing lines right here..You wont be able to feed any more lines to the program.";
but if you want the newlines to be included in the string literal, then you have
to include explicit \n characters on them, as below:
char test[] = /* now test is a char array, you need the pair of [] brackets */
"This is a sample text.\n"
"The file will be terminated by a single dot: .\n"
"The program continues processing the lines because the dot (.)\n"
"did not appear at the beginning.\n"
". even though this line starts with a dot, it is not a single dot.\n"
"The program stops processing lines right here.\n"
".\n"
"You wont be able to feed any more lines to the program.\n";
if you want to end the string in the single dot that is preceded and followed by a
\n, then you can use the strstr() function to find the place of the sequence you are following and put a '\0' in the appropiate place.
char *p = strstr(test, "\n.\n");
/* p (if found, e.g. not NULL) will point to the first \n, so we must use the
* address of the next char */
/* we can do the following as we know that the string extends past the
* position in which the dot is, because we have found (in the string) the
* sequence, that extends past the place we are going to put it. */
if (p) /* this is the same as if (p != NULL) */
p[1] = '\0'; /* put a \0 in the position of the dot */
printf("The cut text is: %s", test);
Your code has still another error, this time it is grave, which will lead you to runtime problems (possibly undetected by the compiler or until the code has been used for a long time), as you can access (and C doesn't check for bounding errors like java does) if you happen to find a dot character in the first position of the array. n will be 0 and when you try to access test[n-1] in your if statement, you'll be accessing the previous to first element in the array (this is test[-1]). This would throw an ArrayOutOfBoundsException in java, but C has not such protection. This problem will not happen at the end of the string (despite you also access the next char to the dot), because even if you find the dot at the end of the string, the following char (and there must be one) will be the last \0 char, so no problem will arise from this (as it has been pointed also erroneously in some other answers)

Related

Integer to pointer type conversion

int count_words(string word)
{
string spaces = "";
int total_words = 1;
int i, j = 0 ;
for (i = 0; i < strlen(word); i++)
{
strcpy(spaces, word[i]);
if (strcmp(spaces, " ") == 0)
{
total_words = total_words + 1;
}
}
return total_words;
}
I am trying to make a function in c that gets the total number of words, and my strategy is to find the number of spaces in the string input. However i get an error at strcpy about integer to ptrtype conversion,. I cant seem to compare the 2 strings without getting the error. Can someone explain to me whats how the error is happening and how I would go about fixing it. The IDE is also suggesting me to add an ampersand beside word[i] but it then makes a segmentation fault output
You need to learn a little more about the distinction between characters and strings in C.
When you say
strcpy(spaces, word[i]);
it looks like you're trying to copy one character to a string, so that in the next line you can do
if (strcmp(spaces, " ") == 0)
to compare the string against a string consisting of one space character.
Now, it's true, if you're trying to compare two strings, you do have to call strcmp. Something like
if (spaces == " ") /* WRONG */
definitely won't cut it.
In this case, though, you don't need to compare strings. You're inspecting your input a character at a time, so you can get away with a simple character comparison instead. Get rid of the spaces string and the call to strcpy, and just do
if (word[i] == ' ')
Notice that I'm comparing against the character ' ', not the string " ". Using == to compare single characters like this is perfectly fine.
Sometimes, you do have to construct a string out of individual characters, "by hand", but when you do, it's a little more elaborate. It would look like this:
char spaces[2];
spaces[0] = word[i];
spaces[1] = '\0';
if (strcmp(spaces, " ") == 0)
...
This would work, and you might want to try it to be sure, but it's overkill, and there's no reason to write it that way, except perhaps as a learning exercise.
Why didn't your code
strcpy(spaces, word[i]);
work? What did the error about "integer to pointer conversion" mean? Actually there are several things wrong here.
It's not clear what the actual type of the string spaces is (more on this later), but it has space for at most 0 characters, so you're not going to be able to copy a 1-character string into it.
It's also not clear that spaces is even writable. It might be a constant, meaning that you can't legally copy any characters into it.
Finally, strcpy copies one string to another. In C, although strings are arrays, they're usually referred to as pointers. So strcpy accepts two pointers, one to the source and one to the destination string. But you passed it word[i], which is a single character, not a string. Let's say the character was A. If you hadn't gotten the error, and if strcpy had tried to do its job, it would have treated A as a pointer, and it would have tried to copy a string from address 65 in memory (because the ASCII value of the character A is 65).
This example shows that working with strings is a little bit tricky in C. Strings are represented as arrays, but arrays are second-class citizens in C. You can't pass arrays around, but arrays are usually referred to by simple pointers to their first element, which you can pass around. This turns out to be very convenient and efficient once you understand it, but it's confusing at first, and takes some getting used to.
It might be nice if C did have a built-in, first-class string type, but it does not. Since it does not, C programmers myst always keep in mind the distinction between arrays and characters when working with strings. That "convenient" string typedef they give you in CS50 turns out to be a bad idea, because it's not actually convenient at all -- it merely hides an important distinction, and ends up making things even more confusing.

Removing spaces in a string

I was trying to remove spaces of a string after scanning it. The program has compiled perfectly but it is not showing any output and the output screen just keeps getting shut down after scanning the string. Is there a logical error or is there some problem with my compiler(I am using a devc++ compiler btw).
Any kind of help would be appreciated
int main()
{
char str1[100];
scanf("%s",&str1);
int len = strlen(str1);
int m;
for (m=0;m<=len;){
if (&str1[m]==" "){
m++;
}
else {
printf("%c",&str1[m]);
}
m++;
}
return 0;
}
Edit : sorry for the error of m=1, I was just checking in my compiler whether that works or not and just happened to paste that code
Your code contains a lot of issues, and the behaviour you describe is very likely not because of a bug in the compiler :-)
Some of the issues:
Use scanf("%s",str1) instead of scanf("%s",&str1). Since str1 is defined as a character array, it automatically decays to a pointer to char as required.
Note that scanf("%s",str1) will never read in any white space because "%s" is defined as skipping leading white spaces and stops reading in when detecting the first white space.
In for (m=1;m<=len;) together with str1[m], note that an array in C uses zero-based indizes, i.e. str1[0]..str1[len-1], such that m <= len exceeds array bounds. Use for (m=0;m<len;) instead.
Expression &str1[m]==" " is correct from a type perspective, but semantically a nonsense. You are comparing the memory address of the mth character with the memory address of a string literal " ". Use str1[m]==' ' instead and note the single quotes denoting a character value rather than double quotes denoting a string literal.
Statement printf("%c",&str1[m]) passes the memory address of a character to printf rather than the expected character value itself. Use printf("%c",str1[m]) instead.
Hope I found everything. Correct these things, turn on compiler warnings, and try to get ahead. In case you face further troubles, don't hesitate to ask again.
Hope it helps a bit and good luck in experiencing C language :-)
There are many issues:
You cannot read a string with spaces using scanf("%s") , use fgets instead (see comments).
scanf("%s", &str1) is wrong anyway, it should be scanf("%s", str1);, str1 being already the address of of the string
for (m = 0; m <= len;) is wrong, it should be for (m = 0; m < len;), because otherwise the last character you will check is the NUL string terminator.
if (&str1[m]==" ") is wrong, you should write if (str1[m]==' '), " " does not denote a space character but a string literal, you need ' ' instead..
printf("%c", &str1[m]); is wrong, you want to print a char so you need str1[m] (without the &).
You should remove both m++ and put that into the for statement: for (m = 1; m < len; m++), that makes the code clearer.
And possibly a few more problems.
And BTW your attempt doesn't remove the spaces from the string, it merely displays the string skipping spaces.
There are a number of smaller errors here that are adding up.
First, check the bounds on your for loop. You're iterating from index 1 to index strlen(str1), inclusive. That's a reasonable thing to try, but remember that in C, string indices start from 0 and go up to strlen(str1), inclusive. How might you adjust the loop to handle this?
Second, take a look at this line:
if (&str1[m] == " ") {
Here, you're attempting to check whether the given character is a space character. However, this doesn't do what you think it does. The left-hand side of this expression, &str1[m], is the memory address of the mth character of the string str1. That should make you pause for a second, since if you want to compare the contents of memory at a given location, you shouldn't be looking at the address of that memory location. In fact, the true meaning of this line of code is "if the address of character m in the array is equal to the address of a string literal containing the empty string, then ...," which isn't what you want.
I suspect you may have started off by writing out this line first:
if (str1[m] == " ") {
This is closer to what you want, but still not quite right. Here, the left-hand side of the expression correctly says "the mth character of str1," and its type is char. The right-hand side, however, is a string literal. In C, there's a difference between a character (a single glyph) and a string (a sequence of characters), so this comparison isn't allowed. To fix this, change the line to read
if (str1[m] == ' ') {
Here, by using single quotes rather than double quotes, the right-hand side is treated as "the space character" rather than "a string containing a space." The types now match.
There are some other details about this code that need some cleanup. For instance, look at how you're printing out each character. Is that the right way to use printf with a character? Think about the if statement we discussed above and see if you can tinker with your code. Similarly, look at how you're reading a string. And there may be even more little issues here and there, but most of them are variations on these existing themes.
But I hope this helps get you in the right direction!
For loop should start from 0 and less than length (not less or equal)
String compare is wrong. Should be char compare to ' ' , no &
Finding apace should not do anything, non space outputs. You ++m twice.
& on %c output is address not value
From memory, scanf stops on whitespace anyway so needs fgets
int main()
{
char str1[100];
scanf("%s",str1);
int len = strlen(str1);
int m;
for (m=0;m<len;++m){
if (str1[m]!=' '){
printf("%c",str1[m]);
}
}
return 0;
}
There are few mistakes in your logic.
scanf terminates a string when it encounter any space or new line.
Read more about it here. So use fgets as said by others.
& in C represents address. Since array is implemented as pointers in C, its not advised to use & while getting string from stdin. But scanf can be used like scanf("%s",str1) or scanf("%s",&str[1])
While incrementing your index put m++ inside else condition.
Array indexing in C starts from 0 not 1.
So after these changes code will becames something like
int main()
{
char str1[100];
fgets(str1, sizeof str1 , stdin);
int len = strlen(str1);
int m=0;
while(m < len){
if (str1[m] == ' '){
m++;
}
else {
printf("%c",str1[m]);
m++;
}
}
return 0;
}

Print only the rightmost part of a string

I am applying printf and/or other functions to a certain string of characters, read from a file. I want to skip the first 5 characters under certain conditions. Now I thought to be clever by, if the conditions apply, increasing the string pointer by 5:
if (strlen(nav_code) == 10 ) {nav_code = 5+nav_code;}
but the compiler refuses this:
error: assignment to expression with array type
What have I misunderstood? How to make my idea work - or is it a bad idea anyway?
It's probably becuase nav_code is not a pointer but a character array like char nav_code[50]. Try the following:
char nav_code[50];
char *nav_code_ptr = nav_code;
if (strlen(nav_code_ptr) == 10 ) {nav_code_ptr += 5;}
// forth on, use nav_code_ptr instead of nav_code
I am applying printf and/or other functions to a certain string of characters, read from a file. I want to skip the first 5 characters under certain conditions.
If printf is all what you need, then sure you can skip the first 5 characters.
Given nav_code is string (either char array or char pointer), then:
printf( "%s", nav_code + 5 ); // skip the first 5 characters
Of course you need to make sure your string has more than 5 characters, otherwise it's flat out illegal as out-of-bound access.
In your code, nav_code is an array and arrays cannot be assigned.
Instead, use a pointer, initialize that with the address of the first element of the array, make pointer arithmetic on that pointer and store the updated result back to the pointer.

Sscanf not returning what I want

I have the following problem:
sscanf is not returning the way I want it to.
This is the sscanf:
sscanf(naru,
"%s[^;]%s[^;]%s[^;]%s[^;]%f[^';']%f[^';']%[^;]%[^;]%[^;]%[^;]"
"%[^;]%[^;]%[^;]%[^;]%[^;]%[^;]%[^;]%[^;]%[^;]%[^;]%[^;]%[^;]"
"%[^;]%[^;]%[^;]%[^;]%[^;]%[^;]",
&jokeri, &paiva1, &keskilampo1, &minlampo1, &maxlampo1,
&paiva2, &keskilampo2, &minlampo2, &maxlampo2, &paiva3,
&keskilampo3, &minlampo3, &maxlampo3, &paiva4, &keskilampo4,
&minlampo4, &maxlampo4, &paiva5, &keskilampo5, &minlampo5,
&maxlampo5, &paiva6, &keskilampo6, &minlampo6, &maxlampo6,
&paiva7, &keskilampo7, &minlampo7, &maxlampo7);
The string it's scanning:
const char *str = "city;"
"2014-04-14;7.61;4.76;7.61;"
"2014-04-15;5.7;5.26;6.63;"
"2014-04-16;4.84;2.49;5.26;"
"2014-04-17;2.13;1.22;3.45;"
"2014-04-18;3;2.15;3.01;"
"2014-04-19;7.28;3.82;7.28;"
"2014-04-20;10.62;5.5;10.62;";
All of the variables are stored as char paiva1[22] etc; however, the sscanf isn't storing anything except the city correctly. I've been trying to stop each variable at ;.
Any help how to get it to store the dates etc correctly would be appreciated.
Or if there's a smarter way to do this, I'm open to suggestions.
There are multiple problems, but BLUEPIXY hit the first one — the scan-set notation doesn't follow %s.
Your first line of the format is:
"%s[^;]%s[^;]%s[^;]%s[^;]%f[^';']%f[^';']%[^;]%[^;]%[^;]%[^;]"
As it stands, it looks for a space separated word, followed by a [, a ^, a ;, and a ] (which is self-contradictory; the character after the string is a space or end of string).
The first fixup would be to use scan-sets properly:
"%[^;]%[^;]%[^;]%[^;]%f[^';']%f[^';']%[^;]%[^;]%[^;]%[^;]"
Now you have a problem that the first %[^;] scans everything up to the end of string or first semicolon, leaving nothing for the second %[;] to match.
"%[^;]; %[^;]; %[^;]; %[^;]; %f[^';']%f[^';']%[^;]%[^;]%[^;]%[^;]"
This looks for a string up to a semicolon, then for the semicolon, then optional white space, then repeats for three items. Apart from adding a length to limit the size of string, preventing overflow, these are fine. The %f is OK. The following material looks for an odd sequence of characters again.
However, when the data is looked at, it seems to consist of a city, and then seven sets of 'a date plus three numbers'.
You'd do better with an array of structures (if you've worked with those yet), or a set of 4 parallel arrays, and a loop:
char jokeri[30];
char paiva[7][30];
float keskilampo[7];
float minlampo[7];
float maxlampo[7];
int eoc; // End of conversion
int offset = 0;
char sep;
if (fscanf(str + offset, "%29[^;]%c%n", jokeri, &sep, &eoc) != 2 || sep != ';')
...report error...
offset += eoc;
for (int i = 0; i < 7; i++)
{
if (fscanf(str + offset, "%29[^;];%f;%f;%f%c%n", paiva[i],
&keskilampo[i], &minlampo[i], &maxlampo[i], &sep, &eoc) != 5 ||
sep != ';')
...report error...
offset += eoc;
}
See also How to use sscanf() in loops.
Now you have data that can be managed. The set of 29 separately named variables is a ghastly thought; the code using them will be horrid.
Note that the scan-set conversion specifications limit the string to a maximum length one shorter than the size of jokeri and the paiva array elements.
You might legitimately be wondering about why the code uses %c%n and &sep before &eoc. There is a reason, but it is subtle. Suppose that the sscanf() format string is:
"%29[^;];%f;%f;%f;%n"
Further, suppose there's a problem in the data that the semicolon after the third number is missing. The call to sscanf() will report that it made 4 successful conversions, but it doesn't count the %n as an assignment, so you can't tell that sscanf() didn't find a semicolon and therefore did not set &eoc at all; the value is left over from a previous call to sscanf(), or simply uninitialized. By using the %c to scan a value into sep, we get 5 returned on success, and we can be sure the %n was successful too. The code checks that the value in sep is in fact a semicolon and not something else.
You might want to consider a space before the semi-colons, and before the %c. They'll allow some other data strings to be converted that would not be matched otherwise. Spaces in a format string (outside a scan-set) indicate where optional white space may appear.
I would use strtok function to break your string into pieces using ; as a delimiter. Such a long format string may be a source of problems in future.

Remove redundant whitespace from string (in-place)

Ok so i posted earlier about trying to (without any prebuilt functions) remove additional spaces so
"this is <insert many spaces!> a test" would return
"this is a test"
Remove spaces from a string, but not at the beginning or end
As it was homework i asked for no full solutions and some kind people provided me with the following
"If you need to do it in place, then create two pointers. One pointing to the character being read and one to the character being copied. When you meet an extra space, then adapt the 'write' pointer to point to the next non space character. Copy to the read position the character pointed by the write character. Then advance the read and write pointers to the character after the character being copied."
The problem is i now want to fully smash my computer in to pieces as i am sooooo irritated by it. I didnt realise at the time i couldnt utilise the char array so was using array indexes to do it, i thought i could suss how to get it to work but now i am just using pointers i am finding it very hard. I really need some help, not full solutions. So far this is what i am doing;
1)create a pointer called write, so i no where to write to
2)create a pointer called read so i no where to read from
(both of these pointers will now point to the first element of the char array)
while (read != '\0')
if read == a space
add one to read
if read equals a space now
add one to write
while read != a space {
set write to = read
}
add one to both read and write
else
add one to read and write
write = read
Try just doing this yourself character by character on a piece of paper and work out what it is you are doing first, then translate that into code.
If you are still having trouble, try doing something simpler first, for example just copying a string character for character without worrying about the "remove duplicate spaces" part of it - just to make sure that you haven't made a silly mistake elsewhere.
The advice of trying to do it with pen and paper first is good. And it really doesn't matter if you do it with pointers or array indexing; you can either use a reader and a writer pointer, or a reader and a writer index.
Think about when you want to move the indices forward. You always move the write index forward after you write a character. You move the read index forward when you've read a character.
Perhaps you could start with some code that just moves over the string, but actually doesn't change it. And then you add the logic that skips additional spaces.
char p[] = "this is a test";
char *readptr = &p[0];
char *writeptr = &p[0];
int inspaces = 0;
while(*readptr) {
if(isspace(*readptr)) {
inspaces ++;
} else {
inspaces = 0;
}
if(inspaces <= 1) {
*writeptr = *readptr;
writeptr++;
}
readptr++;
}
*writeptr = 0;
Here's a solution that only has a single loop (no inner loop to skip spaces) and no state data:
dm9pZCBTdHJpcFNwYWNlcyAoY2hhciAqdGV4dCkNCnsNCiAgY2hhciAqc3JjID0gdGV4dCwgKmRl
c3QgPSB0ZXh0Ow0KICB3aGlsZSAoKnNyYykNCiAgew0KICAgICpkZXN0ID0gKihzcmMrKyk7DQog
ICAgaWYgKCpzcmMgIT0gJyAnIHx8ICpkZXN0ICE9ICcgJykNCiAgICB7DQogICAgICArK2Rlc3Q7
DQogICAgfQ0KICB9DQogICpkZXN0ID0gMDsNCn0NCg==
The above is Base64 encoded as this is a homework question. To decode, copy the above block and paste into this website to decode it (you'll need to check the "Decode" radio button).
assuming you're trying to write a function like:
void removeSpaces(char * str){
/* ... stuff that changes the contents of str[] */
}
You want to scan the string for consecutive spaces, so that your write pointer is always trailing your read pointer. Advance your read pointer to a place where you are pointing at a space, but the next character is not a space. If your read and write pointers are not the same, then your write pointer ought to be pointing at the beginning of a sequence of spaces. The difference between your write and read pointer (i.e. read_pointer - write_pointer) will tell you the number of consecutive spaces that need to be overwritten to close the gap. When there is a difference of greater than zero, (prefix) advance both pointers along by that many positions, copying characters as you go. When you're read pointer is at the end of the string ('\0'), you should be done.
Can you use regular expressions? If so, it might be really easy. Use a regex to replace \s{2,}? with a single space. The \s means any white space (tabs, spaces, carriage feeds...); {2,} means 2 or more; ? means non-greedy. (Disclaimer: my regex might not be the best one you could write, since I'm no regex pro. Also, it's .net syntax, so the regex library for C might have slightly different syntax.)
Why don't you do something like this:
make a second char** that is the same length as the first. As you run through the first array with your pointers keep an extra pointer on the last space you've seen. If the last space you saw was the previous element then you don't copy that char to the second array.
But I would start with something that runs through the char** by each character and prints out each char. If you can make that happen then you can work on actually copying them into a second char**.

Resources