I mixed up two programs in the cs50 sandbox in c? - c

I mixed up two programs in the cs50 sandbox, one was to find the the number of characters in an array and other was the print these characters. I know the program is garbage but could anyone explain me what is the compiler doing here?
When I ran this, the output starts printing alphanumeric text and never stops Thanks
#include <cs50.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
string s = get_string("Name: ");
int n = 0;
while (strlen(s) != '\0')
{
n++;
printf("%c", n);
}
}

You have multiple problems with the code you show, here's a couple of them:
strlen(s) will never be zero as you never modify or remove characters from the string, which means you have an infinite loop
n is an integer and not a character so should be printed with the %d format specifier
'\0' is (semantically) a character, representing the string terminator, it's not (semantically) the value 0
To fix the first problem I suspect you want to iterate over every character in the string? Then that could be done with e.g.
for (int i = 0; i < strlen(s); ++i)
{
printf("Current character is '%c'\n", s[i]);
}
But if all you want is to could the number of characters in the string, then that's what strlen is already gives you:
printf("The number of characters in the string is %zu\n", strlen(s));
If you want to count the length of the string without using strlen then you need to modify the loop to loop until you hit the terminator:
for (n = 0; s[n] != '\0'; ++n)
{
// Empty
}
// Here the value of n is the number of characters in the string s
All of this should be easy to figure out by reading any decent beginners book.

while (strlen(s) != '\0') is wrong. '\0' equals 0. There string length is never 0, so the loop keeps going on forever, printing integers interpreted as characters.

You can either use the indexes to go through the string characters by using the variable "n" or you can increment the pointer of the string that you have received from the standard input to go through all of its characters.
#include <cs50.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
string s = get_string("Name: ");
/* First way using n to iterate */
int n = 0;
for (n = 0; n < strlen(s); ++n)
{
printf("%c", s[n]);
}
printf("\n");
/* Second way increment the string pointer*/
while (strlen(s) != '\0')
{
printf("%c", *s); //print the value of s
s++; // go to the next character from s
}
printf("\n");
return 0;
}

Related

Why is this code producing an infinite loop?

#include <Stdio.h>
#include <string.h>
int main(){
char str[51];
int k = 1;
printf("Enter string\n");
scanf("%s", &str);
for(int i = 0; i < strlen(str); i++){
while(str[k] != '\0')){
if(str[i] == str[k]){
printf("%c", str[i]);
k++;
}
}
}
return 0;
}
It is simple C code that checks for duplicate characters in string and prints the characters. I am not understanding why it is producing an infinite loop. The inner while loop should stop when str[k] reaches the null terminator but the program continues infinitely.
Points to know
You don't need to pass the address of the variable str to scanf()
Don't use "%s", use "%<WIDTH>s", to avoid buffer-overflow
Always check whether scanf() conversion was successful or not, by checking its return value
Always use size_t to iterator over any array
i < strlen(str), makes the loop's time complexity O(n3), instead of O(n2), which also isn't very good you should check whether str[i] != 0. But, many modern compilers of C will optimize it by the way.
#include <Stdio.h> it is very wrong, stdio.h != Stdio.h
Call to printf() can be optimized using puts() and putc() without any special formatting, here also modern compiler can optimize it
while(str[k] != '\0')){ has a bracket (')')
Initialize your variable str using {}, this will assign 0 to all the elements of str
Better Implementation
My implementation for this problem is that create a list of character (256 max) with 0 initialized, and then add 1 to ASCII value of the character (from str) in that list. After that print those character whose value was greater than 1.
Time Complexity = O(n), where n is the length of the string
Space Complexity = O(NO_OF_CHARACTERS), where NO_OF_CHARACTERS is 256
Final Code
#include <stdio.h>
#include <stdlib.h>
#include <limits.h>
static void print_dup(const char *str)
{
size_t *count = calloc(1 << CHAR_BIT, sizeof(size_t));
for(size_t i = 0; str[i]; i++)
{
count[(unsigned char)str[i]]++;
}
for (size_t i = 0; i < (1 << CHAR_BIT); i++)
{
if(count[i] > 1)
{
printf("`%c`, count = %zu\n", i, count[i]);
}
}
free(count);
}
int main(void) {
char str[51] = {};
puts("Enter string:");
if (scanf("%50s", str) != 1)
{
perror("bad input");
return EXIT_FAILURE;
}
print_dup(str);
return EXIT_SUCCESS;
}
Read your code in English: You only increment variable k if character at index k is equal to character at index i. For any string that has different first two characters you will encounter infinite loop: char at index i==0 is not equal to char at index k==1, so k is not incremented and while(str[k]!=0) loops forever.

Program to get an indefinite number of strings in C and print them out

As part of an assignment, I am supposed to write a small program that accepts an indefinite number of strings, and then print them out.
This program compiles (with the following warning
desafio1.c:24:16: warning: format not a string literal and no format arguments [-Wform
at-security]
printf(words[i]);
and it prints the following characters on the screen: �����8 ���#Rl�. I guess it did not end the strings I entered by using getchar properly with the null byte, and it prints out garbage. The logic of the program is to initiate a while loop, which runs untill I press the enter key \n, and if there are an space, this is a word that will be store in the array of characters words. Why am I running into problems, if in the else statement once a space is found, I close the word[i] = \0, in that way and store the result in the array words?
#include <stdio.h>
#include <string.h>
int main()
{
char words[100][100];
int i,c;
char word[1000];
while((c = getchar()) != '\n')
{
if (c != ' '){
word[i++] = c;
c = getchar();
}
else{
word[i] = '\0';
words[i] == word;
}
}
int num = sizeof(words) / sizeof(words[0]);
for (i = 0; i < num; i++){
printf(words[i]);
}
return 0;
}
Here are some fixes to your code. As a pointer (as mentioned in other comments), make sure to enable compiler warnings, which will help you find 90% of the issues you had. (gcc -Wall)
#include <stdio.h>
#include <string.h>
int main() {
char words[100][100];
int i = 0;
int j = 0;
int c;
char word[1000];
while((c = getchar()) != '\n') {
if (c != ' '){
word[i++] = c;
} else {
word[i] = '\0';
strcpy(words[j++], word);
i = 0;
}
}
word[i] = '\0';
strcpy(words[j++], word);
for (i = 0; i < j; i++) {
printf("%s\n", words[i]);
}
return 0;
}
i was uninitialized, so its value was undefined. It should start at 0. It also needs to be reset to 0 after each word so it starts at the beginning.
The second c = getchar() was unnecessary, as this is done in every iteration of the loop. This was causing your code to skip every other letter.
You need two counters, one for the place in the word, and one for the number of words read in. That's what j is.
== is for comparison, not assignment. Either way, strcpy() was needed here since you are filling out an array.
Rather than looping through all 100 elements of the array, just loop through the words that have actually been filled (up to j).
The last word input was ignored by your code, since it ends with a \n, not a . That's what the lines after the while are for.
When using printf(), the arguments should always be a format string ("%s"), followed by the arguments.
Of course, there are other things as well that I didn't fix (such as the disagreement between the 1000-character word and the 100-character words). If I were you, I'd think about what to do if the user entered, for some reason, more than 1000 characters in a word, or more than 100 words. Your logic will need to be modified in these cases to prevent illegal memory accesses (outside the bounds of the arrays).
As a reminder, this program does not accept an indefinite number of words, but only up to 100. You may need to rethink your solution as a result.

trying to write a letter counter in C

I am trying to make a program that counts the number of letters that the user has input. When I run my program, it says error: expected ';' after expression on the line count_letters(){ // writing the function to count number of letters? Does a function need a semicolon at the end? I also feel that I am not approaching this problem correctly, can someone please enlighten me :(
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <ctype.h>
int count_letters(); //function to count letters
int number_of_letters; //length of the string input
int letterCount; // counter for number of letters in the string input
int main(void) {
string text = get_string("Text: "); // getting string input
number_of_letters = strlen(text); //storing the length of string here
printf("Number of letters: %i\n", letterCount); //printing the number of letters in the string input
count_letters() { // writing the function to count number of letters
for (int i = 0; i < number_of_letters; i++) {
if (isalpha(text[i])) {
letterCount++;
}
}
}
}
While you are free to use strlen to get the initial number of characters in text, it isn't necessary. In C, the last character in a "string" is the nul-terminating character '\0' (which has the ASCII value of 0). This is what differentiates a normal array of characters, from a string. It is how all string functions know when to stop scanning for characters.
So you don't need to know beforehand how many characters there are in a string. For example, take the string "hello" entered at the "Text: " prompt where you have declared.
string text = get_string("Text: ");
When you enter "hello" at the prompt:
Text: hello
The string is stored in memory as:
+---+---+---+---+---+---+
| h | e | l | l | o |\0 |
+---+---+---+---+---+---+
^
|
text
where the pointer text points to the address of the first character of the string in memory. Using the fact that a string ends with a nul-terminating character, you can simply scan forward from the start until your reach '\0' (equivalent to plain old 0).
You can use a for loop and iterate using indexes:
for (int i = 0; text[i]; i++)
// do whatever with the character text[i]
Or you can use a pointer and simply increment the pointer so it points to the next character in the string until the '\0' is reached:
string p = text;
while (*p) {
// do whatever with *p (the character at that address)
p++;
}
Putting the last version into your int count_letters (string s) function (that passes a pointer to your string as a parameter to the function) and returns an int representing the number of letters (including only [a-zA-Z]), your function reduces to:
int count_letters (string s)
{
int n = 0;
while (*s) /* while not the nul-character */
if (isalpha (*s++)) /* check if current is letter, advance ptr */
n++; /* increment letter count */
return n; /* return letter count */
}
You main() function, not needing to call strlen() then reduces to:
int main (void) {
string text = get_string ("Text: ");
printf ("Number of letters: %d\n", count_letters(text));
}
Putting it altogether and including the needed headers, you would have:
#include <stdio.h>
#include <ctype.h>
#include "cs50.h"
int count_letters (string s)
{
int n = 0;
while (*s) /* while not the nul-character */
if (isalpha (*s++)) /* check if current is letter, advance ptr */
n++; /* increment letter count */
return n; /* return letter count */
}
int main (void) {
string text = get_string ("Text: ");
printf ("Number of letters: %d\n", count_letters(text));
}
Example Use/Output
Compile and link with the libcs50.so and then, for example you would have:
$ ./bin/ltrcountcs50
Text: hello world
Number of letters: 10
Understanding what a "string" in C is (outside of the unfortunate choice of the typedef char* string; used by CS50), allows you to handle scanning over the characters in your string without needing to know how many characters are included beforehand. (and also helps you understand why failing to provide a nul-terminated string to any of the C string function that expect a nul-terminated string as a parameter results in Undefined Behavior -- they have no way of knowing when to stop scanning for characters).
Look things over and let me know if you have further questions.
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <ctype.h>
int count_letters(); //function to count letters
int number_of_letters; //length of the string input
//initialize letterCount to 0 so that doing letterCount++ does not add 1 to a garbage value
int letterCount = 0; // counter for number of letters in the string input
//define string as a global value if you don't want to refer to it again and again by pass it as parameter or reference
string text;
void count_letters() { //since it's not returning anything, it's void not integer
for(int i = 0; i < number_of_letters; i++) {
if(isalpha(text[i])
letterCount++;
}
}
int main(void){
text = get_string("Text: "); // getting string input
number_of_letters = strlen(text); //storing the length of string here
printf("Number of letters: %i\n", letterCount); //printing the number of letters in the string input
}
Hope this helps. All the comments are there where any modifications are made
I might take your knowledge for being too basic, please forgive me if it is the case.
I believe you have made a small mistake possibly led by the way another language works. The problem lies in the way you have declared count_letters().
To properly declare a function in C, first get out of any existing function, then enter any variable type as a return type for your function, the name of your function, then, in parenthesis, your function's parameters. And after that, your function's code can be inserted between brackets, like you did.
Note you can also declare the function without the code, then put the code for the function lower.
And you might also want to declare your string externally to avoid dealing with pointers.
Here's an example of function declaration:
int foo(int amount)
Hence your code should look a little like this:
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <ctype.h>
void count_letters(); //function to count letters
int number_of_letters; //length of the string input
int letterCount; // counter for number of letters in the string input
string text;
int main(void) {
text = get_string("Text: "); // getting string input
number_of_letters = strlen(text); //storing the length of string here
count_letters();
printf("Number of letters: %i\n", letterCount); //printing the number of letters in the string input
}
void count_letters() { // writing the function to count number of letters
for (int i = 0; i < number_of_letters; i++) {
if (isalpha(text[i])) {
letterCount++;
}
}
}
Now please excuse me if I did not understand or answer your question correctly, it would be with pleasure I'd improve myself if I could get more detail. Lacking the cs50.h library, I cannot know for sure my code works.
#include <stdio.h>
#include <cs50.h>
#include <string.h>
#include <ctype.h>
int count_letters(char *); //function to count letters
int main(void)
{
char* text = get_string("Text: "); // getting string input
printf("Number of letters: %i\n", count_letters(text)); //printing the number of letters in the string input
}
int count_letters(char *text)
{ // writing the function to count number of letters
int letterCount,number_of_letters; //length of the string input
number_of_letters = strlen(text); //storing the length of string here
for(int i = 0; i < number_of_letters; i++){
if(isalpha(text[i]))
{
letterCount++;
}
return letterCount;
}

Trying to grab a character after a space in C

For an assignment I am doing, I have to print out the initials from a string in C (or, an array of characters). To do this, I know that I need to find where the SPACE is, using (int)name[i] == 32 to find if the current character is a SPACE. My only issue with this is that I am having trouble figuring out how I can find the space, and then store the next character in the array of character. (e.g., user enters Mike Baggins, I have to print out MB). I will post my code below, to show you how far I've gotten. Please help, but please don't give me the full solution. Thank you!
#include <cs50.h>
#include <stdio.h>
#include <string.h>
int main(void)
{
string name = get_string(); // gets the user's input
char firstI = name[0]; // stores the first character from the user's input
int len = strlen(name);
if((int)firstI >= 97 && (int)firstI <= 122) // checks if the character is lowercase
{
firstI -= 32; // makes the value uppercase
}
for(int i = 0; i < len; i++)
{
if((int)name[i] == 32) // checks if the character is SPACE
{
printf("I found a space!\n"); // prints out "I found a space"
}
}
printf("%c\n", firstI); // prints out the first initial
}
It's actually simple, see this for example
#include <stdio.h>
#include <ctype.h>
int
main(void)
{
char array[10];
char string[] = "Mike Baggins";
int j;
// Always put the first non-whitespace
// character (we should probably skip all
// spaces first
array[0] = string[0];
// Now start at the character following the first
j = 1;
for (int i = 1; ((string[i - 1] != '\0') && (j < sizeof(array) - 1)); ++i) {
if (string[i - 1] == ' ') {
array[j++] = toupper(string[i]);
}
}
array[j] = '\0';
puts(array);
return 0;
}
All I needed was to know that strings are simply arrays with a special value marking the end of them &rightarrow; '\0'. Of course, you can improve it a lot. For instance, you could count how many initials are there in the input string and allocate enough space to store them all.
Also, this will only work if the interesting character follows the space immediately, but knowing that it's just an array I am sure you can figure out how to extend it to make it ignore consecutive spaces.

To count the number of letters in a word and no of words in a sentence

I am just trying to experiment with counting the number of letters in a word.To distinguish between words in a string I am checking for blank spaces.If it encounters blank space then it is one word and it has respective letters.
For example "Hello World". So the output is supposed to be like
o/p
Hello has 5 letters
World has 5 letter
But when I am trying to write the code I am getting Segmentation fault. Below is the code.
#include <stdio.h>
#include <string.h>
main(void) {
int nc = 0;
int word = 0;
char str[] = "This test";
int len = strlen(str);
int i;
for(i = 0; i < len; i++)
{
++nc;
if(isspace(str)){
++word;
}
}
printf("%d\n",nc);
}
Try this..
for(i = 0; i < len; i++)
{
if(isspace(str[i]))
{
++word;
continue;
}
++nc;
}
if(len>0) word++;
printf("%d %d\n",nc, word);
Add #include <ctype.h> in the beginning to get the prototype of isspace(), and
if(isspace(str))
should be
if(isspace(str[i]))
First, add #include <ctype.h> in your code.
Next, isspace() intakes one int argument and checks the input [in terms of ASCII value] to be
white-space characters. In the "C" and "POSIX" locales, these are: space, form-feed ('\f'), newline ('\n'), carriage return ('\r'), horizontal tab ('\t'), and vertical tab ('\v').
So, you need to provide the elements of the array str one-by-one to isspace(). For that, you need to change your code to
if(isspace(str[i]))
which will give non-zero value if str[i] is a white-space character.
Also, to match your required output [as mentioned in the question], you need to make use of the intermediate values of str[i] and reset nc after every TRUE value of isspace().
Change the condition like this.
if(isspace(str[i]))
Because isspace is int isspace(int c);
int isspace(int c);
This is the prototype of isspace() function.
You need to pass the the value which you want to check like:
isspace(str[i]);
not the whole string.
Give it a try
int len = strlen(str); //len will be number of letters
for(int i = 0; i < len; i++)
{
if(isspace(str[i]))
++word;
}
if(len){
//if you dont want to count space letters then write
//len -= word;
word++; //counting last word
}
printf("letters = %d, Words =%d", len,word);
As you are getting len it will give you number of letters so no need to count nc.

Resources