I need to make an C application for school and im stuck at one bit. I filled my struct with word from a file wich works fine, except for the time it just prints a random integer i guess?
My code:
char buffer[20];
int i;
for(i = 0; i < 10; i++) {
fgets(buffer,20,fp);
apcWordList[i].pcWord = strdup(buffer);
apcWordList[i].cMaxScore = 0;
apcWordList[i].tTime = time(NULL);
}
fclose(fp);
Now what i wanted to do was this(sSecretWord is the word the person guessed and score the points he got for guessing the word):
for(i = 0; i < 10; i++) {
fgets(buffer,20,fp);
if(apcWordList[i].pcWord == sSecretWord && score > apcWordList[i].cMaxScore) {
apcWordList[i].cMaxScore = score;
apcWordList[i].tTime = time(NULL);
}
}
but it crashes and I am really confused how to compare the variables and change them when needed. I hope I have explained it well enough and my English could be read well.
Assuming pcWord is a char *, you cannot compare that pointer using ==, most of the time.
There is no string data type in C, a string is never a single value.
You must use strcmp():
if(strcmp(apcWordList[i].pcWord, sSecretWorD) == 0 &&
score > apcWordList[i].cMaxScore)
The rest of your code makes little sense, I'm afraid. The loop has a typo, and there's no connection between the fgets() and the if. I don't think the fgets() should be in the second part of the code, at all.
The following expression in your if condition
apcWordList[i].pcWord == sSecretWord
compares the memory addresses they evaluate to and not the values stored at those memory locations which is probably what you want. You should use strcmp instead to compare the strings pointed to by above two variables.
strcmp(apcWordList[i].pcWord, sSecretWorD) == 0
Related
I have a quiz game in C where I am using a struct to save when a user enters a wrong answer and the corresponding correct answer to that question. First I used malloc to allocated memory for a single struct.
Struct:
typedef struct
{
char* wrongAnswers;
char* corrections;
} Corrections;
Malloc:
Corrections* corrections = (Corrections*)malloc(sizeof(Corrections));
Later on in my program, I have functionality where a wrong answer increments an 'incorrectAnswers' variable, which is used to reallocate the memory to allow for the new wrong answer to be stored, along with its corresponding correct answer.
Code:
// Extract characters from file and store in character c
for (c = getc(fPointerOpen); c != EOF; c = getc(fPointerOpen)) {
if (c == '\n') // Increment count if this character is newline
numberOfLines++;
}
for (int i = 0; i < numberOfLines; i++) {
int lengthOfQuestion = 150;
if (v == 0) {
printf("Correct\n");
score++;
}
else {
printf("Incorrect\n");
incorrectAnswers++;
corrections = (Corrections*)realloc(corrections, incorrectAnswers * sizeof(Corrections));
corrections[i].wrongAnswers = malloc(sizeof(char) * lengthofanswer);
corrections[i].wrongAnswers = lines[i].userAnswers;
corrections[i].corrections = malloc(sizeof(char) * lengthofanswer);
corrections[i].corrections = lines[i].answers;
}
printf("Your score is %d/%d\n", score, (i + 1));
}
I am receiving a bug depending on the order in which right and wrong answers are input. I have tried using free() in different parts of the program and I have noticed that the bug will always appear when I enter a wrong answer as the last entry in my program/if I enter a right then wrong answer. Why is this the case? My understanding is I am implementing realloc incorrectly.
you should use strcpy to copy string, do not use = to assign string in c.
strcpy(corrections[i].wrongAnswers,lines[i].userAnswers);
strcpy(corrections[i].corrections,lines[i].answers);
Each time you use malloc or realloc, you should check the return value of these functions.
I just started learning C language and I need some help with a program. Here is the code.
Questions:
What is this? customerData[NUM_FIELDS][FIELD_LENGTH];
Is it a char 2D array?
How do you input data into the array? fgetC, putchar, getchar ?
#include <stdio.h> #include <string.h> #include <stdlib.h>
#define INPUT_LENGTH 128
#define FIELD_LENGTH 30
#define NUM_FIELDS 9
int main()
{
FILE *data=NULL;
char input[INPUT_LENGTH];
char customerData[NUM_FIELDS][FIELD_LENGTH];
int element=0;
char *next;
char ch;
data= fopen("data.txt","r");
if(data!=NULL)
{
//token=strtok(input,"|");
/*while loop will go through line by line and stored it in an input array*/
while(fgets(input,INPUT_LENGTH,data)!= NULL)
{
next=strtok(input,"|");
while(next!=NULL)
{
//ch=getchar()
//>probably a get char for ch
strcpy(next,customerData[element][strlen(next)]);
/*need to put the values into customer data one by one*/
printf("%s\n",next);
//element+=1;
next=strtok(NULL,"|");
}
//element=0;
}
printf("program is done\n");
}
fclose(data);
return 0;
}
In general, "help me with my code" questions are off-topic on Stack Overflow. In order to keep the question on-topic, I'm going to focus only on the question of how to access 2D char arrays.
Yes, this is a 2D char array. Or, put another way, it's an array with NUM_FIELDS elements, where each element of the array is a char array with FIELD_LENGTH elements.
There are loads of ways to insert data into a 2D char array, but there are probably two I've encountered most often. Which one you choose to use will depend on how you want to think of this array.
Option 1: A 2D array of single chars
The first way to think about this variable is simply as a 2D array of chars - a grid of elements that you can access. Here, you can simply input values using the normal assignment operator. You'll want to make sure that your indexes are in range, or you'll start accessing invalid memory.
//Set a known element that's definitely in range
customerData[1][2] = 'A';
//Loop through all the elements
for(int ii = 0; ii < NUM_FIELDS; ii++)
{
for (int jj = 0; jj < FIELD_LENGTH; jj++)
{
customerData[i][j] = 'B';
}
}
//Set an element from variables
char nextInput = getNextCharFromInput();
if(x < NUM_FIELD && y < FIELD_LENGTH)
{
customerData[x][y] = nextInput;
}
//Bad. This could corrupt memory
customerData[100][60] = 'X';
//Risky without check. How do you know x and y are in range?
cusomterData[x][y] = 'X';
You could certainly write your code by assigning these elements on character at a time. However, the broader context of your program heavily implies to me that the next option is better.
Option 2: A 1D array of fixed-length strings
In C, a "string" is simply an array of chars. So another way to look at this variable (and the one that makes the most sense for this program) is to treat it as a 1D array of length NUM_FIELDS, where each element is a string of length FIELD_LENGTH.
Looking at this this way, you can start using the C string functions to input data into the array, rather than needing to deal character by character. As before, you still need to be careful of lengths so that you don't go off the end of the strings.
Also be aware that all array decay into pointers, so char* is also a string (just of unknown length).
//Set a specific field to a known string, which is short enough to fit
strcpy(customerData[2], "date");
//Loop through all fields and wipe their data
for(int ii = 0; ii < NUM_FIELDS; ii++)
{
memset(customerData[ii], 0, FIELD_LENGTH);
}
//Set field based on variables
if(x < NUM_FIELDS)
{
//Will truncate next if it is too long
strncpy(customerData[x], next, FIELD_LENGTH);
//Will not input anything if field is too long
if(strlen(next) < FIELD_LENGTH)
{
strcpy(customerData[x], next);
}
}
//Bad. Could corrupt memory
strcpy(customerData[100], "date");
strcpy(customerData[1], "this string is definitely much longer than FIELD_LENGTH");
//Risky. Without a check, how do you know either variable in in range?
strcpy(customerData[x], next);
getchar and fgetC both deal with reading characters, from stdout and a file respectively, so can't be used to put data into a variable. putchar does deal with put character into things, but only stdout, so can't be used here.
So I've got this here:
#include <stdio.h>
char halloString[] = "Ha::ll::o";
char perfumeString[] = "47::11";
char veryLongString[] = "47::11::GHesd::dghsr::bfdr:hfgd46dG";
char *extract (char *input) {somethinghappenshere}
where extract needs to get all characters after the last double ":" of given input:
"o" for halloString
"11" for perfumeString
"bfdr:hfgd46dG" for veryLongString
In short, my issue is finding the length of the string *input points to. As far as I understand it that won't be happening without making something really sketchy.
Am I correct in assuming the length cannot be acquired in a good way?
And if so would it be a horrible idea to do, for example:
char stringToProcessTemp1[50];
char stringToProcessTemp2[50];
char stringToProcess[50];
for (int i = 0; i < 50; i++) {
stringToProcessTemp1[i] = input + i;
}
for (int i = 0; i < 50; i++) {
stringToProcessTemp2[i] = input + i;
}
for (int i = 0; i < 50; i++) {
if (stringToProcessTemp1[i] == stringToProcessTemp2[i]) {
stringToProcessTemp[i] = stringToProcessTemp1[i];
}
}
Later checking where the first empty index is and saving everything before it as the used String as from my very limited experience in C when you go outside of an array you tend to get different outputs every time therefore making the chance both Temp strings match for an extra element directly after the last one of the original string what I'd consider low enough.
It's honestly the only idea I've got right now.
Finding the length of a string is no problem. strlen will do that for you. However, you don't even need that.
You can use the strstr function to find a substring within a string, in this case "::". When you find one, keep looking right after the last one you found until you don't find it anymore, then the last one you found is the one you want. Then you want the substring that starts right after it.
char *extract(char *input)
{
char *last = NULL, *start = input, *curr;
while ((curr == strstr(start, "::")) != NULL) {
last = curr; // keep track of the last "::" found
start = last + 1; // move the starting string to right after the last "::"
// move up 1 instead of 2 in case of ":::"
}
if (last != NULL) {
last +=2; // We found one; move just past the "::"
}
return last;
}
C strings, which are really only an array of characters, are by definition terminated by '\0'. So, for a well formed C string you can always get the length of the string by using strlen().
If, however, your string is not null-terminated, there is no way to determine it's length, and it is not a C string by definition any more, but just an array of characters.
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.
I'm actually writing about the same program as before, but I feel like I've made significant progress since the last time. I have a new question however; I have a function designed to store the frequencies of letters contained within the message inside an array so I can do some comparison checks later. When I ran a test segment through the function by outputting all of my array entries to see what their values are, it seems to be storing some absurd numbers. Here's the function of issue:
void calcFreq ( float found[] )
{
char infname[15], alpha[27];
char ch;
float count = 0;
FILE *fin;
int i = 0;
while (i < 26) {
alpha[i] = 'A' + i++;
}
printf("Please input the name of the file you wish to scan:\n");
scanf("%s", infname);
fin = fopen ( infname, "r");
while ( !feof(fin) ) {
fscanf(fin, "%c", &ch);
if ( isalpha(ch) ) {
count += 1;
i = 0;
if ( islower(ch) ) { ch = toupper(ch); }
while ( i < 26 ) {
if ( ch == alpha[i] ) {
found[i]++;
i = 30;
}
i++;
}
}
}
fclose(fin);
i = 0;
while ( i < 26 ) {
found[i] = found[i] / count;
printf("%f\n", found[i]);
i++;
}
}
At like... found[5], I get this hugely absurd number stored in there. Is there anything you can see that I'm just overlooking? Also, some array values are 0 and I'm pretty certain that every character of the alphabet is being used at least once in the text files I'm using.
I feel like a moron - this program should be easy, but I keep overlooking simple mistakes that cost me a lot of time >.> Thank you so much for your help.
EDIT So... I set the entries to 0 of the frequency array and it seems to turn out okay - in a Linux environment. When I try to use an IDE from a Windows environment, the program does nothing and Windows crashes. What the heck?
Here are a few pointers besides the most important one of initializing found[], which was mentioned in other comments.
the alpha[] array complicates things, and you don't need it. See below for a modified file-read-loop that doesn't need the alpha[] array to count the letters in the file.
And strictly speaking, the expression you're using to initialize the alpha[] array:
alpha[i] = 'A' + i++;
has undefined behavior because you modify i as well as use it as an index in two different parts of the expression. The good news is that since you don't need alpha[] you can get rid of its initialization entirely.
The way you're checking for EOF is incorrect - it'll result in you acting on the last character in the file twice (since the fscanf() call that results in an EOF will not change the value of ch). feof() won't return true until after the read that occurs at the end of the file. Change your ch variable to an int type, and modify the loop that reads the file to something like:
// assumes that `ch` is declared as `int`
while ( (ch = fgetc(fin)) != EOF ) {
if ( isalpha(ch) ) {
count += 1;
ch = toupper(ch);
// the following line is technically non-portable,
// but works for ASCII targets.
// I assume this will work for you because the way you
// initialized the `alpha[]` array assumed that `A`..`Z`
// were consecutive.
int index = ch - 'A';
found[index] += 1;
}
}
alpha[i] = 'A' + i++;
This is undefined behavior in C. Anything can happen when you do this, including crashes. Read this link.
Generally I would advise you to replace your while loops with for loops, when the maximum number of iterations is already known. This makes the code easier to read and possibly faster as well.
Is there a reason you are using float for counter variables? That doesn't make sense.
'i = 30;' What is this supposed to mean? If your intention was to end the loop, use a break statement instead of some mysterious magic number. If your intention was something else, then your code isn't doing what you think it does.
You should include some error handling if the file was not found. fin = fopen(..) and then if(fin == NULL) handle errors. I would say this is the most likely cause of the crash.
Check the definition of found[] in the caller function. You're probably running out of bounds.