sorry if the title is non-specific but I wasn't too sure of how I was supposed to title this post. I'm creating a function which encrypts a given string. Here it is:
int ind(char c, char * t){
int i = 0;
while (i != strlen(t)){
if (t[i] == c) return i;
}
return -1;
}
void translate2 (char * c, char * ret){
char used[1000], d;
int i = 18, size = 0;
for (i=0; i < strlen(c);i++){
printf("\nChar: %c",c[i]);
printf("arguments going in are char %c and str %s", c[i], used);
if (ind(c[i], used) == -1){
used[size] = c[i];
ret[size] = c[i];
size++;
}
else{
if (ind(c[i], used) == 0){
d = used[size];
}
else {d = used[ind(c[i], used)-1];}
/*printf("Thus, our d shall be %c\n\n", d);*/
ret[size] = d;
size++;
}
printf("\nSeq: %s", used);
printf("\nOutput: %s\n", ret);
}
}
Sorry if the code is messy, I'm pretty new to this. I suppose what the code actually does isn't too important. My issue here is that, the code works as intended for the first run through the loop. Once it finishes that, the program stops. I can't figure out why this happens, and I'm not handy enough with debuggers to use them. Can anyone point me towards the right direction? Any help is appreciated. Thanks!
while (i != strlen(t)){
if (t[i] == c) return i;
}
āiā is not incrementing in the loop. You are indefinitely checking the first element
Related
I have been working on a hangman game for my class which is due today and just now it decided to no longer provide any output from my code. If someone could please give it a look so I can go back to possibly submitting this assignment, I would be very appreciative. I dont know what changed specifically.
char **readWordList(char *, int *);
int main(int argc, char *argv[]) {
char **wordList;
char inputFile[100];
int count = 0;
int i;
if (argc != 2) {
printf("You need to provide the word list file name.\n ");
printf("Usage: $0 filename\n");
return -1;
}
wordList = readWordList(argv[1], &count); //function (target input[s], y placeholder var)
if (wordList == NULL) {
printf("Read word failed\n");
exit(1);
}
printf("fortnite");
int a = 0; //placeholder variables
int b = 0;
int c = 0;
int v = 0;
int g = 0;
int hit = 0;
srand(time(NULL)); //random variable for word selection
int r = rand() % 3;
int chances = 10;
char *word = wordList[r]; //address word from line.txt
char guess;
char misses[10];
int lettercount = 0;
//make blank variable by reading random accessed word
for (size_t a = 0; word[a] != 0; a++) {
lettercount++;
}
char space[lettercount];
// write underscores in place of spaces in temporary array
for (size_t c = 0; word[c] != '\0'; c++) {
space[c] = 95;
}
char blank[lettercount * 2]; //equal to array size empty array
// borrowing my spacename function, but seems to make artifacts in blank input now
int t = 0;
int k = 0;
while (space[t] != '\0') {
k = 2 * t;
if (k > lettercount * 2 - 2) {
blank[k] = space[t];
break;
}
blank[k] = space[t];
blank[k + 1] = ' ';
}
while (chances > 0) {
printf("Chances:%d\n", chances);
printf("Misses:%d\n", misses);
printf("Word:%s\n", blank);
printf("Guess[Q]:");
scanf("%c\n", &guess);
while (word[b] != '\0') {
if (guess = 'Q') {
exit(0);
}
if (guess = word[b]) {
v = b * 2;
blank[v] = guess;
b++;
hit = 1;
}
b++;
}
if (hit != 1) {
misses[g] = guess;
}
if (hit = 1) {
hit = 0;
}
chances--;
g++;
}
}
There are multiple problems in the code, including some serious ones:
the #include lines are missing.
the readWordList function is missing.
if (guess = 'Q') sets guess to 'Q' and evaluates to true. You should write if (guess == 'Q')
if (guess = word[b])... same problem.
printf("Misses:%d\n", misses); should be printf("Misses:%s\n", misses); and misses should be initialized as the empty string.
printf("Word:%s\n", blank); has undefined behavior as blank is not null terminated.
while (space[t] != '\0') may iterate too far as space does not have a null terminator since it's length is lettercount and all elements have been set to 95 ('_' in ASCII). Yet since you never increment t, you actually have an infinite loop. Use a simple for loop instead: for (t = 0; i < lettercount; t++)
scanf("%c\n", &guess); reads a character and consumes any subsequent white space, so the user will have to type another non space character and a newline for scanf() to return. You should instead use scanf(" %c", &guess);
while (word[b] != '\0') will iterate beyond the end of the array after the first guess because you do not reset b to 0 before this loop. Furthermore, b is incremented twice in case of a hit. You should use for loops to avoid such silly mistakes.
if (hit = 1) { hit = 0; }... the test is incorrect (it should use ==) and you could just write hit = 0; or better set hit to 0 before the inner loop.
inputFile is unused.
You should compile with gcc -Wall -Wextra -Werror to avoid such silly bugs that can waste precious time.
i fixed it, i lost a variable which provided the chance that a while loop would end for the spacing array function
sorry for being annoying
I have a function that is reading from a file for package names and their directories. I have setup a variable to catch one item before the other (they are separated by a comma). When I append to my string it seems to add it just fine. However, when I go to realloc the string (compress it down to its actual size) it owns retains half of the characters.
When I used to a for loop to test it, there are empty characters being projected between each character. So I have a test work "duck" when I print it as a string it will write "duck" however if it iterate over it, it will go "d" " " "u" " " "c"
while(1)
{
char c = fgetc(db);
actual_file_size++;
if(c == EOF)
{
//pkg_install_dir = realloc(pkg_install_dir, (sizeof(pkg_install_dir) + 2));
//printf("The install dir is: %s\n", pkg_install_dir);
break;
}
if(is_pkg_name) {
printf("Chracter being added to pkg_name: %c\n", c);
strcat(pkg_name, &c);
} else {
strcat(pkg_install_dir, &c);
}
if(c == ',')
{
printf("Actual file size int is: %d\n", actual_file_size);
printf("Package name before realloc: %s\n", pkg_name);
for(int i = 0; i < 5; i++)
{
printf("%c\n", pkg_name[i]);
}
pkg_name = realloc(pkg_name, actual_file_size);
is_pkg_name = 0;
actual_file_size = 0;
printf("The string is:%s\n", pkg_name);
}
Terminal output:
Well thank you to kaylum and this article: How to get char* with unknown length in C?
I was able to solve my issue by removing the function and using realloc inside the while loop please see below and I hope it helps someone else out in the future!
The pkg_name & pkg_install_dir are still using a char buffer because I realized using the realloc way from the article the two points of memory were rolling over each other (good amount of time to figure that out and I will never get back!).
Learning C is fun!
int read_db()
{
FILE *db;
db = fopen("/tmp/devpkg/db/db", "r");
char *pkg_name = malloc(MAX_CHAR_BUFF);
char *pkg_install_dir = malloc(MAX_CHAR_BUFF);
int is_pkg_name = 1;
int actual_file_size = 0;
while(1)
{
char c = fgetc(db);
if(c == EOF)
{
pkg_install_dir = realloc(pkg_install_dir, (actual_file_size - 1));
pkg_install_dir[actual_file_size - 1] = '\0';
break; // while loop will finish here
}
if(is_pkg_name) {
pkg_name[actual_file_size] = c;
} else {
pkg_install_dir[actual_file_size] = c;
}
actual_file_size++;
if(c == ',')
{
pkg_name = realloc(pkg_name, (actual_file_size - 1));
pkg_name[actual_file_size - 1] = '\0';
is_pkg_name = 0;
actual_file_size = 0;
printf("The string is:%s\n", pkg_name);
}
}
fclose(db);
free(pkg_name);
free(pkg_install_dir);
return 0;
}
im new to c i try to make a little and very simple game of hangedman and i dont know why doesent work get error in gcc "expected declaration or statement at the end of input"
im new to c and ii try very hard to learn it.
im missing something? my function is not right? some advice to learn alghorytmically thinking?
thanx in advance for the hel you gonna give me
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//function to find letter in string
int findletter(char y)
{
char c;
int i;
char secret[] = "outcast";
i = 0;
scanf("%c", &c);
while (c != secret[i] && i < strlen(secret))
i++;
if(c == secret[i])
return (1);
else
return (0);
}
//confirmation letter
int guessed(char a)
{
int z;
char guess [6] = {0};
z = 0;
while(findletter(guess[z]) != 1 && findletter(guess[z]) < 6)
{
z++;
if(findletter(guess[z]) == 1)
return 1;
else
return 0;
//word guessed
int tryguess(char v)
{
int x;
x = 0;
while(findletter(guess[x]) == 0)
{
x++;
if(findletter(guess[x] == 1))
return 1;
else
return 0;
}
}
int main()
{
char secret[] = "outcast";
char letter;
int lives;
char guess [6] = {0};
int i;
lives = 10;
i = 0;
printf("welcome to the hanged man\n");
while(i < 6)
{
if((findletter(secret[i] == 1)))
printf("%c", secret[i]);
else
printf("*\n");
i++;
}
return 0;
}
Correction to your code...
int guessed(char a)
{
int z;
char guess [6] = {0};
z = 0;
while(findletter(guess[z]) != 1 && findletter(guess[z]) < 6)
{
z++;
if(findletter(guess[z]) == 1)
return 1;
else
return 0;
} // you forgot closing while loop here
} // function closing parenthesis
//word guessed
Advice:
I don't know how much you had practice and how much you had learned yet..but on observing your mistake above I would like to suggest that whenever you create function or loop always write its prototype first, let's say you want to create a function for adding two numbers..
STEP 1: write prototype
int add(int x, int y)
{
//then do your stuff here...
return 0;
}
This will eliminate you chances of making error of parentheses...
There are a lot of issues with this program, from both a syntax standpoint and a logical one.
General issues include:
Function guessed and its while loop are not closed (missing }).
There is a lot of unused code (functions and variables).
The line if((findletter(secret[i] == 1))) compares the character value of secret[i] with 1 and passes that result to findletter. This doesn't matter though since you don't use this argument, and take user input within the function.
You have hardcoded strings and lengths, which makes your program less dynamic and harder to change in the future.
Using while loops as guards (in the unused functions tryguess and guessed), that are always exited on the first iteration.
findletter simply checks if secret contains the character c, returning on the first occurrence.
It could be more clearly expressed as:
int findletter(char unused) {
char secret[] = "secret",
c;
scanf(" %c", &c);
for (size_t i = 0; i < strlen(secret); i++)
if (secret[i] == c)
return 1;
return 0;
}
With that said, findletter would be better if you passed both the secret and c as arguments, so that you can use it more generically, and decouple user input from the function itself.
(Or you could simply use the standard library function strchr which achieves a very similar goal.)
The pattern of
if (a == b)
return 1;
else
return 0;
can simply be reduced to
return a == b;
Aside from the issues above, the structure of your program doesn't make much sense. If our program worked, you'd basically be asking the player to guess a word of unknown length, one character of the word at a time. They can also simply guess any letter to display the current one. One could 'solve' the entire word "secret" by simply inputting 's' repeatedly.
The structure of a very basic hangman program is:
Select the word to be guessed. Select number of lives.
Create a blanked version of word to track progress. Display this blanked version, which indicates the length to the player.
Ask the player to guess a letter. Skip those already guessed.
Update all positions in the blanked version where letter appears in the word.
Decrement lives on miss, end game if out of lives.
Check if the amount of characters changed in the blank version matches the length of word.
Win condition, or return to step 3.
There are many different ways to achieve this, and there are likely thousands of examples online.
Here is a rough program that is about as simple as it gets. This showcases the usual structure and flow of a game of hangman.
#include <stdio.h>
#include <string.h>
size_t update_all(char *to, const char *from, size_t len, char g) {
size_t changed = 0;
for (size_t i = 0; i < len; i++)
if (from[i] == g) {
to[i] = g;
changed++;
}
return changed;
}
void play_hangman(const char *word, unsigned lives) {
size_t word_length = strlen(word),
blanked_length = 0;
char blanked[word_length + 1],
guess = '\0';
for (size_t i = 0; i < word_length; i++)
blanked[i] = '*';
blanked[word_length] = '\0';
while (lives) {
printf("The word: [%s]\n"
"(Lives = %u) Enter a guess: ",
blanked,
lives);
scanf(" %c", &guess);
if (strchr(blanked, guess)) {
printf("[%c]: Already guessed!\n", guess);
continue;
}
size_t found = update_all(blanked, word, word_length, guess);
blanked_length += found;
if (!found) {
printf("[%c]: NOT FOUND!\n", guess);
lives--;
} else
printf("[%c]: FOUND!\n", guess);
if (!lives)
puts("Out of lives! You lose!");
else if (blanked_length == word_length) {
printf("You win! Word is [%s].\n", word);
return;
}
}
}
int main(void) {
play_hangman("secret", 10);
}
Note that this program is far from perfect, as it doesn't fully keep track of guessed letters, so the player can guess the same wrong letter multiple times, and lose a life every time. To fix this, we would need even more state, collecting each guess the player makes, and use that data instead of the naive if (strchr(blanked, guess)).
It also makes use of the '*' character as a sentinel value, which would cause confusion if our word contained '*'. To fix this, we could use an array of boolean values indicating the correctly guessed letters in the word thus far, and use this to print our word character-by-character. Or we could restrict character inputs with functions like isalpha.
This program simply serves as an example that for a proper approximation of the typical "Hangman" you need to handle more game state than you have.
(Error handling omitted for brevity throughout this answer.)
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int Extract(char input[], double output[])
{
int i, j, len;
i=0;
j=0;
len=0;
char s[50];
while(i<strlen(input)-1)
{
if(input[i]==' ') i++;
j=0;
s[0]='\0';
while(input[i]!=',')
{
if(input[i]==' ') i++;
s[j]=input[i];
i++;
j++;
}
s[j]='\0';
i++;
printf("%s - ", s);
output[len]=(double)atof(s);
printf("Element %d: %lf\n", len, output[len]);
len++;
}
printf("%d", len);
return len;
}
int main(){
char s[120]="0.1,0.35,0.05,0.1,0.15,0.05,0.2.";
double v[1000];
int len = Extract(s, v);
int i;
for(i=0; i<len; i++)
{
printf("%d: %lf\n", i, v[i]);
}
return 1;
}
I try to run this code but even if it compiles correctly I have stack errors, can anybody help me?
Note that the string is composed by some decimal numbers separated by commas and the string ends with a .
UPDATE: maybe there was some dirty in the folder but now I have an output:
Length: 32
0.1 - Element 0: 0.000000
0.35 - Element 1: 0.000000
0.05 - Element 2: 0.000000
0.1 - Element 3: 0.000000
0.15 - Element 4: 0.000000
0.05 - Element 5: 0.000000
Segmentation fault (core dumped)
Since I already made the thread can I still take advantage of your help for converting the string into double, since atof is converting into float and probably that's the reason why it prints all 0.0000?
I think I found the problem:
Your loop only check if the character is not ','. At the end of your input, you do not have a ',' character, instead you have a '.' which will lead to your loop going on forever, resulting in the segfault. You can fix it by changing the last character of your input into a ','.
You do not have the right format for your float output. If you need to only print two significant figures, then change your %lf into %.2lf.
By the way, you check for spaces in your input, but it doesn't look like your input has any spaces. Maybe take those checks out?
It all depends on how regulated your input is. If you can, process your input before you feed it into your function.
Let us know if that helps!
Here I am presenting 3 codes, where the first addresses the segfault issue(s); the second, a verbose commentary on the Extract function as presented; third, an example of the Extract function written in one of many possible improved forms.
The main take-aways should be to always guard against buffer (array) overruns in code and make friends with the debugger.
The peppering of printf's in the code suggests a debugger is not being used. Coding anything beyond the trivial (hello, world?) begs debugger knowledge. Understanding tools such as a debugger is as important as knowing the language.
I Hope this serves as a guide and maybe even some inspiration. Good luck with your coding adventures.
Here's the original code with minimum changes to fix the segfault (array overrun)
int Extract(char input[], double output[])
{
int i, j, len;
i = 0;
j = 0;
len = 0;
char s[50];
while (i<strlen(input) - 1)
{
if (input[i] == ' ') i++;
j = 0;
s[0] = '\0';
/* Primary bug fix; guard against input array overrun *and* check for separator */
while (input[i] && input[i] != ',')
{
if (input[i] == ' ') i++;
s[j] = input[i];
i++;
j++;
}
s[j] = '\0';
/* bug fix; guard against input array overrun when incrementing */
if (input[i]) {
i++;
}
printf("%s - ", s);
output[len] = (double)atof(s);
printf("Element %d: %lf\n", len, output[len]);
len++;
}
printf("%d", len);
return len;
}
Here's a critique of the original code.
int Extract(char input[], double output[])
{
/* Tedious variable declaration and initialization */
int i, j, len;
i = 0;
j = 0;
len = 0;
/* why not 70? or 420? */
char s[50];
/* This is an exceedingly expensive way to determine end of string. */
while (i<strlen(input) - 1)
{
/* Why test for space? There are no spaces in sample input.
This increment risks overrunning the input array (segfault)
*/
if (input[i] == ' ') i++;
j = 0;
s[0] = '\0';
/* no guard against input array overrun */
while (input[i] != ',')
{
/* Why test for space? There are no spaces in sample input.
This increment risks overrunning the input array (segfault)
*/
if (input[i] == ' ') i++;
s[j] = input[i];
i++;
j++;
}
s[j] = '\0';
/* Bug - no guard against input array overrun when incrementing i */
i++;
/* these print statements suggest someone is NOT using a debugger - major fail if so. */
printf("%s - ", s);
output[len] = (double)atof(s);
printf("Element %d: %lf\n", len, output[len]);
len++;
}
/* again, this is easily seen in the debugger. Use the debugger. */
printf("%d", len);
return len;
}
Lastly, an alternative Extract with some (cherry picked) conventions.
int Extract(double* output, const int output_max, const char* input, const char separator)
{
/* declare variables in the scope they're needed and ALWAYS give variables meaningful names */
int input_index = 0, output_count = 0;
/* Detect end of string and guard against overrunning output buffer */
while (input[input_index] && output_count < output_max)
{
const int BUFFER_MAX = 50;
/* let the compiler init buffer to 0 */
char buffer[BUFFER_MAX] = { 0 };
int buffer_index = 0;
/* accumulate values into buffer until separator or end of string encountered */
while (input[input_index] && input[input_index] != separator)
{
buffer[buffer_index++] = input[input_index++];
if (buffer_index == BUFFER_MAX) {
/* Overrun, cannot process input; exit with error code. */
return -1;
}
}
/* only convert buffer if it had accumulated values */
if (buffer_index) {
/* note atof will discard, say, a trailing period */
output[output_count++] = atof(buffer);
}
/* Guard against input_index increment causing an array overrun (possible segfault) */
if (input[input_index]) {
input_index++;
}
}
return output_count;
}
int main() {
const int OUTPUT_MAX = 1000;
const char separator = ',';
const char* input = "0.1 ,0.35,0.05,0.1,0.15,0.05,0.2.";
double output[OUTPUT_MAX];
const int num_elems = Extract(output, OUTPUT_MAX, input, separator);
/* print results to stdout */
if (num_elems == -1) {
fprintf(stdout, "\nElement too long to process error\n");
}
else {
fprintf(stdout, "\nTotal number of elements: %d\n\n", num_elems);
for (int i = 0; i < num_elems; i++) {
fprintf(stdout, "Element %d: %lf\n", i, output[i]);
}
}
return num_elems;
}
Good luck with your coding adventures.
getLine is a function that gets a line, I'm trying to combine lines together outside the getLine function. When ever I try doing this in a loop it messes up the output. I bet it has to do with the pointers, but I have spend many hours trying to figure it out.
int num;
int matrix[370];
i=1;
j=0;
while(*(point=getLine(infile)) != -2){
n[j]=*point;
if(n[0] != n[j]){
printf("matrix dim error 1");
break;
}
while (i<=n[j]){
matrix[i+(3*j)] = *(point+(i+(3*j)));
i++;
printf("%d", matrix[i+(3*j)]);
}
printf("%d %d %d\n", matrix[1],matrix[2],matrix[3]);
j++;
}
fclose( infile );
}
int *getLine(FILE *infile){
int l=0;
int line[7];
int i=1;
int *point;
while ((l=getNum(infile)) != -1){
if(l==EOF){
line[0]=EOF;
point = &line[0];
return(point);
}
line[i]=l;
i++;
}
if(i==1){
line[0]=-2;
point = &line[0];
return(point);
}
line[0]=(i-1); //stores the length of the line in first space
printf("%d %d %d\n",line[1],line[2],line[3]);
point = &line[0];
printf("%d\n",*point);
return(point);
}
int getNum(FILE *infile) {
int c=0;
int value=0;
while ((c=fgetc(infile)) != '\n') {
if(c==EOF){
return(EOF);
}
if((c==32)||(c==13)){
if(value != 0){ //Making sure a number has been gotten
//printf("%d\n\n", value);
return(value);
}
//otherwise keep getting characters
}
else if ((c<=47)||(c>=58)){
printf("incorrect number input %d\n", c);
exit(1);
}
else {
value = (10*value) + (c - '0');
}
}
return(-1);//flags that the end of line has been hit
}
There is one problem:
int *getLine(FILE *infile){
int line[7];
int *point;
point = &line[0];
return(point);
}
You return a pointer to a local variable. It becomes invalid when you return from the function. You could allocate it instead on the heap, or let the caller provide it as an argument.
Instead of
while (i<=n[j]){
didn't you mean
while (i<=n[j][0]){
More Edit: That's actually ok, i overlook the * in the assignment.
Edit: Some more things:
there is no check that the range of int is not exceeded in getNum
there is no check in getLine that more than 7 values are read (which would blow int line[7]
the matrix calculation in my opinion assumes that there are 3 values read, getLine can deliver up to 7
matrix[i+(3*j)] = *(point+(i+(3*j))); ?? point is only 7 int big!!! so for the second value it will read beyond defined data. Shouldn't it read matrix[i+(3*j)] = point[i];
hth
Mario
BTW: I strongly recommend:
resort to std-lib functions
better naming (i and j in the same source are strongly discouraged)