I want to replace all special characters in a string with their escaped equivalences (\n \t \\ \"). My idea is to use reader and writer and then put \\ before any special character. I use an dynamic array/char pointer.
Since I am not so confident in my understanding of pointers I still tend to use sometimes more often arrays than pointers.
As usual with C I get mostly (only) garbage as an output. Where do I get this undefined behavior from? My code so far:
char *escapeChars(const char *src)
{
int i, counter = 0, j = 0;
size_t size = strlen(src) + 1;
char pr[size], *pw;
pr[0] = '\0';
strcat(pr, src); /*to get the constness away*/
pw = pr;
for(i = 0; i < ((int) sizeof(pr)); i++){
if(pr[i] == '\n' || pr[i] == '\t' || pr[i] == '\\' || pr[i] == '\"'){
counter++;
}
}
pw = malloc(sizeof(pr) + (size_t) counter);
for(i = 0; i <((int) sizeof(pr)); i++){
if(pr[i] != '\n' || pr[i] != '\t' || pr[i] != '\\' || pr[i] != '\"'){
pw[i+j] = pr[i];
} else {
pw[i+j] = '\\';
pw[i+j+1] = pr[i];
j++;
}
}
pw[i + j] = '\0';
return pw;
}
As an output I get totally wrong stuff. And I believe it fails when encounters the first special chararacter.
Original string: Some
string with "special characters". And \.
Result: Some
str
If anything is even slightly unclear, notify me.
You need to special case the replacement of '\n' to '\\' + 'n' etc.
There is no need to make a local copy of src to scan for special characters. You can simplify the code this way:
char *escapeChars(const char *src) {
int i, j;
char *pw;
for (i = j = 0; src[i] != '\0'; i++) {
if (src[i] == '\n' || src[i] == '\t' ||
src[i] == '\\' || src[i] == '\"') {
j++;
}
}
pw = malloc(i + j + 1);
for (i = j = 0; src[i] != '\0'; i++) {
switch (src[i]) {
case '\n': pw[i+j] = '\\'; pw[i+j+1] = 'n'; j++; break;
case '\t': pw[i+j] = '\\'; pw[i+j+1] = 't'; j++; break;
case '\\': pw[i+j] = '\\'; pw[i+j+1] = '\\'; j++; break;
case '\"': pw[i+j] = '\\'; pw[i+j+1] = '\"'; j++; break;
default: pw[i+j] = src[i]; break;
}
}
pw[i+j] = '\0';
return pw;
}
Note that you should also escape some other characters: '\r', and the non printing or non portable characters in the range 1 to 31 and 127 to 255 for ASCII. Escaping these as octal sequences is more work but manageable at your skill level.
Related
i'm a beginner to programming and I'm running into a problem. I think that this is quite basic but I have looked around everywhere and can't find a solution (probably because of my own lack of understanding). This is my code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int main() {
char inputString[999];
char inputArray[99][99];
int a = 0;
int b = 0;
fgets(inputString, sizeof inputString, stdin);
for(int i = 0; i <= (strlen(inputString)); i++) {
if(inputString[i] == ' ' || inputString[i] == '\0') {
inputArray[a][b] = '\0';
a++;
b = 0;
}
else {
inputArray[a][b] = inputString[i];
b++;
}
}
for (int i = 0; i < 99; i++) {
if (inputArray[i][0] == '\0') {
break;
}
for (int j = 0; j < 99; j++) {
iif (inputArray[i][0] == 'a' || inputArray[i][0] == 'e' || inputArray[i][0] == 'i' || inputArray[i][0] == 'o' || inputArray[i][0] == 'u' ||
inputArray[i][0] == 'A' || inputArray[i][0] == 'E' || inputArray[i][0] == 'I' || inputArray[i][0] == 'O' || inputArray[i][0] == 'U') {
if (inputArray[i][j] == '.') {
inputArray[i][j] = '\0';
if (inputArray[i][j] == '\0') {
inputArray[i][j] = 'm';
inputArray[i][j + 1] = 'o';
inputArray[i][j + 2] = 'o';
inputArray[i][j + 3] = '.';
inputArray[i][j + 4] = '\0';
i++;
j = 0;
}
}
else if (inputArray[i][j] == ',') {
inputArray[i][j] = '\0';
if (inputArray[i][j] == '\0') {
inputArray[i][j] = 'm';
inputArray[i][j + 1] = 'o';
inputArray[i][j + 2] = 'o';
inputArray[i][j + 3] = ',';
inputArray[i][j + 4] = '\0';
i++;
j = 0;
}
}
else {
if (inputArray[i][j] == '\0') {
inputArray[i][j] = 'm';
inputArray[i][j + 1] = 'o';
inputArray[i][j + 2] = 'o';
inputArray[i][j + 3] = '\0';
i++;
j = 0;
}
}
}
else if (inputArray[i][0] != 'a' || inputArray[i][0] != 'e' || inputArray[i][0] != 'i' || inputArray[i][0] != 'o' || inputArray[i][0] != 'u' ||
inputArray[i][0] != 'A' || inputArray[i][0] != 'E' || inputArray[i][0] != 'I' || inputArray[i][0] != 'O' || inputArray[i][0] != 'U' || inputArray[i][0] != '\0') {
printf("a");
i++;
j = 0;
}
}
}
for (int i = 0; i < 99; i++) {
printf("%s ", inputArray[i]);
if (inputArray[i][0] == '\0') {
break;
}
}
return 0;
}
Essentially I'm trying to input a string, separate them into words using a 2-D array, and then check if the first letters of each string in that array is a consonant or a vowel.
I'm using printf("a"); to test if my code works, but when i run the program and input something like "yo", this is the output:
yo
aaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaaayo
The letter "a" is printed 99 times, which is as many times as the inner for loop is ran, so i'm guessing it has something to do with the fact that the first element of every string in the array is also not a vowel and maybe it's a null character, so I tried adding if (inputArray[i][0] == '\0') { (like in the code), but it still doesn't work.
I'd really appreciate if you guys can help me out
EDIT: I changed the code a bit to make it more readable (thanks Benjamin Maurer!), but essentially what I'm trying to do in the first if statement is add "moo" to the end of a word if it starts with a vowel.
Your code starts normal, but why did you then switch from array notation to this absolute madness in the second loop with pointer dereferences? I'm not even going to try to understand that code, bc. it's unreadable.
According to your description, each of inputArray[i] is a string. So checking if inputArray[i][0] is a consontant/vowel should suffice, no?
#include <ctype.h>
#include <stdio.h>
// ...Read input...
for (int i = 0; i < 99; ++i) {
if (isalpha(inputArray[i][0])) {
char c = toupper(inputArray[i][0]);
switch (c) {
// Intentional fallthroughs
case 'A':
case 'E':
case 'I':
case 'O':
case 'U':
puts("is vowel!");
break;
default:
puts("is consonant");
}
}
}
Both isalpha and toupper are from ctype.h.
islapha checks whether the argument is an alphabetic latin character (a letter).
So my exercise is to sort words in 1D char array. My code is almost working, but it always skips the last char of the last word. Here is my code. I've added some comments to make it somehow readable. I know it's not brilliant code but I've just started with programming.
int main(void) {
char input[] = "If you are working on something that you really care about you dont have to be pushed The vision pulls you Steve Jobs";
sort_alphabetically(input);
printf("%s", input);
}
int sort_alphabetically(char tab[]) {
int j = 0, k = 0, i = 0, g = 0, f = 0, l = 0;
char tmp[1001];
char tmp2[501][1001];
while (tab[i] == ' ') // skipping leading whitespaces
i++;
for (j = i; tab[j] != '\0'; j++) {
if (tab[j] != ' ' && tab[j + 1] != '\0')
k++; // counting word length
else if (tab[j] == ' ' || tab[j + 1] == '\0' || tab[j + 1] == '\0') {
// copying word t0 2d array
for (g = k; g > 0; g--) {
tmp[l] = tab[j - g];
l++;
}
tmp[l] = 0;
strcpy(tmp2[f], tmp); // copying
f++; //words ++ in tmp2
k = 0;
l = 0;
tmp[0] = 0;
}
}
tab[0] = 0;
tmp[0] = 0;
for (j = 0; j < f; j++) {
for (i = 0; i < f - 1; i++) {
if (strcmp(tmp2[i], tmp2[i + 1]) > 0) { //sorting words in alphabeticall order
strcpy(tmp, tmp2[i]);
strcpy(tmp2[i], tmp2[i + 1]);
strcpy(tmp2[i + 1], tmp);
}
}
}
for (i = 0; i < f; i++) {
strcat(tab, tmp2[i]); // copying to tab
strcat(tab, " "); //adding spaces after each word
}
// removing whitespaces
for (i = 0; tab[i] == ' ' || tab[i] == '\t'; i++);
for (j = 0; tab[i]; i++) {
tab[j++] = tab[i];
}
tab[j] = '\0';
}
;
After running this code it cuts the s in last word (Jobs). If someone can help me with this spaghetti I would be so happy.
The problem was with how you were handling the null byte vs the space. In the space case, you were actually on the space when you copied the string. But in the null byte case, you were one before the null byte. This leads to an off-by-one error. You need to modify the code to avoid handling it differently for spaces and null bytes:
for (j = i; tab[j] != '\0'; j++) {
//In the space case, you are on the space, but in the \0 case
//you were one before it.
//Changed this if statement so that you always copy the string
//when you're at the last character.
if (tab[j + 1] == ' ' || tab[j + 1] == '\0') {
//k is a length, but we're using it as an index
//so we will need to adjust by one
for (g = k; g > 0; g--) {
tmp[l] = tab[j - g + 1];
l++;
}
}
else
{
k++;
}
}
I worked this out by putting print statements that showed me the value of tab[j] and the value of k at each cycle. Watching your program execute, either with print statements or a debugger, is usually the best way to diagnose these sorts of issues.
The problem you have is in copying characters to the tmp buffer when you reach the end of the input (tab) string; that is, when tab[j + 1] == '\0' is true. In this case, you aren't copying the last data in this the for loop:
for (g = k; g > 0; g--) {
tmp[l] = tab[j - g];
l++;
}
To fix the issue, simply change the loop's 'condition' to include when g is zero, and skip this 'iteration' when you encounter a space character:
for (g = k; g >= 0; g--) { // Make sure to include any 'last' character
if (tab[j - g] != ' ') { // ... but skip if this is a space
tmp[l] = tab[j - g];
l++;
}
}
Note also that you have a redundant test in this line:
else if (tab[j] == ' ' || tab[j + 1] == '\0' || tab[j + 1] == '\0') {
which could just as well be written without the third test (which is the same as the second), thus:
else if (tab[j] == ' ' || tab[j + 1] == '\0') {
Caveat: Most of the other responders have pointed out the major bugs in your code, but this has some smaller ones and some simplification.
Before doing strcat back to tab, we should do tab[0] = 0 so the initial strcat works correctly.
Doing strcat(tab," ") after the one that copies the word goes one beyond the end of tab and is, therefore, undefined behavior. It also requires an unnecessary cleanup loop to remove the extra space that should not have been there in the first place.
The initial "split into words" loop can be [greatly] simplified.
There are some standard speedups to the bubble sort
I realize that you're just starting out [and some schools actually advocate for i, j, etc], but it's better to use some [more] discriptive names
Anyway, here's a somewhat refactored version:
#include <stdio.h>
#include <string.h>
int opt_dbg;
#define dbg(_fmt...) \
if (opt_dbg) \
printf(_fmt)
void
sort_alphabetically(char tab[])
{
char tmp[1001];
char words[501][1001];
char *src;
char *dst;
char *beg;
int chr;
int wordidx;
int wordcnt;
wordidx = 0;
dst = words[wordidx];
beg = dst;
// split up string into individual words
src = tab;
for (chr = *src++; chr != 0; chr = *src++) {
switch (chr) {
case ' ':
case '\t':
// wait until we've seen a non-white char before we start a new
// word
if (dst <= beg)
break;
// finish prior word
*dst = 0;
// point to start of next word
dst = words[++wordidx];
beg = dst;
break;
default:
*dst++ = chr;
break;
}
}
// finish last word
*dst = 0;
// get number of words
wordcnt = wordidx + 1;
if (opt_dbg) {
for (wordidx = 0; wordidx < wordcnt; ++wordidx)
dbg("SPLIT: '%s'\n",words[wordidx]);
}
// in bubble sort, after a given pass, the _last_ element is guaranteed to
// be the largest, so we don't need to examine it again
for (int passlim = wordcnt - 1; passlim >= 1; --passlim) {
int swapflg = 0;
// sorting words in alphabetical order
for (wordidx = 0; wordidx < passlim; ++wordidx) {
char *lhs = words[wordidx];
char *rhs = words[wordidx + 1];
if (strcmp(lhs,rhs) > 0) {
dbg("SWAP/%d: '%s' '%s'\n",passlim,lhs,rhs);
strcpy(tmp,lhs);
strcpy(lhs,rhs);
strcpy(rhs,tmp);
swapflg = 1;
}
}
// if nothing got swapped, we can stop early (i.e. everything is in
// sort)
if (! swapflg)
break;
}
// clear out destination so [first] strcat will work
tab[0] = 0;
// copy back words into original string
// adding the space as a _prefix_ before a word eliminates the need for a
// cleanup to remove the last space
for (wordidx = 0; wordidx < wordcnt; ++wordidx) {
dbg("SORTED: '%s'\n",words[wordidx]);
// adding spaces before each word
if (wordidx > 0)
strcat(tab, " ");
// copying to tab
strcat(tab,words[wordidx]);
}
}
int
main(int argc,char **argv)
{
char input[] = "If you are working on something that you really care"
" about you dont have to be pushed The vision pulls you Steve Jobs";
--argc;
++argv;
for (; argc > 0; --argc, ++argv) {
char *cp = *argv;
if (*cp != '-')
break;
switch (cp[1]) {
case 'd':
opt_dbg = ! opt_dbg;
break;
}
}
sort_alphabetically(input);
printf("%s\n", input);
return 0;
}
The following program runs without printing anything on the screen, maybe because the loop goes over the null character. I can't understand why and how this happens, and how to fix it.
//program to find how many word in the text doesn't contain p char
#include<stdio.h>
#include<stdbool.h>
#define space ' '
void find_word(char s[]) {
bool wordfound = false;
int i, j = 0, word = 0;
i = 0;
while (s[i]) { //s[i]!='\0' does not
if (s[i] != 'p' && s[i + 1] != space) { //for the first word
wordfound = true;
word++;
}
wordfound = false;
if (s[i] == space && s[i + 1] != space) { //for more than one word in the text
for (j = i + 1; s[j] != space; j++)
if (s[j] != 'p' && s[j + 1] != space)
wordfound = true;
}
if (wordfound) {
word++;
}
wordfound = false;
i = j;
i++;
} //end while loop
printf("Number of words not contain p character%d\n\n", word);
}
int main(void) {
char s[] = {"pppp zzzz ppp ssss dfg sfsfdsf"};
find_word(s);
return 0;
}
There are a few problems with this code, but the main one is that inside the loop you assign j to i which causes the infinite loop as the while(s[i]) condition is never met. Why don't you try to make it simple, like so:
//program to find how many word in the text doesn't contain p char
#include<stdio.h>
#include<stdbool.h>
#define space ' '
void find_word(char s[]) {
bool is_in = false;
short words_count = 0, i = 0;
while (s[i]) {
if (s[i] == 'p') { // if this letter is a 'p', mark the word
is_in = true;
}
if (s[i] == space) { // if it's end of word
if (!is_in) { // check if 'p' is present and increase the count
words_count++;
}
is_in = false;
}
i++;
}
if (!is_in) { // check if the last word has 'p'
words_count++;
}
printf("no. of words without p is %d\n", words_count);
}
int main(void) {
char s[] = {"pppp zzzz ppp ssss dfg sfsfdsf"};
find_word(s);
return 0;
}
You appear to have your for-loop terminating condition set to be unsatisfiable given your input.
if (s[i] == space && s[i + 1] != space) { //for more than one word in the text
for (j = i + 1; s[j] != space; j++)
if (s[j] != 'p' && s[j + 1] != space)
wordfound = true;
}
Here you are checking for a leading space in your input string. If you find it you then increment your index checking until you reach another space. What if your string doesn't have a trailing space?
Instead try to have a second condition for null and space to terminate the loop:
if (s[i] == space && s[i + 1] != space) { //for more than one word in the text
for (j = i + 1; s[j] != '\0' && [j] != space; j++)
if (s[j] != 'p' && s[j + 1] != space)
wordfound = true;
}
And then you set:
wordfound = false;
i = j;
i++;
} //end while loop
This will keep re-setting your loop, I'm not clear on your reasoning for this but that will run your loop indefinitely.
If you make these edits your code terminates:
#include<stdio.h>
#include<stdbool.h>
#define space ' '
void find_word(char s[]) {
bool wordfound = false;
int i, j = 0, word = 0;
i = 0;
while (s[i]) { //s[i]!='\0' does not
if (s[i] != 'p' && s[i + 1] != space) { //for the first word
wordfound = true;
word++;
}
wordfound = false;
if (s[i] == space && s[i + 1] != space) { //for more than one word in the text
for (j = i + 1; s[j] && s[j] != space; j++)
if (s[j] != 'p' && s[j + 1] != space)
wordfound = true;
}
if (wordfound) {
word++;
}
wordfound = false;
i++;
} //end while loop
printf("Number of words not contain p character%d\n\n", word);
}
int main(void) {
char s[] = {"pppp zzzz ppp ssss dfg sfsfdsf"};
find_word(s);
return 0;
}
Output:
Number of words not contain p character24
I have been trying to figure out how to count the vowels and characters in each word of a sentance.
For example
In hello there sentence
hello : 5 characters, 2 vowels
there : 5 characters, 2 vowels. I have seen the code for doing the same thing for a full sentence. But not word by word.
Below is the coding I've been working on
int main() {
char str[512] = "hello there", word[256];
int i = 0, j = 0, v, h;
str[strlen(str)] = '\0';
/* checking whether the input string is NULL */
if (str[0] == '\0') {
printf("Input string is NULL\n");
return 0;
}
/* printing words in the given string */
while (str[i] != '\0') {
/* ' ' is the separator to split words */
if (str[i] == ' ')
{
for (h = 0; word[h] != '\0'; ++h)
{
if (word[h] == 'a' || word[h] == 'e' || word[h] == 'i' || word[h] == 'o' || word[h] == 'u')++v;
}
printf("\nVowels: %d", v);
word[j] = '\0';
printf("%s\n", word);
j = 0;
}
else
{
word[j++] = str[i];
}
i++;
}
word[j] = '\0';
/* printing last word in the input string */
printf("%s\n", word);
return 0;
}
The input will be all lower case. I'm having a hard time figuring this out.
While running the code I'm not getting the vowels count. I'm able to split the sentence. But vowel counting is not happening.
One fairly simple approach:
#include <stdio.h>
const char* s(int n)
{
return n == 1? "" : "s";
}
void count (const char* str)
{
for (int i = 0;;)
for (int v = 0, w = i;;)
{
int len;
char c = str[i++];
switch (c)
{
case 'a': case 'e': case 'i': case 'o': case 'u':
v++;
default:
continue;
case ' ': case '\t': case '\n': case '\0':
len = i - 1 - w;
printf("'%.*s': %d character%s, %d vowel%s\n", len, str+w, len, s(len), v, s(v));
if (c)
break;
else
return;
}
break;
}
}
int main(void)
{
count("My words with vowels");
return 0;
}
This sounds an awful lot like a homework assignment..
here's some pseudo-code <-- below will NOT run as is. Just to show logic.
int c = 0;
int v = 0;
for (int i = 0; i < lengthOfSentence; i++){
if (stringName[i] == '\0') { //optionally '\n' may be more suitable
return;
}
if (stringName[i] == ' '){
print previousWord // + c, v in whatever format you want
c = 0;
v = 0;
}
if (stringName[i] == vowel) { //you can do this part like in your code
word[v+c] = stringName[i]; //get current char and add to next slot
v++;
}
else {
word[v+c] = stringName[i];
c++;
}
beyond that it's minute details like realizing v+c will give you total word length when printing, etc..
Try this code. it might help you
#include<stdio.h>
int main() {
char str[512] = "hello there", word[256];
int i = 0, j = 0, v=0,h; // you didn't initialize v to 0
str[strlen(str)] = '\0';
/* checking whether the input string is NULL */
if (str[0] == '\0') {
printf("Input string is NULL\n");
return 0;
}
/* printing words in the given string */
while (str[i] != '\0') {
/* ' ' is the separator to split words */
if (str[i] == ' ' ) {
for (h = 0; word[h] != '\0'; h++) {
if (word[h] == 'a' || word[h] == 'e' || word[h] == 'i' || word[h] == 'o' || word[h] == 'u')
v++;
}
printf("%s :", word);
printf(" %d chracters,",strlen(word));
printf(" %d Vowels.\n", v);
j = 0; v=0;
word[j] = '\0';
} else {
word[j++] = str[i];
word[j] = '\0';
}
i++;
}
/* calculating vowels in the last word*/ // when NULL occurs, Wont enter into while loop.
for (h = 0; word[h] != '\0'; h++) {
if (word[h] == 'a' || word[h] == 'e' || word[h] == 'i' || word[h] == 'o' || word[h] == 'u')
v++;
}
printf("%s :", word);
printf(" %d chracters,",strlen(word));
printf(" %d Vowels.\n", v);
return 0;
}
What you can probably do is, you can print the count for the characters and vowels when you encounter a " "(space) and then reset the counters. That way, you can find the characters and vowels for each word of the sentence.
If you understand the logic for doing this throughout a sentence, then you can also do it in single words by simple breaking the sentence into individual word and applying the same logic to each word. You can use the fact that words are separated by a space (or multiple, maybe) to break down the sentence into words.
I am trying to remove all quotes in a given line except a backslash followed by a quote
what I have done is this
for (int i = 0; i < lineLength; i ++) {
if (line[i] == '"' ) {
if (line[i-1] == '\\') // if \" is used
line[i-1] = '"'; // then print \
line[i] = '\0'; // or 0
}
}
This removes all characters in the line.. what can I do to remove only quotes?
Any help would be appreciated...
Your problem is line[i] = '\0'; - it terminates the string.
If you want to remove characters from a C string, you need to hold two indices - one for reading and one for writing, loop over the read index reading each character, and write only the ones you want to keep using the second index.
Something along the lines of:
int j = 0;
for (int i = 0; i < lineLength; i ++) {
if (line[i] != '"' && line[i] != '\\') {
line[j++] = line[i];
} else if (line[i+1] == '"' && line[i] == '\\') {
line[j++] = '"';
} else if (line[i+1] != '"' && line[i] == '\\') {
line[j++] = '\\';
}
}
//You missed the string termination ;)
if(j>0) line[j]=0;
You are setting the first " character you find to the null character, terminating the string.
Also an aside, but line[i-1] could cause a segmentation fault when i == 0, or it could happen to contain \ in which case the first quote wouldn't be stripped.
Something like this will do what you want:
char *lineWithoutQuotes = malloc(strlen(line));
int i, j;
if(line[0] != '"')
lineWithoutQuotes[0] = line[0];
for(i = j = 1; i < strlen(line); i++){
if(line[i] == '"' && line[i-1] != '\\')
continue;
lineWithoutQuotes[j++] = line[i];
}
The normal technique using indexes is:
int j = 0;
for (int i = 0; i < lineLength; i++)
{
if (line[i] == '\\')
{
line[j++] = line[i++];
line[j++] = line[i];
if (line[i] == '\0')
break;
}
else if (line[i] != '"')
line[j++] = line[i];
}
line[j] = '\0';
Using pointers (and not needing lineLength), it is:
char *dst = line;
char *src = line;
char c;
while ((c = *src++) != '\0')
{
if (c == '\\')
{
*dst++ = c;
if ((c = *src++) == '\0')
break;
*dst++ = c;
}
else if (c != '"')
*dst++ = c;
}
*dst = '\0';
Or minor variations on those themes...
int newPos = 0;
for (int oldPos = 0; oldPos < lineLength; oldPos++) {
if (!(line[newPos] == '"' && (!newPos || line[newPos-1] == '\\'))) {
line[newPos] = line[oldPos];
newPos++;
}
}
line[newPos] = 0;