so i've looked through here and on google and tried various forms to try and accomplish this. it doesn't seem like it should be hard. i've tried getting a value from the char, tried just using math on it since i've read that a char in C is a number to the compiler anyway. what i have is an array of 4 strings. each element is another array of 20 + 1 characters (to include the null \0) what i'm trying to do is shift the value of each character in each string by a predefined amount using a variable "decryption_shift". what i thought i was doing is using 2 for loops, one to do one string at a time, the other to change each character in the strings. i've tried using pointers, tmp variables. yes this is a homework assignment, problem is it's a higher level class and they aren't teaching us methods/functions/syntax, they want us to research and learn on our own how to do it. i've already spent 2 hours trying to figure out this one snippet and don't know where else to turn. any help is greatly appreciated.
~justin
void decrypt_chunks()
{
for (m = 0; m < 0; m++)
{
for (n = 0; n < 20; n++)
{
// int *chunksp = &chunks[m][n];
chunks[m][n] = chunks[m][n] - DECRYPTION_SHIFT;
// *chunksp[m][n]=tmp;
// chunks[m][n]=tmp;
}
}
}
Your problem is here:
for (m = 0; m < 0; m++)
The loop will never execute because the termination condition is met on initialization. Try
for (m = 0; m < 4; m++)
I can't see where DECRYPTION_SHIFT or chunks is defined (and initialized), so make sure you're actually define it globally or in the decrpyt_chunks() function (note: usually you write variables lowercase and macros uppercase, and if DECRYPTION_SHIFT is a variable you should write it in lowercase letters)
for (m = 0; m < 0; m++) while never run, this statement in words would be something like: set m to ziro (btw where did you defined m?) and do the following things as long as m is less than ziro (never the case, as you set it to ziro)
As this seems like a very basic problem, make sure you actually understand what a programming language is and how it works and consider reading one or two books about c (or almost any other programming language, as this homework would be in most modern languages pretty much the same).
To really make this thing interresting, what you basically do is encrypting like Caesar, so to implement this, the code could look similar to this one:
#include <stdio.h>
#include <string.h>
void decrypt_chunks(int decryption_shift);
char chunks[4][21];
int main(int stdr, char *stdv[])
{
strcpy(chunks[0],"Hello World! And Bye");
printf("message string: %s\n", chunks[0]);
decrypt_chunks(1);
printf("encrypted string: %s\n", chunks[0]);
decrypt_chunks(-1);
printf("decrypted sring: %s\n", chunks[0]);
}
void decrypt_chunks(int decryption_shift)
{
for (int m = 0; m < 4; m++)
{
for (int n = 0; n < 20; n++)
{
chunks[m][n] = chunks[m][n] - decryption_shift;
}
}
}
Related
I wrote a program that counts and prints the number of occurrences of elements in a string but it throws a garbage value when i use fgets() but for gets() it's not so.
Here is my code:
#include<stdio.h>
#include<string.h>
#include<ctype.h>
#include<stdlib.h>
int main() {
char c[1005];
fgets(c, 1005, stdin);
int cnt[26] = {0};
for (int i = 0; i < strlen(c); i++) {
cnt[c[i] - 'a']++;
}
for (int i = 0; i < strlen(c); i++) {
if(cnt[c[i]-'a'] != 0) {
printf("%c %d\n", c[i], cnt[c[i] - 'a']);
cnt[c[i] - 'a'] = 0;
}
}
return 0;
}
This is what I get when I use fgets():
baaaabca
b 2
a 5
c 1
32767
--------------------------------
Process exited after 8.61 seconds with return value 0
Press any key to continue . . . _
I fixed it by using gets and got the correct result but i still don't understand why fgets() gives wrong result
Hurray! So, the most important reason your code is failing is that your code does not observe the following inviolable advice:
Always sanitize your inputs
What this means is that if you let the user input anything then he/she/it can break your code. This is a major, common source of problems in all areas of computer science. It is so well known that a NASA engineer has given us the tale of Little Bobby Tables:
Exploits of a Mom #xkcd.com
It is always worth reading the explanation even if you get it already #explainxkcd.com
medium.com wrote an article about “How Little Bobby Tables Ruined the Internet”
Heck, Bobby’s even got his own website — bobby-tables.com
Okay, so, all that stuff is about SQL injection, but the point is, validate your input before blithely using it. There are many, many examples of C programs that fail because they do not carefully manage input. One of the most recent and widely known is the Heartbleed Bug.
For more fun side reading, here is a superlatively-titled list of “The 10 Worst Programming Mistakes In History” #makeuseof.com — a good number of which were caused by failure to process bad input!
Academia, methinks, often fails students by not having an entire course on just input processing. Instead we tend to pretend that the issue will be later understood and handled — code in academia, science, online competition forums, etc, often assumes valid input!
Where your code went wrong
Using gets() is dangerous because it does not stop reading and storing input as long as the user is supplying it. It has created so many software vulnerabilities that the C Standard has (at long last) officially removed it from C. SO actually has an excellent post on it: Why is the gets function so dangerous that it should not be used?
But it does remove the Enter key from the end of the user’s input!
fgets(), in contrast, stops reading input at some point! However, it also lets you know whether you actually got an entire line of of text by not removing that Enter key.
Hence, assuming the user types: b a n a n a Enter
gets() returns the string "banana"
fgets() returns the string "banana\n"
That newline character '\n' (what you get when the user presses the Enter key) messes up your code because your code only accepts (or works correctly given) minuscule alphabet letters!
The Fix
The fix is to reject anything that your algorithm does not like. The easiest way to recognize “good” input is to have a list of it:
// Here is a complete list of VALID INPUTS that we can histogram
//
const char letters[] = "abcdefghijklmnopqrstuvwxyz";
Now we want to create a mapping from each letter in letters[] to an array of integers (its name doesn’t matter, but we’re calling it count[]). Let’s wrap that up in a little function:
// Here is our mapping of letters[] ←→ integers[]
// • supply a valid input → get an integer unique to that specific input
// • supply an invalid input → get an integer shared with ALL invalid input
//
int * histogram(char c) {
static int fooey; // number of invalid inputs
static int count[sizeof(letters)] = {0}; // numbers of each valid input 'a'..'z'
const char * p = strchr(letters, c); // find the valid input, else NULL
if (p) {
int index = p - letters; // 'a'=0, 'b'=1, ... (same order as in letters[])
return &count[index]; // VALID INPUT → the corresponding integer in count[]
}
else return &fooey; // INVALID INPUT → returns a dummy integer
}
For the more astute among you, this is rather verbose: we can totally get rid of those fooey and index variables.
“Okay, okay, that’s some pretty fancy stuff there, mister. I’m a bloomin’ beginner. What about me, huh?”
Easy. Just check that your character is in range:
int * histogram(char c) {
static int fooey = 0;
static int count[26] = {0};
if (('a' <= c) && (c <= 'z')) return &count[c - 'a'];
return &fooey;
}
“But EBCDIC...!”
Fine. The following will work with both EBCDIC and ASCII:
int * histogram(char c) {
static int fooey = 0;
static int count[26] = {0};
if (('a' <= c) && (c <= 'i')) return &count[ 0 + c - 'a'];
if (('j' <= c) && (c <= 'r')) return &count[ 9 + c - 'j'];
if (('s' <= c) && (c <= 'z')) return &count[18 + c - 's'];
return &fooey;
}
You will honestly never have to worry about any other character encoding for the Latin minuscules 'a'..'z'.Prove me wrong.
Back to main()
Before we forget, stick the required magic at the top of your program:
#include <stdio.h>
#include <string.h>
Now we can put our fancy-pants histogram mapping to use, without the possibility of undefined behavior due to bad input.
int main() {
// Ask for and get user input
char s[1005];
printf("s? ");
fgets(s, 1005, stdin);
// Histogram the input
for (int i = 0; i < strlen(s); i++) {
*histogram(s[i]) += 1;
}
// Print out the histogram, not printing zeros
for (int i = 0; i < strlen(letters); i++) {
if (*histogram(letters[i])) {
printf("%c %d\n", letters[i], *histogram(letters[i]));
}
}
return 0;
}
We make sure to read and store no more than 1004 characters (plus the terminating nul), and we prevent unwanted input from indexing outside of our histogram’s count[] array! Win-win!
s? a - ba na na !
a 4
b 1
n 2
But wait, there’s more!
We can totally reuse our histogram. Check out this little function:
// Reset the histogram to all zeros
//
void clear_histogram(void) {
for (const char * p = letters; *p; p++)
*histogram(*p) = 0;
}
All this stuff is not obvious. User input is hard. But you will find that it doesn’t have to be impossibly difficult genius-level stuff. It should be entertaining!
Other ways you could handle input is to transform things into acceptable values. For example you can use tolower() to convert any majuscule letters to your histogram’s input set.
s? ba na NA!
a 3
b 1
n 2
But I digress again...
Hang in there!
This is an unfinished program I'm writing to learn C (only checks multiples of 2 currently...)
Ultimately, I want this to be an implementation of the Sieve of Eratosthenes (prime numbers)
The problem I'm having is that the output is non-deterministic: sometimes the output includes 11, other times it does not - This happens for a handful of numbers. I have experimented by changing a few things, such as actually initializing the array of booleans to false.
Any ideas why this might be happening?
#include <stdio.h>
#include <stdlib.h>
#include <stdbool.h>
int main(int argc, char *argv[]) {
int n = atoi(argv[1]);
int initialPrimeIterator = 2;
_Bool compositePrimeNumbers[n];
printf("Prime Numbers from 2 -> %d\n", n);
for (int i = initialPrimeIterator; i < n; i += initialPrimeIterator) {
compositePrimeNumbers[i-1] = true;
}
printf("Done...\n");
printf("Printing prime numbers from 2-> %d\n", n);
for (int i = 2; i < n; i++) {
if (!compositePrimeNumbers[i]){
printf("%d\n", i + 1);
}
}
return 0;
}
edit: haha. Just realized I have an array named 'compositePrime...' Should just be 'compositeNumbers'
Since I understand you are aiming at completing the program when overcoming this hurdle, I will not post a completed program, but only point out issues in your current version:
As it has been noted, the array compositePrimeNumbers is uninitialized. Since it must be initialized with all values false which is represented by 0, the quickest way is this:
memset(compositePrimeNumbers, 0, sizeof(compositePrimeNumbers));
You should not mark the current initialPrimeIterator as a composite number, hence the for-loop should start with the next multiple. Also, n must be included:
for (int i = 2 * initialPrimeIterator; i <= n; i += initialPrimeIterator) {
(actually, this can be optimized by replacing 2 * initialPrimeIterator with initialPrimeIterator * initialPrimeIterator).
With these changes, I believe you are well on the way to complete the program.
In C, a local array is not initialized, probably for performance reasons.
One way to fix this is to loop over it to set each element to false.
Just wondering if these variations of for loops are more efficient and practical.
By messing with the c for loop syntax i can embedd statements that would go in the loop-body into the loop-head like so:
Example 1:
#include <stdio.h>
int main(int argc, char ** argv)
{
// Simple program that prints out the command line arguments passed in
if (argc > 1)
{
for(int i = 1; puts(argv[i++]), i < argc;);
// This does the same as this:
// for(int i = 1; i < argc; i++)
// {
// puts(argv[i]);
// }
}
return 0;
}
I understand how the commas work in the for loop it goes through each statement in order, evaluates them then disregards all but the last one which is why it is able to iterate using the "i < argc"condition. There is no need for the final segment to increment the i variable as i did that in the middle segment of the loop head (in the puts(argv[i++]) bit).
Is this more efficient or is just just cleaner to seperate it into the loop body rather than combine it all into one line?
Example 2:
int stringLength(const char * string)
{
// Function that counts characters up until null terminator character and returns the total
int counter = 0;
for(counter; string[counter] != '\0'; counter++);
return counter;
// Same as:
//int counter = 0;
// for(int i = 0; string[i] != '\0'; i++)
//{
// counter++;
//}
//return counter;
}
This one seems more efficient than the version with the loop body as no local variable for the for-loop is initialised. Is it conventional to do these sorts of loops with no bodies?
Step 1: Correctness
Make sure code is correct.
Consider OP's code below. Does it attempt to print argv[argc] which would be bad?
if (argc > 1) {
for(int i = 1; puts(argv[i++]), i < argc;);
I initially thought it did. So did another user. Yet it OK.
… and this is exactly why code is weak.
Code not only should be correct, better code looks correct too. Using an anti-pattern as suggested by OP is rarely1 as good thing.
Step 2: Since code variations have the same big O, focus on understandably.
Sculpt your code – remove what is not needed.
for (int i = 1; i < argc; i++) {
puts(argv[i]);
}
What OP is doing is a trivial optimization concern.
Is premature optimization really the root of all evil?
Is it conventional to do these sorts of loops with no bodies?
Not really.
The key to the style of coding is to follow your group's style guide. Great software is often a team effort. If your group's likes to minimize bodies, go ahead. I have seen the opposite more common, explicit { some_code } bodies.
Note: int stringLength(const char * string) fails for strings longer than INT_MAX. Better to use size_t as the return type – thus an example of step 1 faltering.
1 All coding style rules, except this rule, have exceptions.
Currently learning C - and I have no clue where I'm going wrong in this code:
#include <stdio.h>
int main()
{
char alphabet[20];
int i;
for (int i = 0; i > 20; i++)
{
printf("Enter in a letter:\n");
scanf("%s", alphabet[i]);
if (alphabet[i] == alphabet[i+1])
{
printf("Duplicate Letters");
};
return 0;
}
}
The program that I am asked to make for class — I'm required to create a 1D array, add validation for alphabetical letters and duplicate letters, as well as creating a function for sorting the letters and specifying the number of times each letter was put in.
As much as I've been able to attempt coding is:
Create a 1D array to read 20 alphabetical letters
Add validation for duplicate letters and printf 'Duplicate Letters'
but every time I try, the program terminates at 'Enter in a letter:' or it won't execute.
Where did I go wrong?
For background: I work mainly on Windows 7 because that's what the school has — using MinGW as my compiler — but for working at home I use MacOS using Terminal as the compiler.
for (int i = 0; i > 20; i++)
You're telling the computer here to initialize i to 0, and then, while i is greater than 20, do the loop. However, since i starts at 0, it will never be greater than 20.
for (int i = 0; i < 20; i++)
And, yes, as comments have pointed out, your use of scanf is incorrect. Lacking a better C reference for it, check out http://www.cplusplus.com/reference/cstdio/scanf/ for descriptions of its arguments.
This is the first part of the program and I have a few questions on how parts of it work exactly. Keep in mind this is the first C program I have written. scanf("%d",&numberOfTimes); Why do I need the & and what does it do?
char input[][200]; Is this basically an array of strings or is it something completely different?
#include <stdio.h>
#include <string.h>
char outputs[100];
char input[][200];
int numberOfTimes;
void io(void){
scanf("%d", &numberOfTimes);
for(int i = 0; i < numberOfTimes; i++){
scanf("%s",input[i]);
}
}
This next part of the code is my attempt at actually solving the problem however I suspect that I screwed up the use of a function but I don't know which one or I used something improperly in order to get this result. (I provided example i/o of me code at the bottom).
void stringManipulation(char string[200]){
int strLength = strlen(string);
int number = strLength/2;
for(int i = 0; i <= number; i=i+2){
strcat(outputs,&string[i]);
}
}
int main(void) {
io();
for(int i = 0; i < numberOfTimes; i++) {
stringManipulation(input[i]);
printf("%s\n",outputs);
memset(&outputs[0], 0, sizeof(outputs));
}
return 0;
}
Did I use memset properly? Again I don't understand the use of the &.
Example input:
4
your
progress
is
noticeable
Expected output:
y
po
i
ntc
Output I am getting:
yourur
progressogressress
is
noticeableticeableceable
Thank you for your help.
The & before a variable means that you are referring to the address of the variable, and not the variable value itself. If you don't know about what the address of a variable is : http://www.cquestions.com/2010/02/address-of-variable-in-c.html
char input[][200] is an array of char array (a char array is vulgarized as a string but it ISN'T the TYPE).
Your problem is about your strcat use, you're adding characters that are between string[i] (included) and string[strLength], not only the string[i] character.
Your problem is in strcat:
Your code passes the address and hence you are getting the entire string from that character onward.
strcat(outputs,&string[i]);
Now, change the above code as below:
strcat(output,string[i]);
You'll get the desired output. The problem with your initial code was that you were passing the address and not individual character.
Also, change the for loop in such a way that "<"number and not "<="number.
Let me know if you have any more doubts.