strcpy not working inside for loop? c programming - c

I am writing a program that loops through a text file with two columns. the first values are strings and the second are ints. I am trying to put them in arrays based on their column.
Data example:
stephen 170
shane 150
jake 180
Im trying to do this:
["stephen", "shane", "jake"]
[170,150,180]
For some reason the strcpy function is not working. I am not getting an error message but when I use strcpy and attempt to print the first value of the string array, nothing happens.
#include <stdio.h>
#include <string.h>
int main (void) {
FILE* dict;
char word[50];
int weight;
int weights[50000];
char *words[50000];
dict = fopen("dict.txt", "r");
for (int i = 0; i < 50000; i++) {
fscanf(dict, "%s %d", &word, &weight);
weights[i] = weight;
strcpy(word, words[i]);
}
printf("%s", words[0]);
printf("%d", weights[0]);
return 0;
}

First note that the parameters of strcpy are in the wrong order: the first is the destination and the second is the source, and I guess you want to copy the word string to word[i], so you need to swap the parameters order.
But this won't work either as word[i] points to garbage memory. You'll have to allocate some. You could use for example strdup instead:
words[i] = strdup(word);
Note that it allocates memory on the heap so don't forget to free it once you finished using it.

You have swapped destination and source in your call to strcpy.
Checking man or using a good IDE showing lib function prototypes should help you to avoid that kind of stupid errors for good.
Also, it's mere luck that the program isn't segfaulting as you are reading from words[i] which is an uninitialized array of pointers to chars, you should add a malloc of words[i] before copying to it.
A minimaly fixed (there are still other problems to fix) version of the program could look like below
#include<stdio.h>
#include <string.h>
#include <stdlib.h>
int main (void)
{
FILE* dict;
char word[50];
int weight;
int weights[50000];
char *words[50000];
dict = fopen("dict.txt", "r");
for (int i = 0; i < 50000; i++) {
fscanf(dict,"%s %d", &word, &weight);
weights[i] = weight;
words[i] = malloc(strlen(word)+1);
strcpy(words[i], word);
}
printf("%s", words[0]);
printf("%d", weights[0]);
return 0;
}
Another option would be to use strdup rather than the current code because it does both malloc and strcpy.
Other obvious problems are that your program will have troubles if any word is longer than 50 characters and it's not trivial to fix using scanf. You could use something like fscanf(dict,"%49s %d", &word, &weight); to avoid overflowing word but if the word is too long that will break the parsing loop. (you will get a line with the beginning of the word and the previous value of weight).
And another issue will happen if your dictionary file has less than 50000 entries.
Let's say that the content of your dictionary file has expected format rather than fixing the code.

Related

How do I properly call the function I created to the main?

So I suck with functions and need to debug this. Im pretty sure the function ToPigLating does its job well at converting. However I just need help calling the function ToPigLatin inside of my main function. But when I try doing that I just get a bunch of error codes.
#include <stdlib.h>
#include <string.h>
#define LEN 32
char* ToPigLatin(char* word[LEN]){
char word[LEN];
char translation [LEN];
char temp [LEN];
int i, j;
while ((scanf ("%s", word)) != '\0') {
strcpy (translation, word);
//just pretend I have all the work to convert it in here.
} // while
}
int main(){
printf("Enter 5 words: ");
scanf("%s", word);
ToPigLatin();
}```
Roughly, variables only exist within the function they're declared in. The word in ToPigLatin exists only within ToPigLatin. It is not available in main. This lets us write functions without worrying about all the rest of the code.
You need to declare a different variable in main, it can also be called word, to store the input and then pass that into ToPigLatin.
Let's illustrate with something simpler, a function which doubles its input.
int times_two(int number) {
return number * 2;
}
We need to give times_two a number.
int main() {
// This is different from "number" in times_two.
int number = 42;
// We have to pass its value into time_two.
int doubled = times_two(number);
printf("%d doubled is %d\n", number, doubled);
}
Your case is a bit more complicated because you're working with input and memory allocation and arrays. I'd suggest just focusing on arrays and function calls for now. No scanf. No strcpy.
For example, here's a function to print an array of words.
#include <stdio.h>
// Arrays in C don't store their size, the size must be given.
void printWords(const char *words[], size_t num_words) {
for( int i = 0; i < num_words; i++ ) {
printf("word[%d] is %s.\n", i, words[i]);
}
}
int main(){
// This "words" variable is distinct from the one in printWords.
const char *words[] = {"up", "down", "left", "right"};
// It must be passed into printWords along with its size.
printWords(words, 4);
}
ToPigLatingToPigLating function expects to have a parameter like ToPigLating("MyParameter");
Hello there icecolddash.
First things first, there are some concepts missing. In main section:
scanf("%s", word);
You're probably trying to read a string format and store in word variable.
In this case, you should have it on your declaration scope. After some adjustment, it will look like this:
int main(){
char word[LEN];
As you defined LEN with 32 bytes maximum, your program will not be allowed to read bigger strings.
You're also using standard input and output funcitions as printf, and so you should ever include stdio.h, thats the header which cointains those prototypes already declared, avoiding 'implicit declaration' compiling warnings.
Next issue is how you're declaring your translation function, so we have to think about it:
char* ToPigLatin(char* word[LEN])
In this case, what you wrote:
ToPigLatin is a funcion that returns a char pointer, which means you want your function to probably return a string. If it makes sense to you, no problem at all. Although we got some real problem with the parameter char* word[LEN].
Declaring your variable like this, assume that you're passing an array of strings as a parameter. If I got it right, you want to read all five words in main section and translate each one of them.
In this case I suggest some changes in main function, for example :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define LEN 32
#define MAX_WORDS 5
char *globalname = "translated";
char* ToPigLatin(char* word){
char *translation = NULL;
//Translation work here.
if ( !strcmp(word, "icecolddash") ){
return NULL;
}
translation = globalname;
return translation;
}
int main(){
char word[LEN];
char *translatedword;
int i;
printf("Enter 5 words: \n");
for ( i=0; i < MAX_WORDS; i++ ){
fgets(word, sizeof(word), stdin);
strtok(word, "\n"); // Just in case you're using a keyboard as input.
translatedword = ToPigLatin(word);
if ( translatedword != NULL ){
//Do something with your translation
//I'll just print it out as an example
printf("%s\n", translatedword);
continue;
}
// Generic couldn't translate message
printf("Sorry, I know nothing about %s\n", word);
}
return 0;
}
The above code translate every word in a fixed word "translated".
In case of reading the exact input "icecolddash", the program will output a generic error message, simulating some problem on translation process.
I hope this help you out with your studies.
There are a few things that I see.
#include <stdio.h>
#include <stdlib.h>
char* ToPigLatin(char* word){
printf(word);
return word;
}
int main(){
printf("Enter 5 words: ");
// declare the variable read into by scanf
char * word = NULL;
scanf("%s", word);
//Pass the variable into the function
ToPigLatin(word);
// Make sure you return an int from main()
return 0;
}
I left some comments in the code with some specific details.
However, the main thing that I would like to call out is the style of the way you're writing your code. Always try to write small, testable chunks and build your way up slowly. Try to get your code to compile. ALWAYS. If you can't run your code, you can't test it to figure out what you need to do.
As for the char ** comment you left on lewis's post, here is some reading you may find useful in building up your intuition:
https://www.tutorialspoint.com/what-does-dereferencing-a-pointer-mean-in-c-cplusplus
Happy coding!

Reading in char from file into struct

For my assignment, I have to read in a text file with a varying amount of lines. They follow the following format:
AACTGGTGCAGATACTGTTGA
3
AACTGGTGCAGATACTGCAGA
CAGTTTAGAG
CATCATCATCATCATCATCAT
The first line is the original line I will testing the following ones against, with the second line giving the number of remaining lines.
I'm having trouble trying to save these to a struct, and can't even get the first line to save. I tried using the void function with an array and it seems to work, but can't seem to transfer it over to structs.
Here's my code so far:
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define LENGTH 25
struct dna {
char code[LENGTH];
};
int main(){
char filename[] = "input1.txt";
FILE *input = fopen("input1.txt","r");
char firstDna[LENGTH]="";
struct dna first;
struct dna first.code[]= "";
makeArray(input,first);
// printf("%s",filename);
system("pause");
return 0;
}
void makeArray(FILE *input,struct dna first){
int i=-1;
//nested for loops to initialze array
//from file
while(i != '\n'){
fscanf(input,"%c",first[i].code);
printf("%c", first[i].code);
i++;
}//closing file
fclose(input);
}
Since this is for a class assignment, I want to preface this by saying that a good way to tackle these types of assignments is to break it up into tasks, then implement them one by one and finally connect them. In this case the tasks might be something like:
parse the first line into a (struct containing a) char array.
parse the number into an int variable
parse each remaining line in the file like you did with the first line
test the first line against the other lines in the file (except the number)
You also mentioned in a comment that the struct is for extra credit. For that reason, I'd recommend implementing it using just a char array first, then refactoring it into a struct once you have the basic version working. That way you have something to fall back on just in case. This way of developing might seem unnecessary at this point, but for larger more complicated projects it becomes a lot more important, so it's a really good habit to get into as early as possible.
Now, let's look at the code. I'm not going to give you the program here, but I'm going to identify the issues I see in it.
Let's start with the main method:
char filename[] = "input1.txt";
FILE *input = fopen("input1.txt","r");
This opens the file you're reading from. You're opening it correctly, but the first line is in this case unnecessary, since you never actually use the filename variable anywhere.
You also correctly close the file at the end of the makeArray function with the line:
fclose(input);
Which works. It would, however, probably be better style if you put this in the main method after calling the makeArray function. It's always a good idea to open and close files in the same function if possible, since this means you will always know you didn't forget to close the file without having to look through your entire program. Again, not really an issue in a small project, but a good habit to get into. Another solution would be to put the fopen and fclose functions in the makeArray function, so main doesn't have to know about them, then just send the char array containing the filepath to makeArray instead of the FILE*.
The next issue I see is with how you are passing the parameters to the makeArray function. To start off, instead of having a separate function, try putting everything in the main method. Using functions is good practice, but do this just to get something working.
Once that's done, something you need to be aware of is that if you're passing or returning arrays or pointers to/from functions, you will need to look up the malloc and free functions, which you may not have covered yet. This can be one of the more complex parts of C, so you might want to save this for last.
Some other things. I won't go into detail about these but try to get the concepts and not just copy paste:
struct dna first.code[]= ""; should probably be first.code[0] = \0;. \0 is used in C to terminate strings, so this will make the string empty.
Passing %c to fscanf reads a single character (you can also use fgetc for this). In this case, it will probably be easier using %s, which will return a word as a string.
Assuming you do use %s, which you probably should, you will need to call it twice before the loop - once to get the first DNA sequence and another time to get the number of other DNA sequences (the number of iterations).
Each iteration of the loop will then test the original DNA sequence against the next DNA sequence in the file.
I hope that helps!
sample to fix
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define LENGTH 25
struct dna {
char code[LENGTH];
};
struct dna *makeArray(FILE *input, int *n);//n : output, number of elements
int main(void){
char filename[] = "input1.txt";
FILE *input = fopen(filename,"r");
struct dna first = { "" };
fscanf(input, "%24s", first.code);//read first line
printf("1st : %s\n", first.code);
int i, size;
struct dna *data = makeArray(input, &size);//this does close file
for(i = 0; i < size; ++i){
printf("%3d : %s\n", i+1, data[i].code);
}
free(data);//release data
system("pause");
return 0;
}
struct dna *makeArray(FILE *input, int *n){//n : output, number of elements
int i;
fscanf(input, "%d", n);//read "number of remaining lines"
struct dna *arr = calloc(*n, sizeof(struct dna));//like as struct dna arr[n] = {{0}};
for(i = 0; i < *n; ++i){
fscanf(input, "%24s", arr[i].code);
}
fclose(input);
return arr;
}
a simple fix might be :
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define LENGTH 25
struct dna {
char code[LENGTH];
};
void makeArray(FILE *input,struct dna *first){
int i=0;
fscanf(input,"%c",&first->code[i]);
printf("%c",first->code[i]);
while(first->code[i] != '\n' && i < LENGTH){
i++;
fscanf(input,"%c",&first->code[i]);
printf("%c",first->code[i]);
}
}
int main() {
struct dna first;
char filename[] = "input1.txt";
FILE *input = fopen(filename,"r");
makeArray(input,&first);
fclose(input);
printf("%s",first.code);
return 0;
}
PS: i tried to not change your original code
in order to change the code[Length] in the makeArray function you will have to pass it's adresse this is why i call mkaeArray function this way : makeArray(input,&first);.

Breaking down a pointer str to smaller pointers str

#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXLINES 25
int get_lines(char *studentinfo[]);
int main()
{
int onswitch=0;
char *studentinfo[100];
char *fname[100];
char *lname[100];
char *score[100];
int counter;
int x,y;
char temp,temp2,temp3;
counter=get_lines(studentinfo);
for (y=0; y<counter; y++)
{
temp=strtok(studentinfo, " ");
fname[y]=malloc(strlen(temp));
strcpy(fname[y],temp);
temp2=strtok(NULL, " ");
lname[y]=malloc(strlen(temp2));
strcpy(lname[y],temp2);
temp3=strtok(NULL," ");
score[y]=malloc(strlen(temp3));
strcpy(score[y],temp3);
int get_lines(char *studentinfo[])
{
int n=0;
char buffer[80];
puts("Enter one line at a time; enter a blank when done.");
while ((n<MAXLINES) && (gets(buffer) !=0) && (buffer[0] != '\0'))
{
if ((studentinfo[n]=(char*)malloc(strlen(buffer)+1))==NULL)
return -1;
strcpy(studentinfo[n++],buffer);
}
return n;
}
Alright guys I am trying to make program that takes in student information for sorting later. I have taking the input down with the function on the bottom. I am trying to break down to the student information into three different pointers for sorting. The problem I am having is trying to allocate enough memory to store then information. Then actually storing the memory in that pointer location.
A simple input is
John Smith 80
^fname ^lname ^score
I thought the for loop I had would work in theory but it didnt (error: Unhandled exception at 0x0F3CFA50 (msvcr110d.dll) in ConsoleApplication3.exe: 0xC0000005: Access violation reading location 0xFFFFFF8) can anybody point me in the right direction (not just give me a loop that works) ?
With your implementation, you get an access violation. You are trying to touch a dirty region of memory. Here is the solution with an explanation below
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define MAXLINES 25
int get_lines(char *studentinfo[]);
int main()
{
int onswitch=0;
char *studentinfo[100];
char *fname[100];
char *lname[100];
char *score[100];
int counter;
int x,y;
char *temp,*temp2,*temp3;
counter=get_lines(studentinfo);
for (y=0; y<counter; y++)
{
temp=strtok(studentinfo[y], " ");
fname[y]=malloc(strlen(temp));
strcpy(fname[y],temp);
temp2=strtok(NULL, " ");
lname[y]=malloc(strlen(temp2));
strcpy(lname[y],temp2);
temp3=strtok(NULL," ");
score[y]=malloc(strlen(temp3));
strcpy(score[y],temp3);
printf("%s %s %s", fname[y], lname[y], score[y]);
}
}
int get_lines(char *studentinfo[])
{
int n=0;
char buffer[80];
puts("Enter one line at a time; enter a blank when done.");
while ((n<MAXLINES) && (gets(buffer) !=0) && (buffer[0] != '\0'))
{
if ((studentinfo[n]=(char*)malloc(strlen(buffer)+1))==NULL)
return -1;
strcpy(studentinfo[n++],buffer);
}
return n;
}
First off, you are missing an ending bracket } for your for loop as well as your main function. So add those.
Your getlines function is all good.
Your for loop is screwed up. In particular, you confused the data types you are passing. Remember, you have declared an array of POINTERS.
temp=strtok(studentinfo, " ");
This is saying, hey, let's tokenize my array pointer. You don't want this. You want to tokenize the yth element in that array! So element 0 in your array is a pointer to the string "JOHN SMITH 80". This is what we want to tokenize. Otherwise what you had was trying to tokenize somthing along the lines of 0xabcdabcd or whatever the memory address of the allocated array was.
temp=strtok(studentinfo[y], " ");
This is the correct way. It says tokenize the first element, which is a pointer to our string.
Your next problem is your temp variables. You are calling strlen(temp). strlen expects a pointer to a string. You are passing the data of the char itself. Actually, you are passing the return pointer (likely null) of the strtok function that was stored in your char byte.
char temp,temp2,temp3;
You declared three bytes for the type char. What you wanted was three char * to hold pointers to your string tokens.
char *temp,*temp2,*temp3;
With this, strlen takes in these pointers, mallocs some space for your fname elements, and then you proceed to copy into this element using strcpy.
Note: strcpy also takes two pointers, one for destination, one for source, so again your temp variables needed to be pointers to your strings.
Hope this helps let me know if you are confused with my explanation at all.
strcpy takes characters until it reaches a \0 character. You want to check out the strncpy or memcpy functions, and then manually add the null terminator.

Why does this c program crashe?

I want to make a list of , for example 10 sentences that are entered through the keyboard. For getting a line I am using a function getline(). Can anybody explain why does this program crash upon entering the second line? Where is the mistake ?
#define LISTMAX 100
#define LINEMAX 100
#include <stdio.h>
#include <string.h>
void getline(char *);
int main ()
{
char w[LINEMAX], *list[LISTMAX];
int i;
for(i = 0; i < 10; i++)
{
getline(w);
strcpy(list[i], w);
}
for(i = 0; i < 10; i++)
printf("%s\n", list[i]);
return 0;
}
void getline(char *word)
{
while((*word++ = getchar()) != '\n');
*word = '\0';
}
A string is a block of memory (an array), which contains chars, terminated by '\0'. A char * is not a string; it's just a pointer to the first char in a string.
strcpy does not create a new string. It just copies the data from one block of memory to another. So your problem is: you haven't allocated a block of memory to hold the string.
I'll show you two solutions. The first solution is: change the declaration of list so that the memory is already allocated. If you do it this way, you can avoid using strcpy, so your code is simpler:
// no need for w
char list[10][LISTMAX];
// ...
// get the line straight into list
// no need to copy strings
getline(list[i]);
But if you want to stretch yourself, the second solution is to allocate the block of memory when you know you'll need it. You need to do this a lot in C, so maybe now is a good time to learn this technique:
#include <stdlib.h> // include the malloc function
// ...
char w[LINEMAX], * list[LISTMAX]
// put this line between the getline and strcpy lines
list[i] = (char *) malloc((strlen(w) + 1) * sizeof(char));
This solution is more complicated, but you only allocate as much memory as you need for the string. If the string is 10 characters long, you only request enough memory to hold 11 characters (10 characters + '\0') from the system. This is important if, say, you want to read in a file, and you've no idea how big the file will be.
By the way, why do you have LINEMAX and LISTMAX as separate constants? Can you think of a reason why they might be different? And why haven't you made 10 a constant? Wouldn't this be better?
#define LINEMAX 100
#define NUMBER_OF_LINES 10
// ...
char list[NUMBER_OF_LINES][LINEMAX];
// ...
for (i = 0; i < NUMBER_OF_LINES; i++)

typedef memory allocation

VARIABLES AREN'T SET IN STONE YET! Excuse if if no indention. I am new to this site. Anyway, I have a text document of a list of games in five different categories, and I need to some help with memory allocation VIA typedef. How would one do it? So far, this is what I have:
/*
Example of text document
2012 DotA PC 0.00 10
2011 Gran Turismo 5 PS3 60.00 12
list continues in similar fashion...
*/
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
//function prototype here
char **readFile(char *file);
char *allocateString(char temp[]);
typedef struct
{
int year;
char name[100];
char system[10];
float price;
int players;
}game;
int main(void)
{
char **list;
system("pause");
return 0;
}
//function defined here
char **readFile(char *file) //reads file and and allocates
{
FILE* fpIn;
int i, total=0;
fpIn = fopen("list.txt", "r");
if (!fpIn)
{
printf("File does not exist");
exit(101);
}
/*
allocate memory by row here VIA for loop with the total++ to keep track of the
number of games
*/
/*
allocate memory individually for each item VIA "allocateString by using going
to set list[i] = allocateStrng(tmpList) using for loop the for loop will have
for (i=0; i<total; i++)
*/
return;
}
//allocateString here
char *allocateString(char temp[]);
{
char *s;
s = (char*)calloc(strlen(temp+1), sizeof(char)));
strcpy(s, temp);
return s;
}
Usually you'd allocate a decent amount of memory up front, detect situations where that amount is not enough, and enlarge the allocation in those cases using realloc (or malloc followed by memcpy and free). This advice holds for both the buffer into which you read the current line (to be passed as temp to allocateString) and the array to hold the sequence of all lines.
You can detect an insufficient buffer size for the line buffer when after calling fgets(buf, bufsize, fpIn) the strlen(buf) == bufsize - 1 but still buf[bufsize - 2] != '\n'. In other words, when reading filled the whole buffer, but still didn't reach a newline. In that case, the next read will continue the current line. You might want an inner loop to extend the buffer and read again for as long as it takes.
Note that your allocateString pretty much duplicates strdup, so you might want to use that instead.
The links in the above text mainly come from the manual of the GNU C library. cppreference.com is another good source of C function documentation. As are the Linux man pages.
s = (char*)calloc(strlen(temp+1), sizeof(char)));
//the name of the array is a pointer, so you are doing pointer arithmetic.
//I think you want strlen(*temp+1, sizeof(char)));
// or strlen(temmp[1]) it isn't clear if this is a pointer to a string or an array
// of strings
//you need the length of the string *temp is the content which temp points to
//strcpy(s, temp);

Resources