removing last character from strings in two dimensional array - c

How can I remove the '\n' from each string in this array?
I know that I can do something like this for a simple C-String, but I failed at using it in this case
cmd[strcspn(cmd, "\n")] = '\0';
I am also not sure if that would be the propper way or not.
The String will never contain any space or \n in the middle. They are also of a static length (6).
#include <stdlib.h>
unsigned char cmd[][6] = {
{"r123\n"},
{"r999\n"},
{"l092\n"},
{"l420\n"}};
void main(void) {
int i;
for(i = 0; i < (sizeof(cmd) / sizeof(cmd[0])); i++) {
printf("%s\n", cmd[i]);
}
}

Just do it by hand, it's easy!
If it's guaranteed to be only the last char in every word, and it's guaranteed to be there, than like this:
for (i = 0; i < elem_number; ++i){
cmd[i][strlen(cmd[i])-1] = 0;
}
If, on the other hand, you are unsure how many whitespace characters there will be at the end, but you know they will only be there at the end (there might be 0 in this case!) than this:
for (i = 0; i < elem_number; ++i){
for (j = 0; cmd[i][j] != 0; ++j){
if (isspace(cmd[i][j]))
cmd[i][j] = 0;
}
}
Voila!
If there will be whitespaces in the middle, then you have to define the desired behaviour: cut only the trailing whitespaces, cut the string in many little ones, or something completely different.
Oh, and one other sidenote:
everyone else seems to be using char = '\0'. In C, '\0' and 0 are equivalent, i.e. if ('\0' == 0) { ... } evaluates to true.
Sidenote 2: I used elem_number because I did not know if the number of elements is a parameter or hardcoded / know in advance. Substitute with what is appropriate.

Setting a character in a char array to \0 will truncate the string at that character.
So in your example setting the 5th character will do the job.
cmd[i][4] = '\0';
If the intended string can be less than 4 in length then don't hard-code to 4 but rather strlen(cmd[i])-1

Maybe you can use strrchr? Use in a loop if the string may contain several linebreaks.

for(i = 0; i< sizeof(cmd)/sizeof(unsigned char[6]);i++)
*strchr(cmd[i], '\n') = '\0';

Related

How do I replace all occurrences in an array with another array in C

I want to replace all occurrences in an array (string) with another array.
I have a code that:
stores the string in an array in which the replacing is to take place output[],
another array that stores the string to be searched for as replace[] and a third array called toBeReplacedBy and the replacing of the first occurrence works just fine but it skips the other occurrences in the output
for example:
replace[]:
abc
toBeReplacedBy[]:
xyz
output[]:
abcdefabc
becomes
xyzdefabc
but it should become:
xyzdefxyz
I suspect the problem lies with the replacer code :
//the replacer
for (i = 0; i<80; i++) {
if (output[i] == replace[i])
output[i] = toBeReplacedBy[i];
}
//debug purpose
puts("output[]:\n");
puts(output);
return 0;
}
What have I done wrong here and how could I get it to replace all occurrences in the array.
please be aware that I only wish to use stdio.h to do this
thabks in advance
Never iterate further than the array length. This leads to undefined and possibly dangerous behaviour. If you only expect strings, use something like:
int i = 0;
while(output[i] != '\0')
{
// your logic here
i++;
}
Additionally you want to check for concurrent appearances of the same characters. But in your code you only check the first three characters. Everything after that is undefinded behaviour, because you cannot know what replace[3] returns.
Something similar to this could work:
int i = 0;
int j = 0;
int k;
while(output[i] != '\0')
{
if (output[i] == replace[j])
j++;
else
j = 0;
// replace 3 with the array length of the replace[] array
if (j == 3)
{
for(k = i; j >= 0; k-- )
{
output[k] = toBeReplacedBy[j]
j--
}
j = 0;
}
i++;
}
But please check the array boundaries.
edit: Additionally as Nellie states using a debugger would help you to understand what went wrong. Go through your program step by step and look how and when values change.
First advice is to try to debug your program if it does not work.
for (i = 0; i<80; i++) {
if (output[i] == replace[i])
output[i] = toBeReplacedBy[i];
}
There are two problems in this loop.
The first is that are iterating until i is 80. Let's look what happens when i becomes 3. output[3] in case of abcdefabc is d, but what is replace[3]? Your replacement array had only 3 letters, so you have to go back in the replacement array once you finish with one occurrence of it in the original string.
The second is that you check letter by letter.
Say you original array, which you named output somehow was abkdefabc, first three letters do not match your replacement string, but you will check the first two letters they will match with the replacement's first two letters and you will incorrectly change them.
So you need to first check that the whole replacement string is there and only then replace.
You should use strlen() to know length of your array or iterate until you reach the end of a your array ('\0').
'\0' and strlen are only available for array of char.
Your loop should looks like this :
int i = 0;
int len = strlen(my_string);
while (i < len)
{
//logic here
i = i + 1;
}
OR
int i = 0;
while (my_string[i] != '\0')
{
// logic here
i = i + 1;
}

2D string array is storing '\0' when it encounters a word with more than one space or digit

I am pretty new to C programming. My program is supposed to take a string and move it into a 2D array. With the words either being separated by a white-space or a digit. This works perfectly fine if there is one space or digit separating it. However, as soon as there is more than one it starts adding '\0' to my array.
//Move the string into a 2D array
for(i = 0; i < total + 1; i++)
{
if(isalpha( *(tempString + i) ))
{
sortingArray[n][j++] = tempString[i];
input++;
}
else
{
sortingArray[n][j++] = '\0';
n++;
j = 0;
}
if(tempString[i] == '\0')
break;
}
This is a sample of what happens (n = number of rows placed)
./a.out "one more way"
5 inputs
before
one
more
way
After
one
more
way
You need to skip consecutive delimiters:
for(i = 0; i < total; i++)
{
if(isalpha(tempString[i]))
{
sortingArray[n][j] = tempString[i];
++j;
++input;
}
else
{
// skip consecutive delimiters
while (i < total && !isalpha(tempString[i]))
++i;
sortingArray[n][j] = '\0';
++j
++n;
j = 0;
}
}
Disclaimer: not verified by a compiler. Use caution!
I also took the liberty of some improvements to your original code.
there is no sense to check for \0 if you have the length of the string.
changed *(tempString + i) to the clear tempString[i]
moved the increments out of the larger expressions into their own full expression. It is clearer this way.
It's a simple logic failure for which a debugger is ideal for identifying.
Imagine you have the string "hello world".
It stores "hello" into sortingArray[0] easily enough. When it gets to the first space it increments n and starts looking for the next word. But the next character it finds is another space so it increments n again.
A slight change is required to your logic
if(isalpha( *(tempString + i) ))
{
sortingArray[n][j++] = tempString[i];
input++;
}
else if(j>0)
{
sortingArray[n][j++] = '\0';
n++;
j = 0;
}
Now the code will only increment n if the previous character was a letter (by virtue of j being more than 0). Otherwise if it doesn't care and will keep going.
You should also check to see if j is non-zero after the loop as that means there is a new entry in sortingArray that needs a NUL added.
One thing also to note is that the way you're doing the for loop is a little odd. You have this
for(i = 0; i < total + 1; i++)
but also this inside the loop
if(tempString[i] == '\0')
break;
Typically, the way to terminate the for loop would be to write it like this
for(i = 0; tempString[i]!='\0'; i++)
as that way you firstly don't care about the length of the string, but the loop will finish when it hits the NUL character.

Pointers to string C

trying to write function that returns 1 if every letter in “word” appears in “s”.
for example:

containsLetters1("this_is_a_long_string","gas") returns 1
containsLetters1("this_is_a_longstring","gaz") returns 0
containsLetters1("hello","p") returns 0
Can't understand why its not right:
#include <stdio.h>
#include <string.h>
#define MAX_STRING 100
int containsLetters1(char *s, char *word)
{
int j,i, flag;
long len;
len=strlen(word);
for (i=0; i<=len; i++) {
flag=0;
for (j=0; j<MAX_STRING; j++) {
if (word==s) {
flag=1;
word++;
s++;
break;
}
s++;
}
if (flag==0) {
break;
}
}
return flag;
}
int main() {
char string1[MAX_STRING] , string2[MAX_STRING] ;
printf("Enter 2 strings for containsLetters1\n");
scanf ("%s %s", string1, string2);
printf("Return value from containsLetters1 is: %d\n",containsLetters1(string1,string2));
return 0;
Try these:
for (i=0; i < len; i++)... (use < instead of <=, since otherwise you would take one additional character);
if (word==s) should be if (*word==*s) (you compare characters stored at the pointed locations, not pointers);
Pointer s advances, but it should get back to the start of the word s, after reaching its end, i.e. s -= len after the for (j=...);
s++ after word++ is not needed, you advance the pointer by the same amount, whether or not you found a match;
flag should be initialized with 1 when declared.
Ah, that should be if(*word == *s) you need to use the indirection operator. Also as hackss said, the flag = 0; must be outside the first for() loop.
Unrelated but probably replace scanf with fgets or use scanf with length specifier For example
scanf("%99s",string1)
Things I can see wrong at first glance:
Your loop goes over MAX_STRING, it only needs to go over the length of s.
Your iteration should cover only the length of the string, but indexes start at 0 and not 1. for (i=0; i<=len; i++) is not correct.
You should also compare the contents of the pointer and not the pointers themselves. if(*word == *s)
The pointer advance logic is incorrect. Maybe treating the pointer as an array could simplify your logic.
Another unrelated point: A different algorithm is to hash the characters of string1 to a map, then check each character of the string2 and see if it is present in the map. If all characters are present then return 1 and when you encounter the first one that is not present then return 0. If you are only limited to using ASCII characters a hashing function is very easy. The longer your ASCII strings are the better the performance of the second approach.
Here is a one-liner solution, in keeping with Henry Spencer's Commandment 7 for C Programmers.
#include <string.h>
/*
* Does l contain every character that appears in r?
*
* Note degenerate cases: true if r is an empty string, even if l is empty.
*/
int contains(const char *l, const char *r)
{
return strspn(r, l) == strlen(r);
}
However, the problem statement is not about characters, but about letters. To solve the problem as literally given in the question, we must remove non-letters from the right string. For instance if r is the word error-prone, and l does not contain a hyphen, then the function returns 0, even if l contains every letter in r.
If we are allowed to modify the string r in place, then what we can do is replace every non-letter in the string with one of the letters that it does contain. (If it contains no letters, then we can just turn it into an empty string.)
void nuke_non_letters(char *r)
{
static const char *alpha =
"abcdefghijklmnopqrstuvwxyz"
"ABCDEFGHIJKLMNOPQRSTUVWXYZ";
while (*r) {
size_t letter_span = strspn(r, alpha);
size_t non_letter_span = strcspn(r + letter_span, alpha);
char replace = (letter_span != 0) ? *r : 0;
memset(r + letter_span, replace, non_letter_span);
r += letter_span + non_letter_span;
}
}
This also brings up another flaw: letters can be upper and lower case. If the right string is A, and the left one contains only a lower-case a, then we have failure.
One way to fix it is to filter the characters of both strings through tolower or toupper.
A third problem is that a letter is more than just the 26 letters of the English alphabet. A modern program should work with wide characters and recognize all Unicode letters as such so that it works in any language.
By the time we deal with all that, we may well surpass the length of some of the other answers.
Extending the idea in Rajiv's answer, you might build the character map incrementally, as in containsLetters2() below.
The containsLetters1() function is a simple brute force implementation using the standard string functions. If there are N characters in the string (haystack) and M in the word (needle), it has a worst-case performance of O(N*M) when the characters of the word being looked for only appear at the very end of the searched string. The strchr(needle, needle[i]) >= &needle[i] test is an optimization if there are likely to be repeated characters in the needle; if there won't be any repeats, it is a pessimization (but it can be removed and the code still works fine).
The containsLetters2() function searches through the string (haystack) at most once and searches through the word (needle) at most once, for a worst case performance of O(N+M).
#include <assert.h>
#include <stdio.h>
#include <string.h>
static int containsLetters1(char const *haystack, char const *needle)
{
for (int i = 0; needle[i] != '\0'; i++)
{
if (strchr(needle, needle[i]) >= &needle[i] &&
strchr(haystack, needle[i]) == 0)
return 0;
}
return 1;
}
static int containsLetters2(char const *haystack, char const *needle)
{
char map[256] = { 0 };
size_t j = 0;
for (int i = 0; needle[i] != '\0'; i++)
{
unsigned char c_needle = needle[i];
if (map[c_needle] == 0)
{
/* We don't know whether needle[i] is in the haystack yet */
unsigned char c_stack;
do
{
c_stack = haystack[j++];
if (c_stack == 0)
return 0;
map[c_stack] = 1;
} while (c_stack != c_needle);
}
}
return 1;
}
int main(void)
{
assert(containsLetters1("this_is_a_long_string","gagahats") == 1);
assert(containsLetters1("this_is_a_longstring","gaz") == 0);
assert(containsLetters1("hello","p") == 0);
assert(containsLetters2("this_is_a_long_string","gagahats") == 1);
assert(containsLetters2("this_is_a_longstring","gaz") == 0);
assert(containsLetters2("hello","p") == 0);
}
Since you can see the entire scope of the testing, this is not anything like thoroughly tested, but I believe it should work fine, regardless of how many repeats there are in the needle.

How to solve this output in C?

I have to search a substring in a string & display the complete word as given below everytime the substring is found-
eg:
Input: excellent
Output: excellent,excellently
I cannot figure out how to make the output like the one above.
My output:
excellent,excellently,
It always give me a comma in the end.
Prog: desc
Iteratively convert every words in the dictionary into lowercase,
and store the converted word in lower.
Use strncmp to compare the first len characters of input_str and lower.
If the return value of strncmp is 0, then the first len characters
of the two strings are the same.
void complete(char *input_str)
{
int len = strlen(input_str);
int i, j, found;
char lower[30];
found = 0;
for(i=0;i<n_words;i++)
{
for(j=0;j<strlen(dictionary[i]);j++)
{
lower[j] = tolower(dictionary[i][j]);
}
lower[j+1]='\0';
found=strncmp(input_str,lower,len);
if(found==0)//found the string n print out
{
printf("%s",dictionary[i]);
printf(",");
}
}
if (!found) {
printf("None.\n");
} else {
printf("\n");
}
}
Check if you have already printed a word before printing a second one:
char printed = 0;
for (i=0; i < n_words; i++)
{
for(j = 0; j < strlen(dictionary[i]); j++)
lower[j] = tolower(dictionary[i][j]);
lower[j + 1] = '\0';
found = strncmp(input_str, lower, len);
if (found == 0)//found the string n print out
{
if (printed)
printf(",");
printf("%s", dictionary[i]);
printed = 1;
}
}
There are two approaches that I tend to use for the comma-printing problem:
At the start of the loop, print the comma if i > 0.
At the end (after printing the real value), print the comma if i < (n - 1).
You can use either, the first is simpler since the comparison is simpler, but it can be slightly less convenient since it moves the comma-printing in time (!). On each loop iteration, you're printing the comma that belongs to the previous iteration. At least that how it's feels to me, but of course it's rather subjective.

Strip numbers from a string in C

I'm looking for a simple solution for stripping numbers from a string.
Example: "GA1UXT4D9EE1" => "GAUXTDEE"
The occurrence of the numbers inside the string is erratic hence I cannot rely on functions such as scanf().
I'm new at programming in C.
Thanks for any help.
I will give you some tips:
You need to creat a new string.
Iterat over the original string.
Check if the current character is between the ascii values of numbers
If not, add it to the new string.
char stringToStrip[128];
char stripped[128];
strcpy(stringToStrip,"GA1UXT4D9EE1");
const int stringLen = strlen(stringToStrip);
int j = 0;
char currentChar;
for( int i = 0; i < stringLen; ++i ) {
currentChar = stringToStrip[i];
if ((currentChar < '0') || (currentChar > '9')) {
stripped[j++] = currentChar;
}
}
stripped[j] = '\0';
iterate through the string and check for the ascii value.
for(i = 0; i < strlen(str); i++)
{
if(str[i] >= 48 && str[i] <= 57)
{
// do something
}
}
I would agree that walking through would be an easy way to do it, but there is also an easier function to do this. You can use isdigit(). C++ documentation has an awesome example. (Don't worry, this also works in c.)
http://www.cplusplus.com/reference/cctype/isdigit/
Here is the code to do it.
int i;
int strLength = strlen(OriginalString);
int resultPosCtr = 0;
char *result = malloc(sizeof(char) * strLength);//Allocates room for string.
for(i = 0; i < strLength; i++){
if(!isdigit(OriginalString[i])){
result[resultPosCtr] = OriginalString[i];
resultPosCtr++;
}
}
result[resultPosCtr++] = '\0'; //This line adds the sentinel value A.K.A the NULL Value that marks the end of a c style string.
Everyone has it right.
Create a new char[] A.K.A. C style string.
Iterate over the original string
Check to see if the character at that iteration is a number
if not add to new string

Resources