I'm making a simple code for simulating Caesar's cypher and I'm having a weird bug where, although the output string fraseout[] is formed correctly and will print correctly at the very last print it gets it's last character trimmed. Why is this happening?
#include <stdio.h>
#include <string.h>
#include <math.h>
int main (void)
{
printf("Insira a frase:\n");
char frase [256];
scanf("%s", frase);
int size = (int)strlen(frase);
printf("Insira o tamanho da divergência: \n");
int diff = 0;
scanf("%i", &diff);
char fraseout [size];
int i = 0;
for (i = 0; i<=size-1; i++)
{
int val = (int)frase[i];
if (val + diff > 126)
{
val = 31+diff-(126-val);
}
else if (val +diff < 32)
{
val = 127 + diff+(val-32);
}
else
{
val +=diff;
}
fraseout [i] = (char)val;
}
printf("\"%s\" -> \"%s\"\n", frase, fraseout);
return 0;
}
fraseout is not long enough to hold the NULL terminating byte, so you need to make it one bigger:
char fraseout [size+1];
Also, after building fraseout, you need to make sure it's NULL terminated, otherwise you'll print garbage:
fraseout[size] = '\0';
There are two related points,
Need to take the size as strlen()+ 1, as strlen() does not take into account the terminating null.
Need to make the fraseout[i], the last element as 0 or '\0' to make it usable as a string.
Related
Good evening. I'm working on a program for class and I am hitting a brick wall when it comes to dealing with arrays using C.
--EDIT-- Full code has been posted.
#define _CRT_SECURE_NO_WARNINGS
#define STRMAX 20
#define MAX 100
#include<stdio.h>
int main()
{
int count = 0;
char strlist[STRMAX][MAX];
int start = 0, end = STRMAX;
for (start; start < end; start++) {
char string[MAX];
printf("Enter a string: ");
fgets(string, MAX - 1, stdin);
printf("\nThe string is: %s", string);
int size = strlen(string);
int result = strcmp(string, "stop\n");
if (result == 0) {
break;
}
strcpy(strlist[start], string);
count = count + 1;
}
char rev[STRMAX][MAX];
int temp = 0;
printf("count is: %d\n",count);
while (count != 0) {
strcpy(rev[temp], strlist[count]);
temp = temp + 1;
count = count - 1;
}
printf(rev);
return 0;
}
The last line, printf(rev); is throwing the warning: "using uninitialized memory 'rev'. "
I do not understand C, its the beginning of this course. However I am NOT looking for a "do my homework for me" answer, more of a "here is a better way to go about this" answer.
the output for the code is:
Enter a string: 1
The string is: 1
Enter a string: 2
The string is: 2
Enter a string: 3
The string is: 3
Enter a string: stop
The string is: stop
count is: 3
╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠╠3
the "count is: 3" is entirely for debugging. I really don't have a clue why my solution doesn't work. If there is any more information that is needed or anything else you would like to see feel free to ask and i'll update the post! thanks.
--EDIT--
STRMAX and MAX are both definitions set for the 2D array required for keeping an array of strings (20 and 50 respectively)
First of all, the line
strcpy(rev[temp], strlist[count]);
is wrong. Valid indexes for strlist are 0 to count-1, assuming that you only want to read valid strings. However, you are using the indexes 1 to count instead. Therefore, you should move the line
count = count - 1;
before that line.
Also, the line
printf(rev);
does not make sense.
If you want to print all strings in the array, then you should print every string individually, in a loop.
Since you are storing the number of valid strings in the variable temp, you must print that many strings.
for ( int i = 0; i < temp; i++ )
{
printf( "%s\n", rev[i] );
}
Also, you should #include <string.h>, because you are using strcpy and strlen.
Additionally, you probably should remove the trailing newline character from the input obtained from fgets. Otherwise, you will be printing that newline character, which will give you unwanted extra lines, forcing you to compensate by printing less newline characters explicitly. The existance of the newline character is also forcing you to add a newline character to the target string "stop":
int result = strcmp(string, "stop\n");
You will be able to remove that newline character from the target string if you also remove it from the input string.
After making these changes, your code should look like this:
#define _CRT_SECURE_NO_WARNINGS
#define STRMAX 20
#define MAX 100
#include <stdio.h>
#include <string.h>
int main()
{
int count = 0;
char strlist[STRMAX][MAX];
int start = 0, end = STRMAX;
for (; start < end; start++) {
char string[MAX];
printf("Enter a string: ");
fgets(string, MAX - 1, stdin);
//remove trailing newline character
string[strcspn(string,"\n")] = '\0';
printf("The string is: %s\n", string);
int result = strcmp(string, "stop");
if (result == 0) {
break;
}
strcpy(strlist[start], string);
count = count + 1;
}
char rev[STRMAX][MAX];
int temp = 0;
printf("count is: %d\n",count);
while (count != 0) {
count = count - 1;
strcpy(rev[temp], strlist[count]);
temp = temp + 1;
}
for ( int i = 0; i < temp; i++ )
{
printf( "%s\n", rev[i] );
}
return 0;
}
This program has the following output:
Enter a string: 1
The string is: 1
Enter a string: 2
The string is: 2
Enter a string: 3
The string is: 3
Enter a string: stop
The string is: stop
count is: 3
3
2
1
Im trying to code a program in C to generate a string containing random letters using only arrays first and then again using pointers. I've looked at many other questions but is not quite what I'm trying to accomplish. I can really use help please.
Function 1- Generates a string with random upper
case letter A-Z with 40 characters.
Function 2- Function to let user enter a string
with random upper case letter and a replacement character.
Function 3- Searches string1 from function 1 and replaces
occurences of any character from string 2 (user entered) with
replacement character.
OUTPUT EX.
String 1- "AABBCCDDEEFFGGHHABCDEFGH"
String 2- "BE"
Replacement char- "3"
Filtered string- AA33CCDD33FFGGHHA3CD3FGH.
This is what I have so far, Im not very good with arrays.
#include <stdio.h>
#include <stdlib.h>
int main()
{
int s1 [41];
srand(time(NULL));
int i;
for (i = 0; i < 41; i++)
{
s1 [i] = rand();
}
return 0;
}
Any help will be appreciated.
Thanks alot.
#include <stdio.h>
#include <stdlib.h>
void rand_str(char* txt, size_t sz)
{
int i=sz-1;
while( i --> 0 )
{
txt[i] = 'A' + rand() % 26;
}
printf("Random Str: %.*s\n", sz+i, txt);
}
void fn2(char* tgt, size_t sz, char* repl )
{
puts("String 2: ");
fgets(tgt, sz, stdin);
puts("Replacement Char: ");
*repl = getchar();
}
void search_replace(char* txt, char* tgt, char repl)
{
while(*tgt != '\0')
{
while ((strchr(txt, *tgt) ? (tgt[strchr(txt, *tgt)-tgt] = repl) : 0) == repl);
tgt++;
}
}
int main(void)
{
char txt[41] = {0};
char tgt[40] = {0};
char repl;
rand_str(txt, sizeof(txt));
fn2(tgt, sizeof(tgt), &repl);
search_replace(txt, tgt, repl);
return !printf("Filtered String: %s\n", txt);
}
Please note that I did not compile any of this code. It might have some typo and/or runtime errors. The concept is correct though and you should understand the code first and not just copy it.
Function 1:
#include <stdlib.h> // Important! rand() function that generate random function is in that library!
//This function returns a pointer of an array (arr). In other words it returns the **address** of the first character of the array.
// Assuming arr is valid!
char* randomString(char* arr){
// This part does not REALLLYY matters it just makes sure the random will truly be random...
time_t t;
srand((unsigned) time(&t)); // Seeds the random function.
//------------------
//Looping the array assigning random letters:
int i = 0;
while(i<SIZE){
arr[i] = 'A'+(rand()%('Z'-'A'+1));// 'A' has a numerical value, we want the range from 'A' to 'Z' to be random. 'Z'-'A' is the range of letters (26) because its a modulu if the modulu was just 'Z'-'A' (26) it wouldnt print Z. 'Z' is the 26th letter, 26%26 is zero, it will not give 'Z' this is why I increased 'Z'-'A' by 1 so the modulu will include 'Z' as random latter.
i = i + 1;
}
arr[i] = 0;// String terminator also called NULL.
return "lol";
}
Function 2:
#include <string.h>
int replace(char* inputString, char* userInput,char replacement ){
/* e.g.
inputString = "ABSDSADASBBBAA";//Generate yourself... (Might want to user function 1)
userInput = "AB"; // You need to do the user input yourself...
replacement = 'D';
*/
int i = 0;
while(i<strlen(inputString)){
int j = 0;
while(j<strlen(userInput)){
if(inputString[i]==userInput[j]){
inputString[i] = replacement;
}
j = j+1;
}
i = i + 1;
}
}
Function 3:
int main(){
// Just use regular IO libraries to get user's input...
// Assuming you did that, I will hard code the values (you need to do the IO e.g. gets())
char str[SIZE];
randomString(str); // Requirement #1 reuse of function 1
char * userInput = "AB"; // You need to do the user input yourself...
char replacement = 'D';// You need to do the user input yourself...
replace(str, userInput, replacement)//Requirement #2
return 0;
}
This is for Homework
I have to write a program that asks the user to enter a string, then my program would separate the even and odd values from the entered string. Here is my program.
#include <stdio.h>
#include <string.h>
int main(void) {
char *str[41];
char odd[21];
char even[21];
int i = 0;
int j = 0;
int k = 0;
printf("Enter a string (40 characters maximum): ");
scanf("%s", &str);
while (&str[i] < 41) {
if (i % 2 == 0) {
odd[j++] = *str[i];
} else {
even[k++] = *str[i];
}
i++;
}
printf("The even string is:%s\n ", even);
printf("The odd string is:%s\n ", odd);
return 0;
}
When I try and compile my program I get two warnings:
For my scanf I get "format '%s' expects arguments of type char but argument has 'char * (*)[41]". I'm not sure what this means but I assume it's because of the array initialization.
On the while loop it gives me the warning that says comparison between pointer and integer. I'm not sure what that means either and I thought it was legal in C to make that comparison.
When I compile the program, I get random characters for both the even and odd string.
Any help would be appreciated!
this declaration is wrong:
char *str[41];
you're declaring 41 uninitialized strings. You want:
char str[41];
then, scanf("%40s" , str);, no & and limit the input size (safety)
then the loop (where your while (str[i]<41) is wrong, it probably ends at once since letters start at 65 (ascii code for "A"). You wanted to test i against 41 but test str[i] against \0 instead, else you get all the garbage after nul-termination char in one of odd or even strings if the string is not exactly 40 bytes long)
while (str[i]) {
if (i % 2 == 0) {
odd[j++] = str[i];
} else {
even[k++] = str[i];
}
i++;
}
if you want to use a pointer (assignement requirement), just define str as before:
char str[41];
scan the input value on it as indicated above, then point on it:
char *p = str;
And now that you defined a pointer on a buffer, if you're required to use deference instead of index access you can do:
while (*p) { // test end of string termination
if (i % 2 == 0) { // if ((p-str) % 2 == 0) { would allow to get rid of i
odd[j++] = *p;
} else {
even[k++] = *p;
}
p++;
i++;
}
(we have to increase i for the even/odd test, or we would have to test p-str evenness)
aaaand last classical mistake (thanks to last-minute comments), even & odd aren't null terminated so the risk of getting garbage at the end when printing them, you need:
even[k] = odd[j] = '\0';
(as another answer states, check the concept of even & odd, the expected result may be the other way round)
There are multiple problems in your code:
You define an array of pointers char *str[41], not an array of char.
You should pass the array to scanf instead of its address: When passed to a function, an array decays into a pointer to its first element.
You should limit the number of characters read by scanf.
You should iterate until the end of the string, not on all elements of the array, especially with (&str[i] < 41) that compares the address of the ith element with the value 41, which is meaningless. The end of the string is the null terminator which can be tested with (str[i] != '\0').
You should read the characters from str with str[i].
You should null terminate the even and odd arrays.
Here is a modified version:
#include <stdio.h>
int main(void) {
char str[41];
char odd[21];
char even[21];
int i = 0;
int j = 0;
int k = 0;
printf("Enter a string (40 characters maximum): ");
if (scanf("%40s", str) != 1)
return 1;
while (str[i] != '\0') {
if (i % 2 == 0) {
odd[j++] = str[i];
} else {
even[k++] = str[i];
}
i++;
}
odd[j] = even[k] = '\0';
printf("The even string is: %s\n", even);
printf("The odd string is: %s\n", odd);
return 0;
}
Note that your interpretation of even and odd characters assumes 1-based offsets, ie: the first character is an odd character. This is not consistent with the C approach where an even characters would be interpreted as having en even offset from the beginning of the string, starting at 0.
Many answers all ready point out the original code`s problems.
Below are some ideas to reduce memory usage as the 2 arrays odd[], even[] are not needed.
As the "even" characters are seen, print them out.
As the "odd" characters are seen, move them to the first part of the array.
Alternative print: If code used "%.*s", the array does not need a null character termination.
#include <stdio.h>
#include <string.h>
int main(void) {
char str[41];
printf("Enter a string (40 characters maximum): ");
fflush(stdout);
if (scanf("%40s", str) == 1) {
int i;
printf("The even string is:");
for (i = 0; str[i]; i++) {
if (i % 2 == 0) {
str[i / 2] = str[i]; // copy character to an earlier part of `str[]`
} else {
putchar(str[i]);
}
}
printf("\n");
printf("The odd string is:%.*s\n ", (i + 1) / 2, str);
}
return 0;
}
or simply
printf("The even string is:");
for (int i = 0; str[i]; i++) {
if (i % 2 != 0) {
putchar(str[i]);
}
}
printf("\n");
printf("The odd string is:");
for (int i = 0; str[i]; i++) {
if (i % 2 == 0) {
putchar(str[i]);
}
}
printf("\n");
here is your solution :)
#include <stdio.h>
#include <string.h>
int main(void)
{
char str[41];
char odd[21];
char even[21];
int i = 0;
int j = 0;
int k = 0;
printf("Enter a string (40 characters maximum): ");
scanf("%s" , str);
while (i < strlen(str))
{
if (i % 2 == 0) {
odd[j++] = str[i];
} else {
even[k++] = str[i];
}
i++;
}
odd[j] = '\0';
even[k] = '\0';
printf("The even string is:%s\n " , even);
printf("The odd string is:%s\n " , odd);
return 0;
}
solved the mistake in the declaration, the scanning string value, condition of the while loop and assignment of element of array. :)
This code don't count words properly. I don't know if it is wrong on the for or what. Need help.
#include <stdio.h>
#include <stdlib.h>
int count_p(char sentence[100]) {
int i, m = 1;
for (i = 0 ; i < 100 ; i++) {
if (sentence[i] == ' ') {
m += 1;
}
}
return(m);
}
void main() {
char s[100];
int p;
printf("Sentence here: ");
scanf("%s", &s[50]);
p = count_p(sentence);
printf("Words: %d", p);
printf("\n");
}
The %s in scanf stops reading when it found a whitespace. Therefore, ' ' won't appear in s unless it was there as indeterminate value in uninitialized variable.
You can use fgets to read a whole line.
Here is a fixed code that also checks for end of the string.
#include <stdio.h>
#include <stdlib.h>
int count_p(char sentence[100]) {
int i, m = 1;
for (i = 0 ; i < 100 && sentence[i] != '\0'; i++) {
if (sentence[i] == ' ') {
m += 1;
}
}
return(m);
}
int main(void) {
char s[100];
int p;
printf("Sentence here: ");
fgets(s, sizeof(s), stdin);
p = count_p(s);
printf("Words: %d", p);
printf("\n");
return 0;
}
scanf("%s", &s[50]);
Not a correct way to take input and writing at index which is out of bound. Do this instead -
scanf("%99[^\n]", s); // this will read 99 characters and until '\n' is encountered
In main you function call is incorrect -
p = count_p(sentence); // sentence is not declares in main
Call like this -
p = count_p(s); // pass s instead of sentence to function
Also in function count_p change ccondition in for loop as -
size_t i;
size_t len=strlen(s);
for (i = 0 ; i < len ; i++)
You see &s[50] means that you pass a pointer to the 51-th element of s, you then try to access s from the beginning but, the first 50 characters in s were not yet initialized, this leads to undefined behavior.
Also, your loop from 0 to 99 will have the same issue since you might input a string of less than 100 characters, in that case you would be accessing uninitialized data too.
You can fix your program by changing this
scanf("%s", &s[50]);
to
scanf("%99s", s);
and then
for (i = 0 ; i < 100 ; i++) {
to
for (i = 0 ; s[i] != '\0' ; i++) {
because scanf() will append a '\0' to make the array a valid c string, that's also the reason for the "%99s".
Another problem is that, if you want white space characters not to make scanf() stop reading, you need a different specifier, because "%s" stops at the first white space character, this is a suggestion
scanf("%99[^\n]", s);
Or you can do as #MikeCAT suggested and go with fgets(). But be careful with the trailing '\n' in case of fgets().
And finally, altough highly unlikely in this situation, scanf() might fail. To indicate success it returns the number of specifiers actually matched, thus it might indicate partial success too. It's fairly common to see the return value of scanf() ignored, and it's very bad when you have a "%d" specifier for example because then the correspoinding parameter might be accessed before initializing it.
The statement scanf("%s", &s[50]); is in correct in your situation.Since you want to enter a sentence separated by spaces,the correct way of doing it is :
scanf(" %99[^\n]s",sentence);
That will prevent buffer overflow and allow space between words.Also your program does not seem to count words correctly if the sentence has consecutive whitespaces.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
int count_p(char *sentence);
void main()
{
char sentence[100];
printf("Sentence here: ");
scanf(" %99[^\n]s",sentence);
int p = count_p(sentence);
printf("Words: %d", p);
printf("\n");
}
int count_p(char *sentence)
{
int len = strlen(sentence);
int x = 0 , wordCount = 0;
for( int n = 0 ; n < len ; n++ )
{
x++;
if( sentence[n] == ' ' )
x = 0;
if( x == 1 )
wordCount++;
}
return wordCount;
}
#include <stdlib.h>
#include <time.h>
#include <ctype.h>
#include <stdio.h>
#include <string.h>
#include <ctype.h>
//function prototypes
void checkAnswer(char *, char[]);
int main(void) {
char *strGame[5] = { "ADELANGUAGEFERVZOPIBMOU", "ZBPOINTERSKLMLOOPMNOCOT",
"PODSTRINGGDIWHIEEICERLS", "YVCPROGRAMMERWQKNULTHMD",
"UKUNIXFIMWXIZEQZINPUTEX" };
char answer[80] = { 0 };
int displayed = 0;
int x;
int startTime = 0;
system("clear");
printf("\n\n\tWord Find\n\n");
startTime = time(NULL);
for (x = 0; x < 5; x++) {
/* DISPLAY TEXT FOR A FEW SECONDS */
while (startTime + 3 > time(NULL)) {
if (displayed == 0) {
printf("\nFind a word in: \n\n");
printf("%s\n\n", strGame[x]);
displayed = 1;
}
}
system("clear");
printf("\nEnter word found: ");
fgets(answer, 80, stdin);
checkAnswer(strGame[x], answer);
displayed = 0;
startTime = time(NULL);
}
}
void checkAnswer(char *string1, char string2[]) {
int x;
for (x = 0; x <= strlen(string2); x++)
string2[x] = toupper(string2[x]);
if (strstr(string1, string2) != 0)
printf("\nGreat job!\n");
else
printf("\nSorry, word not found!\n");
}
When I run the code, it doesn't register my input correctly. It tells me that the word wasn't found. I used toupper to make my input the same as my strings and strstr to compare my input with the strings. I took this from a basic C programming book. It used gets. I know that you shouldn't use gets so I changed it to fgets. Is this where the problem is? Any suggestions?
You can avoid the issue with the \n (newline) mentioned by BLUEPIXY -- namely, that gets() removes it but fgets() does not -- by reversing the terms in your call to checkAnswer():
checkAnswer(answer, strGame[x]);
checkAnswer() then uses the same order with strstr(). If you search for "foobar" in "foobar\n", strstr() will return a pointer. But if you search for "foobar\n" in "foobar", it won't.
The newline is there because the user hits Enter. So another way around this would be to add a \n to the end of all your strGame[] strings. Or, you could remove any newline in the answer with:
void truncateAtNewline (char *str) {
char *p = strchr(str, '\n');
if (p) *p = '\0';
}
The problem is that fgets() will leave the newline at the end of the string. When you type the word, then you press Enter and fgets() interprets that as input.
So, a way to bypass this is to eat the newline by doing this:
fgets(answer, 80, stdin);
// go to the last position where the
// newline is placed and replace it
// with the null terminator
answer[strlen(answer)-1] = '\0';
Also here:
for (x = 0; x <= strlen(string2); x++)
string2[x] = toupper(string2[x]);
the <= is not needed, since you start from 0, thus change it to this:
for (x = 0; x < strlen(string2); x++)
string2[x] = toupper(string2[x]);
How I found your problem? I used printf to output the strings before comparing them.
void checkAnswer(char *string1, char string2[]) {
int x;
for (x = 0; x < strlen(string2); x++)
string2[x] = toupper(string2[x]);
printf("|%s|\n", string1);
printf("|%s|\n", string2);
if (strstr(string1, string2) != 0)
printf("\nGreat job!\n");
else
printf("\nSorry, word not found!\n");
}
Output before my fix:
|ADELANGUAGEFERVZOPIBMOU|
|ADEL
|
Output after the fix:
|ADELANGUAGEFERVZOPIBMOU|
|ADEL|
Or you can use a function to trim newlines and spaces. I have some methods here.
Consider also not using system().
Moreover, always add a return 0; line of code before your main() ends.