Check for double characters - Functions - c

I have created a bit of code, that can check an input text for double characters. I got to work if I had all my code inside my main function, but have some trouble when I want to create an extra function. The error I am getting is the following: "error: control may reach end of non-void function", which I have identified to that the system cannot identify a return value from my count_double_characters function.
Can you help me understand what I am doing wrong?
#include <stdio.h>
#include <string.h>
int count_double_characters(char *ch);
int main(void)
{
char input[400];
printf("Write the text you want to check: ");
fgets(input, sizeof(input), stdin);
count_double_characters(input);
}
int count_double_characters(char *ch)
{
char n = strlen(ch);
int count_double = 0;
for (int i = 0; i < n; i++)
{
for (int j = i + 1; j < n; j++)
{
if (ch[i] == ch[j])
{
count_double++;
}
}
}
if (count_double > 0)
{
char s = printf("Its a double!\n");
return s;
}
else if (count_double == 0)
{
char d = printf("Looks good\n");
return d;
}
}

Consider this section of your code:
if (count_double > 0)
{
char s = printf("Its a double!\n");
return s;
}
else if (count_double == 0)
{
char d = printf("Looks good\n");
return d;
}
// if count_double is less than 0, the program goes here
// but there is non return statement, meaning that the function
// does not return any value.
// That what's the error message is telling you
}
Now you will tell me that count_double can never be 0, which is correct, but apparently the compiler is not smart enough to detect this.
To correct, you can simply drop the if (count_double == 0) or replace it with if (count_double <= 0).

Related

C strcpy segmentation fault when copying from another function [duplicate]

This question already has an answer here:
Segmentation fault when returning pointers [duplicate]
(1 answer)
Closed 3 months ago.
This is a snippet of the code from a project made in the programming class at my college, and my problem is that I get a segmentation fault error when I get to the strcpy part and I have no idea why.
I don't know if it's relevant or not, but I am coding in vs code under linux.
Here's the code:
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <ctype.h>
typedef struct Teams {
char country[20];
char sponsor[20];
char group;
int points;
} E;
char *sponsor_generator(char *country) {
int i, k = 0;
char sp[20];
for (i = strlen(country) - 1; i >= 0; i--) {
sp[k] = country[i];
k++;
}
sp[k] = '\0';
return sp;
}
void read(E *ec, int *n) {
(*n)++;
printf("Country: ");
scanf("%s", (ec + *n)->country);
(ec + *n)->group = (ec + *n)->country[0];
do {
printf("Number of points: ");
scanf("%d", &(ec + *n)->points);
} while ((ec + *n)->points >= 10);
strcpy((ec + *n)->sponsor, sponsor_generator((ec + *n)->country));
}
int main() {
int n = -1;
E ec[64];
read(ec, &n);
return 0;
}
I tried to look up any solutions, but I didn't find something that would work.
There are multiple problems in your code:
function sponsor_generator returns a pointer to a local array that become invalid as soon as the function returns. sponsor_generator should take the destination array as an argument.
naming the next function read probably clashes with the POSIX system call by the same name. Use a different name.
scanf("%s", (ec + *n)->country); may cause a buffer overflow if the input exceeds 19 characters. Always specify a limit and test the return value:
if (scanf("%19s", (ec + *n)->country) != 1) {
printf("premature end of file\n");
exit(1); // or return an error code to the caller
}
using the array syntax would make the code more readable.
naming the type E is a bad idea: using the structure tag Team would improve readability.
passing the address of the array element and relying on the function return value to increment the number of entries simplifies the code.
Here is a modified version:
#include <stdio.h>
#include <string.h>
typedef struct Team {
char country[20];
char sponsor[20];
char group;
int points;
} Team;
char *sponsor_generator(char *sp, const char *country) {
int i, k;
for (i = strlen(country), k = 0; i-- > 0; k++) {
sp[k] = country[i];
}
sp[k] = '\0';
return sp;
}
/* flush the remainder of the input line:
return EOF at end of file or on read error
return '\n' otherwise
*/
int flush_line(FILE *fp) {
int c;
while ((c = getc(fp)) != EOF && c != '\n')
continue;
return c;
}
int read_team(Team *team) {
int c, points, res;
printf("Country: ");
res = scanf("%19s", team->country);
flush_line(stdin);
if (res != 1) {
return -1;
}
for (;;) {
printf("Number of points: ");
res = scanf("%d", &points);
c = flush_line(stdin);
if (res != 1) {
printf("invalid input\n");
if (c == EOF) {
return -1;
}
} else {
if (points >= 0 && points < 10)
break;
printf("number of points must be between 0 and 9\n");
}
}
team->points = points;
team->group = team->country[0];
sponsor_generator(team->sponsor, team->country);
return 0;
}
void print_team(const Team *team) {
printf("country: %s, sponsor: %s, group: %c, points: %d\n",
team->country, team->sponsor, team->group, team->points);
}
int main() {
Team ec[64];
int n;
for (n = 0; n < 64; n++) {
if (read_team(&ec[n]) < 0) {
printf("premature end of file\n");
break;
}
}
for (int i = 0; i < n; i++) {
print_team(&ec[n]);
}
return 0;
}

Why does my bool function require "return true" to work normally?

I'm learning CS50x course. And the homework of problem set 2 is Caesar's algorithm.
I made it to work normally. But there's one thing make me confused:
the bool only_digits function - it requires a final return true to work normally. I searched on Google and people said there has to be a default return value, okay, I understand.
But when I switched it from TRUE to FALSE, the program just treated all the command-line arguments as FALSE. Therefore the program couldnt work.
I'm new to algorithm and programming. Please help me understand this part.
#include <cs50.h>
#include <stdio.h>
#include <ctype.h>
#include <string.h>
#include <stdlib.h>
bool only_digits(string s);
char rotate(char c, int n);
int main(int argc, string argv[])
{
// Make sure program was run with just one command-line argument
// Also make sure every character in argv[1] is a digit
if (argc < 2 || argc >2 || only_digits(argv[1]) == false)
{
printf("Usage: ./caesar key\n");
return 1;
}
// Convert argument to int
int x = atoi(argv[1]);
// Prompt the user
string plaintext = get_string("plaintext: ");
// Encrypt the plaintext
printf("ciphertext: ");
for (int i = 0, len = strlen(plaintext); i < len; i++)
{
char cipher = rotate(plaintext[i], x);
printf("%c", cipher);
}
printf("\n");
}
// Function check if only digit
bool only_digits(string s)
{
for (int i = 0, len = strlen(s); i < len; i++)
{
if (isdigit(s[i]))
{
while(s[i] == '\0')
return true;
}
else
{
return false;
}
}
return true; /* This part, I dont understand why */
}
// Function rotate
char rotate(char c, int n)
{
if (isalpha(c))
{
if (isupper(c))
{
c = 'A' + (c - 'A' + n) % 26;
return c;
}
else c = 'a' + ((c - 'a' + n) % 26);
return c;
}
else return c;
}
So I'll talk here about a single function, the one with the return true :
bool only_digits(string s)
{
for (int i = 0, len = strlen(s); i < len; i++)
{
if (isdigit(s[i]))
{
while(s[i] == '\0')
return true;
}
else
{
return false;
}
}
return true; /* This part, I dont understand why */
}
So you ask if (isdigit(s[i]) and then you start a while loop that terminates as soon as s[i] != '\0' which is already true as soon as you enter the if-body.
What you'd like to do is to check if there are any non-digits in your string.
Something like
bool only_digits(string s)
{
for (int i = 0, len = strlen(s); i < len; i++)
{
if (!isdigit(s[i]))
return false;
}
return true; /* if we didn't find a non-digit, we're fine */
}

Segmentation Fault when accessing command line argument ~ CS50

i'm new to CS and have been tackling cs50. its been a great experience so far as I was a math major and most of the concepts and assignments have been clicking really well.
i know part of the learning process is to solve your bugs yourself, but after a few hours staring at the one line that i narrowed down is causing the segmentation fault, I'm getting pretty frustrated.
I've attached my code below. i spent an hour watching a tutorial on pointers but still can't narrow down why I can pass in argv[1] to my function validateKey() but can't access the memory when i try to use it.
I saw experienced programmers stating that its crucial to be able to identify where exactly the segmentation fault is arising, so after debugging I noticed anytime in the program I try to access argv[1] (whether in main or local), that memory access is restricted
greatly appreciate your time and support!
#include <cs50.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
#include <stdlib.h>
#include <math.h>
int findIndex(char keyVal);
void cipherText(string s, string key);
bool validateKey(string s);
string alphabet = "abcdefghijklmnopqrstuvwxyz";
int main(int argc, char *argv[])
{
if (argc != 2)
{
printf("Usage ./substitution key\n");
return (1);
}
int length = strlen(argv[1]);
if (length != 26)
{
printf("Key must contain 26 characters\n");
return (1);
}
else
{
if (validateKey(argv[1])) //allows to pass argv[1]
{
string userText = get_string("plaintext: ");
cipherText(userText, argv[1]); //allows to pass
printf("\n");
return (0);
}
else
{
printf("Usage ./substitution key\n");
return (1);
}
}
}
bool validateKey(string s)
{
int n = strlen(s);
int hash[n][1];
for (int i = 0; i < n; i++)
{
int b;
if (isdigit(s[i]))
{
return false;
}
b = s[i];
if (hash[b][0] == 1)
{
return false;
}
else hash[b][0] = 1;
}
return true;
}
int findIndex(char keyVal)
{
for (int i = 0; i < 26; i++)
{
if (alphabet[i] == tolower(keyVal) || alphabet[i] == toupper(keyVal))
{
return i;
break;
}
}
return -1;
}
void cipherText(string s, string key)
{
printf("ciphertext: ");
for (int i = 0, n = strlen(s); i < n; i++)
{
if (!(isalnum(s[i])) || isdigit(s[i]))
{
printf("%c", s[i]);
continue;
}
int index = findIndex(s[i]);
if (index < 0) break;
if (isupper(s[i]))
{
printf("%c", toupper(key[index])); //SEGMENTATIONF
continue;
}
else if (islower(s[i]))
{
printf("%c", tolower(key[index]));
}
else printf("%c", s[i]);
}
}

CS50 Caesar segmentation fault

I am new here and working on the second homework Caesar of cs50, it seems most of my review is correct except the last one -- I cannot handle the situation of lacking argv[1], which means if I only type ./caesar, it will return segmentation fault. I am wondering why this code if (argc != 2) cannot return 0 when argc == 1, however it works when argc > 1, I find that is weird. Can anyone help me?? Thanks in advance!
# include <stdio.h>
# include <cs50.h>
# include <string.h>
# include <ctype.h>
# include <math.h>
# include <stdlib.h>
int check_the_key(int argc, string y);
int main(int argc, string argv[])
{
string x = argv[1];
int y = argc;
int k = check_the_key(y, x);
if (k == 0)
{
printf("ERROR!!!!!\n");
return 1;
}
else
{
// printf("The key is %i\n", k);
string text = get_string("Input your text:");
int i;
int n;
printf("ciphertext: ");
for (i = 0, n = strlen(text); i < n; i++)
{
if (islower(text[i]))
{
printf("%c", (text[i] - 97 + k) % 26 + 97 );
}
else if (isupper(text[i]))
{
printf("%c", (text[i] - 65 + k) % 26 + 65);
}
else
{
printf("%c", text[i]);
}
}
printf("\n");
return 0;
}
}
int check_the_key(int argc, string y)
{
int number = argc;
string key = y;
int numberkey = atoi(key);
if (argc != 2)
{
return 0;
}
else
{
if (numberkey > 0)
{
return numberkey;
}
else
{
return 0;
}
}
}
I know what is going on! Because I need to pass some value into atoi(), if I only call ./caesar, there is no value I can pass into atoi(), so it causes segmentation fault. Which means I need to change code order slightly, put int numberkey = atoi(key); inside the else loop. So the code will run if (argc != 2) first, if no, then go to the next step! Here is the code after change.
int check_the_key(int argc, string y)
{
int number = argc;
string key = y;
if (argc != 2)
{
return 0;
}
else
{
int numberkey = atoi(key);
if (numberkey > 0)
{
return numberkey;
}
else
{
return 0;
}
}
}

printing substrings in a file

So I want to write a program which would print out a text line that contains a certain word from a file. e.g. if I was looking for a word 'linux' it would print out
2 computers called linux00, linux01 and linux02. 5 manager,"
said linux00. "Hello linux00," said 7 here to see us?" said
linux01. "Well," said the 10 linux02. "You're all going to be
unplugged," said 12 goooooooooooo..." said linux00.
from a story.txt:
Once upon a time, there were three little computers called
linux00, linux01 and linux02. One day, the nice computer manager
came into the Linux Laboratory. "Hello nice computer manager,"
said linux00. "Hello linux00," said the nice computer manager.
"What brings you here to see us?" said linux01. "Well," said the
nice computer manager, "I've got bad news and I've got good
news." "What's the bad news?" said linux02. "You're all going to be
unplugged," said the nice computer manager. "What's the
goooooooooooo..." said linux00.
Here's my code:
#include<stdio.h>
#include <stdlib.h>
#define ARR_LEN 100
int getLine(FILE * fin,char a[],int n)
{
int find = contains("linux", 5, a, ARR_LEN);
int count;
int i;
i = 0;
char c = getc(fin);
while(c != '\n')
{
a[i] = c;
// printf ("%c", a[i]);
//i = 0;
if (a[i] == EOF){
return EOF;
}
if (find == 1)
{
printf("%c", c);
c = getc(fin);
}
i = i + 1;
}
if(a[i]=='\n')
{
if ((i - 1) > ARR_LEN) {
printf("warning msg: length is over array bounds\n");
}
// printf("length of line is: %d\n", i - 1);
//printf("%c", a[i]);
i = i + 1;
//printf("\n");
return i - 1;
}
}
int contains(char target[], int m, char source[], int n) {
int flag = 0; // the source originally does not contain the target
int i;
for(i = 0; i < n; i++) { // go through each character of the source string
int targetIndex = 0;
int j;
/*check if the preceding characters of the source string are a substring
that matches the target string*/
for(j = i; j < n && targetIndex < m; j++) {
if(target[targetIndex] == source[j]) {
targetIndex += 1;
if(targetIndex == m) { // the 'target' has been fully found
flag = 1;
break;
}
}
else
{
break;
}
}
if(flag == 1) // 'target' is already found, no need to search further
{
break;
}
}
return flag;
}
main(int argc,char ** argv)
{
setbuf(stdout,NULL);
char a[ARR_LEN];
FILE * fin;
if(argc<2){
printf("wrong number of arguments\n");
exit(0);
}
fin = fopen(argv[1], "r");
if (fin == NULL) {
printf("Cannot open %s\n", fin);
exit(0);
}
int t = 0;
int j = 0;
int find = contains("linux", 5, a, ARR_LEN);
while (j != EOF)
{
t = t + 1;
printf("%d ", t);
j = getLine(fin,a,ARR_LEN);
printf("\n");
}
fclose(fin);
}
The getLine function is alright and it prints out a text with a line number in front all good. But the problem is with this
if (find == 1)
{
printf("%c", c);
c = getc(fin);
}
part, where I want the program to only print out the line if "contains" finds a match in that line.
Thanks for any help & sorry for a long post!!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int main()
{
char sentence[500];
char word[10] = "linux";
FILE* fp1 = fopen("strstr.txt","r");
if(fp1 == NULL)
{
printf("Failed to open file\n");
return 1;
}
while((fscanf(fp1,"%[^\n]\n",sentence)>0))
{
if(strstr(sentence,word)!=NULL)
printf("%s\n\n",sentence);
}
}

Resources