I was trying to solve a problem in toph.co platform. I have made a code. It is not working as it should be. Giving me the correct output in some cases. But when I am trying a case with 'o' it is entering in a loop. And maybe the problem is there. But I am unable to find that out.
Problem link: https://toph.co/p/better-passwords
Please help me to solve the problem in my code. I am using c programming language. As I am new in programming, I am not getting the point that is wrong.
I have tried it in many ways. Modifying the code again and again. Now I am becoming mad.
#include <stdio.h>
#include<string.h>
int main()
{
char s[40], i, j;
int len;
gets(s);
len= strlen(s);
for(i=0; i<=len; i++)
{
if(s[i] == 's')
{
s[i]= '$';
}
else if(s[i] == 'i')
{
s[i]= '!';
}
else if(s[i] == 'o')
{
s[i]= '(';
for(j=len; j>i; j--)
{
s[j]=s[j-1];
len= strlen(s);
}
s[i+1]=')';
}
else
{
continue;
}
len= strlen(s);
}
if (s[0]>='a' && s[0]<='z')
{
s[0]= s[0]- 32;
}
int new_len=strlen(s);
s[new_len]='.';
puts(s);
return 0;
}
I expect the output Un$()ph!$t!cated. , but it is showing Un$()ph!$t!cated.....'Many unwanted charecter'.....
Your string null byte is missing after manipulations, easiest way to avoid such problems - is to initialize whole character array into zero bytes:
char s[40] = {0}, // was char s[40], uninitialized !
Also do you notice a compile message "warning: the `gets' function is dangerous and should not be used" ?
gets() is dangerous, because it is not protected from buffer overflow - try to run your program with very long string exceeding your buffer s capacity and you will get a crash :
* stack smashing detected *: terminated Aborted (core dumped)
Use fgets() instead of gets(), like so :
fgets(s, 39, stdin);
if (s[strlen(s)-1] == '\n') s[strlen(s)-1] = '\0'; // deleting newline character
Notice, that we read here BUFFER_SIZE - 1 characters here, i.e.- by 1 char less, than your buffer is able to hold (40), because if we enter long string which is of full buffer size,- then your code extending string will smash stack once again. You need to be serious about buffer overflows.
As most commentators wrote: you don't put the end-of-string character '\0' behind the extended string. Strings in C are marked by this extra character at the end. It is needed to find the end of a string.
Example: A string "abc" is actually a sequence of 4 characters, 'a', 'b', 'c', and '\0'. Its length is 3, and its s[3] contains '\0'.
Your loop:
for(j=len; j>i; j--)
{
s[j]=s[j-1];
len= strlen(s);
}
In the first turn of the loop the character at s[len] is replaced by the character at s[len-1]. This overwrites the original '\0' with the last (visible) character of your string.
If you change the loop into:
for (j = len; j > i; j--)
{
s[j + 1] = s[j];
}
the '\0' will be copied in the first run.
Note 1: Move the assignment to len behind the loop.
Note 2: Make sure that your variable s is big enough for all inputs.
Note 3: See the whitespace I use? Adopt a good code style and stick to it.
There are a couple of places in your code where you are overwriting the "\0".
These are:
s[j]=s[j-1];
And
s[new_len]='.';
So the rectified code would be....
int main()
{
char s[40], i, j;
int len;
gets(s);
len= strlen(s);
for(i=0; i<=len; i++)
{
if(s[i] == 's')
{
s[i]= '$';
}
else if(s[i] == 'i')
{
s[i]= '!';
}
else if(s[i] == 'o')
{
s[i]= '(';
for(j=len+1; j>i; j--) //j needs to be one more than the length
{
s[j]=s[j-1];
len= strlen(s);
}
s[i+1]=')';
}
else
{
continue;
}
len= strlen(s);
}
if (s[0]>='a' && s[0]<='z')
{
s[0]= s[0]- 32;
}
int new_len=strlen(s);
s[new_len]='.';//add a '.'
s[new_len+1] = '\0'; //add the terminating character
puts(s);
return 0;
}
Related
I'm writing a function that replaces blank spaces into '-' (<- this character).
I ultimately want to return how many changes I made.
#include <stdio.h>
int replace(char c[])
{
int i, cnt;
cnt = 0;
for (i = 0; c[i] != EOF; i++)
if (c[i]==' ' || c[i] == '\t' || c[i] == '\n')
{
c[i] = '-';
++cnt;
}
return cnt;
}
main()
{
char cat[] = "The cat sat";
int n = replace(cat);
printf("%d\n", n);
}
The problem is, it correctly changes the string into "The-cat-sat" but for n, it returns the value 3, when it's supposed to return 2.
What have I done wrong?
#4386427 suggested this should be another answer. #wildplasser already provided the solution, this answer explains EOF and '\0'.
You would use EOF only when reading from a file (EOF -> End Of File). See this discussion. EOF is used to denote the end of file, and its value is system dependent. In fact, EOF is rather a condition than a value. You can find great explainations in this thread. When working with char array or a char pointer, it will always be terminated by a '\0' character, and there is always exactly one of those, thus, you would use it to break out of the loop when iterating through an array/pointer. This is a sure way to ensure that you don't access memory that is not allocated.
#include <stdio.h>
int repl(int c);
int main(void){
int c, nc;
nc =0;
while ((c=getchar())!=EOF)
nc = replc(c);
printf("replaced: %d times\n", nc);
return 0;
}
int replc(int c){
int nc = 0;
for(; (c = getchar())!=EOF; ++c)
if (c == ' '){
putchar('-');
++nc;
} else putchar(c);
return nc;
}
A string ends with a 0 (zero) value, not an EOF (so: the program in the question will scan the string beyond the terminal\0 until it happens to find a -1 somewhere beyond; but you are already in UB land, here)
[sylistic] the function argument could be a character pointer (an array argument cannot exist in C)
[stylistic] a pointer version wont need the 'i' variable.
[stylistic] The count can never be negative: intuitively an unsigned counter is preferred. (it could even be a size_t, just like the other string functions)
[stylistic] a switch(){} can avoid the (IMO) ugly || list, it is also easier to add cases.
unsigned replace(char *cp){
unsigned cnt;
for(cnt = 0; *cp ; cp++) {
switch (*cp){
case ' ' : case '\t': case '\n':
*cp = '-';
cnt++;
default:
break;
}
}
return cnt;
}
EOF used in the for loop end condition is the problem as you are not using is to check end of file/stream.
for (i = 0; c[i] != EOF; i++)
EOF itself is not a character, but a signal that there are no more characters available in the stream.
If you are trying to check end of line please use
for (i = 0; c[i] != "\0"; i++)
So I'm working through the K&R C book and there was a bug in my code that I simply cannot figure out.
The program is supposed to remove all the comments from a C program. Obviously I'm just using stdin
#include <stdio.h>
int getaline (char s[], int lim);
#define MAXLINE 1000 //maximum number of characters to put into string[]
#define OUTOFCOMMENT 0
#define INASINGLECOMMENT 1
#define INMULTICOMMENT 2
int main(void)
{
int i;
int isInComment;
char string[MAXLINE];
getaline(string, MAXLINE);
for (i = 0; string[i] != EOF; ++i) {
//finds whether loop is in a comment or not
if (string[i] == '/') {
if (string[i+1] == '/')
isInComment = INASINGLECOMMENT;
if (string[i+1] == '*')
isInComment = INMULTICOMMENT;
}
//fixes the problem of print messing up after the comment
if (isInComment == INASINGLECOMMENT && string[i] == '\0')
printf("\n");
//if the line is done, restates all the variables
if (string[i] == '\0') {
getaline(string, MAXLINE);
i = 0;
if (isInComment != INMULTICOMMENT)
isInComment = OUTOFCOMMENT;
}
//prints current character in loop
if(isInComment == OUTOFCOMMENT && string[i] != EOF)
printf("%c", string[i]);
//checks to see of multiline comment is over
if(string[i] == '*' && string[i+1] == '/' ) {
++i;
isInComment = OUTOFCOMMENT;
}
}
return 0;
}
So this works great except for one problem. Whenever a line starts with a comment, it prints that comment.
So for instance, if I had a line that was simply
//this is a comment
without anything before the comment begins, it will print that comment even though it's not supposed to.
I thought I was making good progress, but this bug has really been holding me up. I hope this isn't some super easy thing I've missed.
EDIT: Forget the getaline function
//puts line into s[], returns length of that line
int getaline(char s[], int lim)
{
int c, i;
for (i = 0; i < lim-1 && (c = getchar()) != '\n'; ++i)
s[i] = c;
if (c == '\n') {
s[i] = c;
++i;
}
s[i] = '\0';
return i;
}
There are many problems in your code:
isInComment is not initialized in function main.
as pointed by others, string[i] != EOF is wrong. You need to test for end of file more precisely, especially for files that do not end with a linefeed. This test only works if char type is signed and EOF is a valid signed char value. It will nonetheless mistakenly stop on a stray \377 character, which is legal in a string or in a comment.
When you detect the end of line, you read another line and reset i to 0, but i will be incremented by the for loop before you test again for single line comment... hence the bug!
You do not handle special cases such as /* // */ or // /*
You do not handle strings. This is not a comment: "/*", nor this: '//'
You do not handle \ at end of line (escaped linefeed). This can be used to extend single line comments, strings, etc. There are more subtle cases related to \ handling and if you really want completeness, you should handle trigraphs too.
Your implementation has a limit for line size, this is not needed.
The problem you are assigned is a bit tricky. Instead of reading and parsing lines, read one character at a time and implement a state machine to parse escaped linefeeds, strings, and both comment styles. The code is not too difficult if you do it right with this method.
if (string[i] == '\0') {
getaline(string, MAXLINE);
i = 0;
if (isInComment != INMULTICOMMENT)
isInComment = OUTOFCOMMENT;
}
When you start a new line, you initialize i to 0. But then in the next iteration:
for (i = 0; string[i] != EOF; ++i)
i will be incremented, so you'll begin the new line with index 1. Therefore there is a bug when the line begins with //.
You can see that it solves the problem if you write instead:
if (string[i] == '\0') {
getaline(string, MAXLINE);
i = 0;
if (isInComment != INMULTICOMMENT)
isInComment = OUTOFCOMMENT;
}
though it's usually considered as bad style to modify for loop indices inside the loop. You may redesign your implementation in a more readable way.
I'm trying to get selected characters from one string into another. Everything looks okay, except the program keeps adding additional characters to the output. And it seems that it tends to add different number of these "unecessary" characters. Where might the problem be?
int main(void) {
int i,j=0;
char string[256];
char second_arr[256];
scanf("%255s", string);
for(i=0;i<256;i++){
if(string[i]=='('||string[i]=='['||string[i]=='{'){
second_arr[j]=string[i];
j++;
}
}
printf("%s", second_arr);
}
Say,
input: (hello)(}[} --->
Output:(([[H
Problem 1: You're not testing scanf for failure. It can return EOF, or zero to indicate the input didn't match your format string.
Problem 2: You're copying all 256 chars even if the user entered fewer, which means you're copying junk.
Problem 3: You're not adding a null terminator to second_arr.
Just do this:
if (scanf("%255s", string) != 1)
{
printf("scanf failed\n");
return 1;
}
for (i = 0; i < 256 && string[i]; i++) {
if(string[i]=='('||string[i]=='['||string[i]=='{'){
second_arr[j]=string[i];
j++;
}
}
second_arr[j] = '\0';
printf("%s", second_arr);
return 0;
Try this:
for (i=0; string[i]!=0; i++) // iterate the input string until the null-character
{
if (string[i] == '(' || string[i] == '[' || string[i] == '{')
second_arr[j++] = string[i];
}
second_arr[j] = 0; // set a null-character at the end of the output string
There is nothing to terminate the second string. Add
||string[i]=='\0'
to your conditions. Also break out of the loop when you see that null char, but only after you have copied it.
You should add at the end of second string second_arr the char '\n' to indicate its end.
#include <stdio.h>
int main()
#include <stdio.h>
int main()
{
char msg[31] = {'\0'};
char encrypted[31] = {'\0'};
int key;
printf("Please enter a message under 30 characters: ");
fgets(msg, 31, stdin);
printf("Please enter an encryption key: ");
scanf("%d", &key);
int i = 0;
while (msg[i] && ('a' <= msg[i] <= 'z' || 'A' < msg[i] < 'Z'))
{
encrypted[i] = (msg[i] + key);
i++;
}
printf("%s\n", msg);
printf("%d\n", key);
printf("%s\n", encrypted);
}
Okay i've got my code to increment the characters but i don't know how to make it ignore special characters and spaces. Also how do i use % to loop back to 'a' and 'A'?
Thank you.
You just need a simple for loop:
for (int i = 0; i < 31; i++)
{
// operate on msg[i]
}
If you didn't know the length of the string to begin with, you might prefer a while loop that detects the null terminator:
int i = 0;
while (msg[i])
{
// operate on msg[i]
i++;
}
Your fgets and scanf are probably fine, but personally, I would be consistent when reading input, and fgets for it all. Then you can sscanf to get key out later.
scanf and fgets seem fine in this situation the way you've used them.
In C, a string is just an array of characters. So, you access each element using a for loop and array indexing:
for (int i = 0; i < strlen(str); i++) {
char thisChar = str[i];
//Do the processing for each character
}
You can perform arithmetic on thisChar as necessary, but be careful not to exceed 255. You might want to put a check on key to ensure it doesn't get too big.
Getting a string from scanf:
char msg[31];
scanf("%30s", msg);
OR (less efficient, because you have to fill the array with 0s first)
char msg[31] = { 0 };
scanf("%30c", msg);
Iterating a string is as easy a for loop (be sure to use c99 or c11)
int len = strlen(msg);
for(int i = 0; i < len; i++) {
char current = msg[i];
//do something
msg[i] = current;
}
"Encrypting" (i.e. ciphering) a character require a few steps
Determine if we have an uppercase character, lowercase character, or non-alphabetic character
Determine the position in the alphabet, if alphabetic.
Update the position, using the modulus operator (%)
Correct the position, if alphabetic
I could give you the code here, but then you wouldn't learn anything from doing it yourself. Instead, I encourage you to implement the cipher based on the steps I provided above.
Note that you can do things like:
char c = 'C';
char e = 'E' + 2;
char lower_c = 'C' - 'A' + 'a';
I have this program in C I wrote that reads a file line by line (each line has just one word), sorts the alphabets, and then displays the sorted word and the original word in each line.
#include<stdio.h>
int main()
{
char line[128];
int i=0;
int j;
int length;
while(fgets(line,sizeof line,stdin) != NULL)
{
char word[128];
for (i=0; line[i] != '\0'; i++)
{
word[i]=line[i];
}
while (line[i] != '\0')
i++;
length=i;
for (i=length-1; i >=0; i--)
{
for (j=0; j<i; j++)
{
if (line[j] > line[i])
{
char temp;
temp = line[j];
line[j] = line[i];
line[i]=temp;
}
}
}
printf("%s %s",line,word);
}
return 0;
}
I'm compiling and running it using the following bash commands.
gcc -o sign sign.c
./sign < sample_file | sort > output
The original file (sample_file) looks like this:
computer
test
file
stack
overflow
The output file is this:
ackst stack
cemoprtu computer
efil file
efloorvw overflow
er
estt test
ter
ter
I'm having two issues:
The output file has a bunch of newline characters at the beginning (ie. about 5-7 blank lines before the actual text begins)
Why does it print 'ter' twice at the end?
PS - I know these are very elementary questions, but I only just started working with C / bash for a class and I'm not sure where I am going wrong.
Problem 1
After this code, the variable line contains a line of text, including the newline character from the end of the string
while(fgets(line,sizeof line,stdin) != NULL)
{
This is why you are getting the "extra" newlines. The ASCII value for newline is less than the ASCII value for 'A'. That is why the newlines end up at the beginning of each string, once you've sorted the characters. E.g. "computer\n" becomes "\ncemoprtu".
To solve this, you can strip the newlines off the end of your strings, after the for-loop
if(i > 0 && word[i-1] == '\n')
{
word[i-1] = '\0';
line[i-1] = '\0';
--i;
}
...
printf("%s %s\n",line,word); /* notice the addition of the newline at the end */
This happens to solve problem 2, as well, but please read on, to see what was wrong.
Problem 2
After the loop
for (i=0; line[i] != '\0'; i++) { /* */ }
The string word will not be null-terminated (except by blind luck, since it is ready random uninitialized memory). This is why you get the "ter", because that is part of the data you left behind when you copied the word "computer" to word.
Problem 3
After the loop
for (i=0; line[i] != '\0'; i++) { /* */ }
The value of line[i] != '\0' will always be false. This means that this code will do nothing
while (line[i] != '\0')
i++;
It might make the problem more obvious if I replace the for-loop and the while-loop with basically identical code, using goto:
i=0;
begin_for_loop:
if(line[i] != '\0')
{
{
word[i]=line[i];
}
i++;
goto begin_for_loop;
}
begin_while_loop:
if(line[i] != '\0')
{
i++;
goto begin_while_loop;
}
(btw, most professional programmers will do anything from laugh to yell at you if you mention using goto :) I only am using it here to illustrate the point)
A tip I find handy is to draw out my arrays, variables etc on a piece of paper, then trace through each line of my code (again, on paper) to debug how it works.