Weird shapes as output( Strings)- C language - string

So i have a problem. I have to separate the first name, last name and hostname of email.
For example:
zephyr.extreme#gmail.com>> Input
Output=
First name= Zephyr
Last name= extreme
Host Name= gmail.com
I am not getting the desired result. I am getting some weird shapes as output.
Code:
#include <stdio.h>
int main()
{
char email[40], first[20],last[20],host[30];
printf("Enter the email= ");
gets(email);
int i;
while(email[i]!='\0')
{
while(email[i]!='.')
{
first[i]=email[i];
i++;
}
while(email[i]!='#')
{
last[i]=email[i];
i++;
}
while(email[i]!='\0')
{
host[i]=email[i];
i++;
}
}
puts(first);
puts(last);
puts(host);
}

Assuming the format will always be first.last#host..., use this code:
#include <stdio.h>
#include <string.h>
int main()
{
char email[40], first[20],last[20],host[30],name[40];
int firstDot,atSymbol;
int i;
int length;
char *token;
printf("Enter the email= ");
gets(email);
length = strlen(email);
for(i=0;i<length;i++){
if(email[i]=='.')
{
firstDot = i;
}
else if(email[i]=='#')
{
atSymbol = i;
}
}
strncpy(name,email,atSymbol);
name[atSymbol]= '\0';
token = strtok(name, ".");
/* walk through other tokens */
while( token != NULL )
{
printf( "%s\n", token );
token = strtok(NULL, ".");
}
strncpy(host,email+atSymbol,length-atSymbol);
host[length-atSymbol] = '\0';
puts(host);
}

So i updated the code, now the only problem is the last output.
After host name= gmail.com prints, but then some extra shapes are also printing. These are smile face and some weird symbols.
Code:
#include <stdio.h>
int main()
{
char email[40], first[20],last[20],host[30];
printf("Enter the email= ");
gets(email);
int i=0,j;
while(email[i]!='.')
{
first[i]=email[i];
i++;
}
i=0;
while(email[i]!='#')
{
last[i]=email[i];
i++;
}
j=i;
i=0;
while(email[j]!='\0')
{
host[i]=email[j];
j++;
i++;
}
printf("First Name= ");
puts(first);
printf("Last name= ");
puts(last);
printf("Host name= ");
puts(host);
}

C strings (char pointers) should be null-terminated. This means your string needs a '\0' character at its end so that string manipulation functions such as puts or strlen know where they end, in constrast to other languages where the string's length is stored together with it. The "weird shapes" you are seeing are just random data stored after the end of the string being interpreted as characters. When you call puts it just keeps outputting bytes-as-characters until it randomly finds a byte with value '\0'
You can solve this by adding a '\0' character to the end of the string after each of the blocks where you write a string.
while(email[i]!='.')
{
first[i]=email[i];
i++;
}
email[i] = '\0'; //same thing as email[i] = 0; but using a char makes what
//you're doing clearer

Related

cs50 caeser, I don't understand check50 fail

Below is my code and it is working for 10/11 checks, but shows the error message for this one:
:( encrypts "world, say hello!" as "iadxp, emk tqxxa!" using 12 as key
Cause
expected "ciphertext: ia...", not "ciphertext: ia..."
Log
running ./caesar 12...
sending input world, say hello!...
checking for output "ciphertext: iadxp, emk tqxxa!\n"...
Expected Output:
ciphertext: iadxp, emk tqxxa!
Actual Output:
ciphertext: iadxp, emk tqxxa!
I have no idea why as they look identical to me, what obvious error am I missing here??
#include <ctype.h>
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <math.h>
#include <stdlib.h>
int main(int key, string word[])
{
//Ensure only a key of 2 is accepted
if (key != 2)
{
printf("Usage: ./caesar key\n");
return 1;
}
//Ensure the second input has has no letters.
for (int i = 0, n = strlen(word[1]); i < n;)
if (isalpha(word[1][i]))
{
printf("Usage: ./caesar key\n");
return 1;
}
//Ensure each character of the input is a digit
else if (isdigit(word[1][i]))
{
i++;
}
else
{
printf("Usage: ./caesar key\n");
return 1;
}
string text = get_string("Plain text: ");
{
printf("ciphertext: ");
}
{
//check each character is an alphabetical one
for (int b = 0, n = strlen(text); b < n; b++;)
{
int k = 0;
int cipher = 0;
if(!isalpha(text[b]))
{
printf("%c", text[b]);
}
else if (isalpha(text[b]))
{
//Calculate the cipher code for a lower-case letter
if (islower(text [b]))
{
int t = text [b] - 97;
k = (t + atoi(word[1])) % (26);
cipher = k + 97;
//Calculate the cipher code for an upper-case letter
}
else if (isupper(text[b]))
{
int t = text [b] - 65;
k = (t + atoi(word[1])) % (26);
cipher = k + 65;
}
}
//print cipher text.
{
printf("%c", cipher);
}
}
printf("\n");
}
}
First, to see what check50 sees, try this on the failing input.
./caeser 12 | cat -v
cat -v displays unprintable characters. The unprintable characters are coming from here printf("%c", cipher);. That line executes whether the input (text[b]) is alpha or not. That line needs to move inside the else if (isalpha(text[b])) block.

cs50 vigenere - loops incorrectly

Apologies if the answer to this is incredibly simple. I just can't work it out.
I've been working on the CS50 Vigenere problem and I think I'm almost there. However the program loops in a way that I don't expect and I'm not sure why. Once it has printed the first ciphered character of the plaintext, it loops back to move to the next character in the key but misses out the part where it needs to move to the next character of the plain text. At least I think that is what is happening.
Here is my code. Any help would be greatly appreciated.
#include <cs50.h>
#include <ctype.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main(int argc, string argv [])
{
int a;
int ciphertext;
int k;
string plain;
int cipher;
// check user has input a valid number of arguments
if (argc < 2 || argc > 2)
{
printf("please input a valid number of arguments\n");
return 1;
}
// check user has input a valid key and prompt for plaintext
char * key = argv [1];
for (a = 0; a < strlen(key); a++)
if (!isalpha(key[a]))
{
printf("Please input a valid key. Key must be alphabetical");
return 1;
}
{
if (a == strlen(key))
{
plain = get_string("Plaintext: ");
}
{
printf("ciphertext: ");
}
}
//read plaintext and keep track
{
for (int i = 0, n = strlen(plain); i < n; i++)
{
//read key and keep track
if (isalpha(plain[i]))
{
for (int j = 0, p = strlen(key); j < p; j++)
//convert key to numerical
{
if (isupper(key[j]) > 'A')
{
k = (key[j] - 65);
//calculate ciphertext and print (upper case)
{
printf("%c", (plain[i] + (k % p) %26) +65);
}
}
else if (islower(key[j]) > 'a')
{
k = (key[j] - 97);
{
printf("%c", (plain[i] + (k % p) %26) +97);
}
}
else printf("%c", plain[i]);
}
}
}
{
printf("\n");
}
}
}

Append char to string - the NXC language

I want to write myself a function similar to PHP's str_repeat. I want this function to add specified amount of characters at the end of string.
This is a code that does not work (string argument 2 expected!)
void chrrepeat(const char &ch, string &target, const int &count) {
for(int i=0; i<count; i++)
strcat(target, ch);
}
I don't exactly know what language is that (C++?), but you seem to be passing a char to strcat() instead of a null-terminated string. It's a subtle difference, but strcat will happily access further invalid memory positions until a null byte is found.
Instead of using strcat, which is inefficient because it must always search up to the end of the string, you can make a custom function just for this.
Here's my implementation in C:
void chrrepeat(const char ch, char *target, int repeat) {
if (repeat == 0) {
*target = '\0';
return;
}
for (; *target; target++);
while (repeat--)
*target++ = ch;
*target = '\0';
}
I made it return an empty string for the case that repeat == 0 because that's how it works in PHP, according to the online manual.
This code assumes that the target string holds enough space for the repetition to take place. The function's signature should be pretty self explanatory, but here's some sample code that uses it:
int main(void) {
char test[32] = "Hello, world";
chrrepeat('!', test, 7);
printf("%s\n", test);
return 0;
}
This prints:
Hello, world!!!!!!!
Convert char to string.
void chrrepeat(char ch, string &target, const int count) {
string help = "x"; // x will be replaced
help[0] = ch;
for(int i=0; i<count; i++)
strcat(target, help);
}

encode text in C

my program reads several string from standard input. I want to encode it like this: where is A print 00,where is B print 01. This is my code. I don't know where I'm wrong. Thank you!
#include<stdio.h>
#include<conio.h>
#include<string.h>
int main(void)
{
char text[100];
printf("enter text:");
fgets(text,100,stdin);
int i,j;
unsigned int aux;
char a[100];
char b[100];
for(i=0;i<100;i++)
for(j=0;j<100;j++)
{
if(text[i]=='a'){
aux=aux|0;
aux=aux<<2;
a[j-1]=aux;
a[j]='\0';
}
if(text[i]=='b'){
aux=aux|1;
aux=aux<<2;
b[j-1]=aux;
b[j]='\0';
}
strcat(a,b)
}
printf("%s", a[j]);
getch();
return 0;
}
printf ("%02d\n", toupper(text[i]) - 'A');
or
for (i = 0; i < strlen (text); i++)
sprintf (&a[i*3], "%02d ", toupper(text[i]) - 'A');
Note that this only works for text only strings

Creating a 2 dimensional character array dynamically in C++

I want to create a 2 dimensional character array dynamically through pointers. Then input 10 strings in it and then take a string target from user and find it in array. if it is present then return its index. I have written code for it but it has errors. Please help me in correcting it. Thanks in advance.
#include<iostream>
#include<string>
using namespace std;
int strsearch(char [][50],char *);
int main()
{
char str[10][50];
char *target=new char [50];
int index;
for(int i=0; i<10; i++)
{
str = new char* [50];
str++;
}
for(int i=0; i<10; i++)
{
cout<<"Enter a sting";
cin>>str[i][50];
str++;
}
cout<<"Enter a string to find:";
cin>>target;
index=strsearch(str,target);
if(index<0)
{
cout<<"String not found";
}
else
{
cout<<"String exist at location "<<index<<endl;
}
return 0;
}
int strsearch(char string[10][50],char *fstr)
{
int slen;
for(int i=0;i<10;i++)
{
slen=strlen(**string);
if (strnicmp(*string[50],fstr,slen)== 0)
{
return i;
}
}
return -1;
}
Simply use:
std::vector<std::string> obj;
It will save you all the head & heart aches and guard you against easy to go wrong manual memory management issues. What you are trying to do is to solve the problem C way. With C++ the correct way to do it is using a vector of strings.
I think this is an error in any case:
for(int i=0;i<10;i++)
{
slen=strlen(**string);
if (strnicmp(*string[50],fstr,slen)== 0)
{
return i;
}
}
Must be something like:
for(int i=0;i<10;i++)
{
slen=strlen(string[i]);
if (strnicmp(string[i],fstr,slen)== 0)
{
return i;
}
}
I have done some correction, i think it can help you but i have not compiled to check for errors.
#include<iostream>
#include<string>
#define DIM_1 10 // Avoid to use "magic numbers" in your code
#define DIM_2 50
using namespace std;
int strsearch(char **string,char *fstr);
int main()
{
char **str = new char*[DIM_1]; //char str[10][50]; dynamically allocated array.
char *target=new char [DIM_2];
int index;
for(int i=0; i<DIM_1; i++)
{
str[i] = new char[DIM_2]; //Do not lost the original pointer
//str++;
}
for(int i=0; i<DIM_1; i++)
{
cout<<"Enter a sting";
cin>>str[i][DIM_2];
//str++; Do not lost the original pointer
}
cout<<"Enter a string to find:";
cin>>target;
index=strsearch(str,target);
if(index<0)
{
cout<<"String not found";
}
else
{
cout<<"String exist at location "<<index<<endl;
}
// Free memory!!
for (int i=0; i<DIM_1;i++) delete[] str[i];
delete[] str;
delete[] target;
return 0;
}
int strsearch(char **string,char *fstr) //its dinamicly allocated array
{
int slen;
int result=-1; //Only one return-> structured programming
for(int i=0;i<DIM_1;i++)
{
slen=strlen(**string);
//strlen and strnicmp is C, not C++, check string class.
if (strnicmp(string[i],fstr,DIM_2)== 0) //Find in the string[i]
{
result= i;
}
}
return result;
}

Resources