K&R replace multiple spaces with single space - c

#include <stdio.h>
#define MAXLENGTH 1000
void get_input(char ch[], int maxline);
void replace_blanks(char ch[], int z);
int main(void)
{
char ch[MAXLENGTH];
int z;
z = 0;
printf("Please enter some input. ");
get_input(ch,MAXLENGTH);
replace_blanks(ch,MAXLENGTH);
while(putchar(ch[z]) != EOF)
{
++z;
}
return 0;
}
void get_input(char ch[], int lim)
{
int z, i;
z = 0;
while((i = getchar()) != EOF && z < lim-1 && i != '\n')
{
ch[z] = i;
z++;
}
if(i == '\n')
{
ch[z] = i;
z++;
}
ch[z] = '\0';
}
void replace_blanks(char ch[], int lim)
{
char ch_copy[lim];
int i, arrayindex, copy_counter;
copy_counter = 0;
arrayindex = 0;
i = arrayindex;
while(ch[arrayindex] != EOF && arrayindex < lim-1){
if(ch[arrayindex] != ' '){
ch_copy[copy_counter] = ch[arrayindex];
i = arrayindex;
arrayindex++;
copy_counter++;
}
else if(ch[arrayindex] == ' ' && ch[i] != ' '){
ch_copy[copy_counter] = ch[arrayindex];
i = arrayindex;
arrayindex++;
copy_counter++;
} else {
i = arrayindex;
arrayindex++;
}
}
ch_copy[arrayindex] = '\0';
for(arrayindex = 0; ch_copy[arrayindex] != EOF && arrayindex < lim-1; arrayindex++){
printf("%d", arrayindex);
ch[arrayindex] = ch_copy[arrayindex];
}
ch[arrayindex] = '\0';
}
Output from this functon from the printf() is
Please enter some input. hello hi
0123456789101112131415161718192021222324252627282930313233343536373839404142434445464748495051525354555657585960616263646566676869707172737475767778798081828384858687888990919293949596979899100101102103104105106107108109110111112113114115116117118119120121122123124125126127128129130131132133134135136137138139140141142143144145146147148149150151152153154155156157158159160161162163164165166167168169170171172173174175176177178179180181182183184185186187188189190191192193194195196197198199200201202203204205206207208209210211212213214215216217218219220221222223224225226227228229230231232233234235236237238239240241242243244245246247248249250251252253254255256257258259260261262263264265266267268269270271272273274275276277278279280281282283284285286287288289290291292293294295296297298299300301302303304305306307308309310311312313314315316317318319320321322323324325326327328329330331332333334335336337338339340341342343344345346347348349350351352353354355356357358359360361362363364365366367368369370371372373374375376377378379380381382383384385386387388389390391392393394395396397398399400401402403404405406407408409410411412413414415416417418419420421422423424425426427428429430431432433434435436437438439440441442443444445446447448449450451452453454455456457458459460461462463464465466467468469470471472473474475476477478479480481482483484485486487488489490491492493494495496497498499500501502503504505506507508509510511512513514515516517518519520521522523524525526527528529530531532533534535536537538539540541542543544545546547548549550551552553554555556557558559560561562563564565566567568569570571572573574575576577578579580581582583584585586587588589590591592593594595596597598599600601602603604605606607608609610611612613614615616617618619620621622623624625626627628629630631632633634635636637638639640641642643644645646647648649650651652653654655656657658659660661662663664665666667668669670671672673674675676677678679680681682683684685686687688689690691692693694695696697698699700701702703704705706707708709710711712713714715716717718719720721722723724725726727728729730731732733734735736737738739740741742743744745746747748749750751752753754755756757758759760761762763764765766767768769770771772773774775776777778779780781782783784785786787788789790791792793794795796797798799800801802803804805806807808809810811812813814815816817818819820821822823824825826827828829830831832833834835836837838839840841842843844845846847848849850851852853854855856857858859860861862863864865866867868869870871872873874875876877878879880881882883884885886887888889890891892893894895896897898899900901902903904905906907908909910911912913914915916917918919920921922923924925926927928929930931932933934935936937938939940941942943944945946947948949950951952953954955956957958959960961962963964965966967968969970971972973974975976977978979980981982983984985986987988989990991992993994995996997998hello hi
Segmentation fault: 11

No no, declare ch as char[]:
char ch[MAXLENGTH];
While possible, it's definitely possible to store strings in an int array,
you shouldn't do that at all.
I also would write your get_input like this:
int get_input(char *ch, size_t lim)
{
if(!fgets(ch, lim, stdin))
return 0;
// removing possible \n
ch[strcspn(ch, "\n")] = 0;
return 1;
}
The logic behind the algorithm seems to be OK, however your while and for
conditions are a little bit strange and it caused problems when stepping through
the debugger.
while(ch[arrayindex] != EOF && arrayindex < lim-1)
Don't check for EOF, you shouldn't write an EOF in
a string, because EOF is an signed int and doesn't fit in a char. If you
read a line with fgets, there is never going to be a EOF in the string. Also
because you did while((i = getchar()) != EOF && z < lim-1 && i != '\n') in
the read function, you are not going to have an EOF in the string. You should
check for '\0' which is the only correct way to terminate a string.
The correct condition would be:
while(ch[arrayindex] != '\0' && arrayindex < lim-1)
If you are checking for the bounds, then it would be better to have that first
and then check for the end of string.
while(arrayindex < lim-1 && ch[arrayindex])
Here I omitted the != '\0' because '\0' == 0.
After the loop you should do
ch_copy[copy_counter] = '\0';
Use copy_counter, not arrayindex, because arrayindex is the index for the
original, where multiple blanks are stored. copy_counter is the index for the
copy.
But if prior of the while loop you did:
memset(ch_copy, 0, lim);
then the whole buffer would be initalized with 0 and you won't need to worry
about the 0 terminating because the copy will never be larger than the original.
Lastly, the condition in the for loop should be corrected with the same logic
as for the while loop. Here you don't need to check for the boundaries,
because you know that the copy is never be larger than the original:
for(arrayindex = 0; ch_copy[arrayindex]; arrayindex++){
ch[arrayindex] = ch_copy[arrayindex];
}
ch[arrayindex] = 0;
Or you could just use strcpy:
strcpy(ch, ch_copy);
So the function should look like this:
void replace_blanks(char ch[], int lim)
{
char ch_copy[lim];
int i, arrayindex, copy_counter;
memset(ch_copy, 0, lim);
copy_counter = 0;
arrayindex = 0;
i = arrayindex;
while(arrayindex < lim -1 && ch[arrayindex]){
if(ch[arrayindex] != ' '){
ch_copy[copy_counter] = ch[arrayindex];
i = arrayindex;
arrayindex++;
copy_counter++;
}
else if(ch[arrayindex] == ' ' && ch[i] != ' '){
ch_copy[copy_counter] = ch[arrayindex];
i = arrayindex;
arrayindex++;
copy_counter++;
} else {
i = arrayindex;
arrayindex++;
}
}
strcpy(ch, ch_copy);
}

Related

Write a program to break long input lines into two or more shorter lines of length at most n

I am currently learning C and working on a problem that breaks input lines into lengths of n. Below is my current code where n is set to 30. When it reaches the n-th index it replaces that index with ' ' and then line breaks, but it will only do it for the first n characters and I'm unsure what isn't getting rest in order to it to continue making a new line at the nth index.
int getline2(void);
int c, len, cut, counter;
char line[MAXLINE];
main() {
while ((len = getline2()) > 0) {
if (len > BREAK) {
c = 0;
counter = 0;
while (c < len) {
if (line[c] == ' ') {
counter = c;
}
if (counter == BREAK) {
line[counter] = '\n';
counter = 0;
}
counter++;
c++;
}
}
printf("%s", line);
}
return 0;
}
int getline2(void) {
int c, i;
extern char line[];
for (i = 0; i < MAXLINE - 1 && (c = getchar()) != EOF && c != '\n'; ++i)
line[i] = c; //i gets incremented at the end of the loop
if (c == '\n') {
line[i] = c;
++i;
}
line[i] = '\0';
return i;
}
Your code is a little too complicated:
you do not need to store the bytes read from the file into an array, just output them one at a time, keeping track of the line length
when the line would become too long, output a newline and reset the count before you output the byte.
also not that none of these global variables deserves to be global.
and the prototype for main should be either int main(), int main(void) or int main(int argc, char *argv[]) or equivalent. main()` is an obsolete syntax that should be avoided.
Here is a modified version:
#include <stdio.h>
#define BREAK 30
int main() {
int c;
int len = 0;
while ((c = getchar()) != EOF) {
if (c == '\n') {
putchar(c);
len = 0;
} else {
if (len >= BREAK) {
putchar('\n');
len = 0;
}
putchar(c);
len++;
}
}
return 0;
}

A nearly lookalike strindex implementation of K&R found substring when there was no substring

I was trying to implement the K&R strindex program. User will be asked to enter a line, if the line contains the string "boi" in it, program will confirm that the line contained the pattern. The problem is, program confirms some other string/strings.
If i enter "şgb" it will confirm that it contains the string "boi". So far, it only happens with "şgb".
https://onlinegdb.com/SyeeO0mzH
#include <stdio.h>
#define MAXLINE_LENGTH 100
char pattern[] = "boi";
int get_line(char line[], int maxlength);
int str_index(char str[], char substr[]);
int main() {
char line[MAXLINE_LENGTH];
while(get_line(line, MAXLINE_LENGTH) > 0) {
if(str_index(line, pattern) >= 0) {
printf("%s", line);
printf("Pattern found above line\n");
}
}
return 0;
}
int get_line(char line[], int maxlength){
int index = 0, character;
while(--maxlength > 0 && (character = getchar()) != EOF && character != '\n') {
line[index++] = character;
}
if(character == '\n') {
line[index++] = character;
}
line[index] = '\0';
return index;
}
int str_index(char str[], char substr[]) {
int i, j, k;
for(i = 0; str[i] != '\0'; i++) {
for(j = i, k = 0; substr[k] != '\0' && str[j] == substr[k]; j++, k++) ;
if(k > 0) {
return i;
}
}
return -1;
}
boi
boi
Pattern found above line
fbajdobadşgbadf
fbajdobadşgbadf
Pattern found above line
şgb
şgb
Pattern found above line
In str_index, if any character in str is the first character in substr, then, when i is such that str[i] is that character, substr[j] == substr[k] will be true in the first iteration of for(j = i, k = 0;…, and k will be incremented. When that loop ends, k > 0 is true, and return i; will be executed.
You need to modify the code so that it returns i only if all the characters in substr have been matched.

Replacing three 'a' in with a single '*' in a string

So my program should get input from an user and store it in an array. After that if the input string includes three 'a's in a row it should be replaced with a single '*'. However I can't seem to get it right. It only replaces the first a with a *. I tried to replace the following 2 a with a blank but the output looks funny.
For this exercise I have to use putchar() and getchar().
Thank you in advance.
#include <stdio.h>
char c;
char buffer[256];
int counter= 0;
int i;
int main()
{
while ((c = getchar()) != '\n') {
buffer[counter] =c;
counter++;
if (counter >255) {
break;
}
}
for(i=0; i<256; i++) {
if(buffer[i]== 'a'&&buffer[i+1]=='a'&&buffer[i+2]=='a')
{
buffer[i]= '*';
buffer[i+1]=' ';
buffer[i+2]=' ';
}
putchar(buffer[i]);
}
putchar('\n');
return 0;
}
So my program should get input from an user and store it in an array.
After that if the input string includes three 'a's in a row it should
be replaced with a single '*'. However I can't seem to get it right.
You almost got it! Just move index by 2 to and continue.
#include <stdio.h>
char c;
char buffer[256];
int counter= 0;
int i;
int main(void)
{
while ((c = getchar()) != '\n') {
buffer[counter] =c;
counter++;
if (counter >= 255) {
break;
}
}
buffer[counter] ='\0';
for(i=0; i<256; i++) {
if(buffer[i]== 'a'&&buffer[i+1]=='a'&&buffer[i+2]=='a')
{
buffer[i]= '*';
putchar(buffer[i]);
i = i + 2;
continue;
}
putchar(buffer[i]);
}
putchar('\n');
return 0;
}
Test:
123aaa456aaa78
123*456*78
In string you must assign a end of character at the end and that is call null character \0 or just a numeric 0. Correct your code like below:-
while ((c = getchar()) != '\n') {
buffer[counter] =c;
counter++;
if (counter >=255) {
break;
}
}
buffer[counter] ='\0';// or buffer[counter] =0;
To avoid side effect in a string array always set all its value with 0 first:-
char buffer[256];
memset(buffer, 0, sizeof(buffer));
If you want to change the number of characters, you will need to create a different buffer to copy the output to.
If you really just want to output to the console, you could just write every character until you hit your matching string.
#include <stdio.h>
char c;
char buffer[256];
char output[256];
int counter= 0;
int i, j;
int main()
{
while ((c = getchar()) != '\n') {
buffer[counter] = c;
counter++;
if (counter >255) {
break;
}
}
buffer[counter] = 0;
for(i=0, j=0; i<256; i++, j++) {
if(buffer[i] == 'a' && buffer[i+1] == 'a'&& buffer[i+2] == 'a')
{
output[j]= '*';
i += 2;
}
else
output[j] = buffer[i];
putchar(output[j]);
}
putchar('\n');
return 0;
}
There are multiple problems in your code:
there is no reason to make all these variables global. Declare them locally in the body of the main function.
use int for the type of c as the return value of getchar() does not fit in a char.
you do not check for EOF.
your test for buffer overflow is off by one.
you do not null terminate the string in buffer. You probably make buffer global so it is initialized to all bits 0, but a better solution is to set the null terminator explicitly after the reading loop.
to replace a sequence of 3 characters with a single one, you need to copy the rest of the string.
You can use a simple method referred as the 2 finger approach: you use 2 different index variables into the same array, one for reading, one for writing.
Here is how it works:
#include <stdio.h>
int main() {
char buffer[256];
int c;
size_t i, j, counter;
for (counter = 0; counter < sizeof(buffer) - 1; counter++) {
if ((c = getchar()) == EOF || c == '\n')
break;
buffer[counter] = c;
}
buffer[counter] = '\0';
for (i = j = 0; i < counter; i++, j++) {
if (buffer[i] == 'a' && buffer[i + 1] == 'a' && buffer[i + 2] == 'a') {
buffer[j] = '*';
i += 2;
} else {
buffer[j] = buffer[i];
}
}
buffer[j] = '\0'; /* set the null terminator, the string may be shorter */
printf("modified string: %s\n", buffer);
return 0;
}

Program wont exit with EOF and wont print if last character is ' [space]'

I am new to C so please forgive my misunderstandings. I am trying to write a simple program that takes a users character input, mutates it, and prints it out in "piglatin"... where the first letter of a word is moved to the end of the word and then an "ay" is appended to the end of the word. Example-> the word "like" becomes ... "ikelay". Here is my program...
//pig latin
#include <stdio.h>
#define MAX 1000
void pigify(char chars[], int cnt);
void sortWords(char stream[], int total);
void clearWord(char word[], int j);
int main(){
int c, i;
char allChars[MAX];
i = 0;
while((c = getchar()) != EOF){
allChars[i] = c;
++i;
}
allChars[i] = '\0';
sortWords(allChars, i);
return 0;
}
/////////////////
/////////////////
void sortWords(char stream[], int total){
int i, j, start, end, m;
char words[total];
clearWord(words, total);
i = j = end = m = 0;
while(stream[i] != '\0'){
if(stream[i] != '\n' && stream[i] != '\t' && stream[i] != ' '){
++i;
++j;
} else if (j > 2){
end = i;
for(start = i-j; start <= end; ++start){
words[m] = stream[start];
++m;
}
pigify(words, m);
clearWord(words, m);
j = m = 0;
}
}
}
/////////////////
/////////////////
void clearWord(char word[], int i){
int j;
for (j = 0; j <= i; ++j){
word[j] = '\0';
}
}
/////////////////
/////////////////
void pigify(char alls[], int cnt){
int j;
char pchars[cnt+3];
j = 0;
while(alls[j] != '\0'){
pchars[j] = alls[j];
++j;
}
if(alls[0] != 'a' && alls[0] != 'e' && alls[0] != 'i' && alls[0] != 'o' && alls[0] != 'u'){
pchars[cnt] = alls[0];
pchars[cnt+1] = 'a';
pchars[cnt+2] = 'y';
pchars[cnt+3] = '\0';
pchars[0] = ' ';
}
printf("\npost pigification --> %s\n", pchars);
}
I have been on it for a long time and I can't find where i've made a mistake. I do not care so much about the program, I don't need to convert input to "piglatin" but I would really love to know what I have done wrong!!! Help, advice, and/or pointers would be awesome! thank you
Writing outside array bounds. Use <
char words[total];
clearWord(words, total);
void clearWord(char word[], int i){
int j;
// for (j = 0; j <= i; ++j){
for (j = 0; j < i; ++j){
word[j] = '\0';
}
}
May have other problems too
Replace this line:
while((c = getchar()) != EOF){
allChars[i] = c;
++i;
}
With this:
while ((allChars[i] = getchar()) != '\n')
i++;
Otherwise, every time you press enter, the loop starts over. Maybe someone else can explain that, but the above code will let your code do what you want it to.
In the future, a function such as fgets() may be more suitable for your needs, as you don't have to worry about checking for EOF and such - you just have to strip the newline at the end in that case.
With help form #chux and after using some more print statements to find out what is going on, I realized that in the function sortWords the variable i was not being incremented for the case in which a space '' '' character or a new line or tab character ''\n'' and ''\t'' was reached. After changing the function to this ...
void sortWords(char stream[], int total){
int i, j, start, end, m;
char words[total];
clearWord(words, total);
i = j = end = m = 0;
while(stream[i] != '\0'){
if(stream[i] != '\n' && stream[i] != '\t' && stream[i] != ' '){
++i;
++j;
} else if (j > 2){
end = i;
for(start = i-j; start <= end; ++start){
words[m] = stream[start];
++m;
}
pigify(words, m);
clearWord(words, m);
j = m = 0;
++i;
}
}
}
The program works at least somewhat more as expected. The bugs i set out to solve with this question are fixed at least. Still not perfect but i think this was a poorly asked question on my part and should be ended

How to fix segmentation fault: 11 compiler error

I have been learning from the C Programming Language book (K&R) and was writing one of the exercises that removes trailing blanks from an input. I understand that a segmentation fault is at some level a problem having to do with accessing memory that is not accessible, but I have read through this code several times and can't find the error. I would like it very much if someone could help find this error and tell me how to discover errors like this in the future.
#include <stdio.h>
#define MAXLINE 1000
#define CHAR 0 /*character definition*/
#define TRAIL 1 /*determines whether program is in a trailing blank*/
int getinput(char input[], int max);
int trailrem(char input[], char copyto[]);
int len;
int main() {
char line[MAXLINE]; /*current line*/
char newline[MAXLINE];
int i, c, newreturn; /*integer counter, character holder, current line length, and trailrem return value*/
int len;
while((len = getinput(line, MAXLINE)) > 0) {
newreturn = trailrem(line, newline);
for(i = 0; i <= newreturn; ++i)
printf("\n%c\n", newline[i]);
}
}
int getinput(char input[],int max) {
int i, c, line;
for(i = 0; (c = getchar()) != EOF && c != '\n' && c < (max-1); ++i)
input[i] = c;
if(c == '\n') {
input[i] = c;
++i;
}
input[i] = '\0';
return i;
}
int trailrem(char input[], char copy[]) {
int i, j, minusin, state, r;
for(i = len; input[i] != EOF && i >= 0; --i) {
if(input[i] =='\n')
state = TRAIL;
else if((input[i] == ' ' && state == TRAIL) ||( input[i] == '\t' && state == TRAIL))
++minusin;
else if(state == TRAIL && (input[i] != ' ' || input[i] != '\t'))
state = CHAR;
for(j = (r = len-minusin); state == CHAR; --j){
copy[j-2] = input[i];
}
}
copy[r] = '\0';
copy[r-1] = '\n';
return r;
}
So many problems in your code. But the main problem is, you have a global len
int len;
And a local len in the main function.
You are initializing len in main function like this:
while((len = getinput(line, MAXLINE)) > 0)
So the local len is updated. But the global len is still 0.
You are expecting that, you will get the updated value of len in trailrem method but you don't. In trailrem() you will get len equal to 0!
for(i = len; input[i] != EOF && i >= 0; --i)
So i is 0 too. And hence, copy[r-1] = '\n'; will crash, because r-1 can be negative.
Other problems: (BLUEPIXY and WhozCraig mentioned in the comment).
for(i = 0; (c = getchar()) != EOF && c != '\n' && c < (max-1); ++i)
here, c < (max-1) should be i < (max-1).
++minusin; in trailrem function where minusin is uninitialized.

Resources