Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Closed 6 years ago.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
This question does not appear to be about a specific programming problem, a software algorithm, or software tools primarily used by programmers. If you believe the question would be on-topic on another Stack Exchange site, you can leave a comment to explain where the question may be able to be answered.
Improve this question
So my program takes a file as input and parses out spaces. Tokens are saved into an array. I have a function to print out the contents of the array to test if the parser works. The code compiles with gcc -o filename filename.c . But when I run the program and give it a filepath, I get a pop up window indicating filename.exe has stopped working : A problem caused the program to stop working correctly. Windows will close the program and notify you if a solution is available.
#include <stdio.h>
#include <stdint.h>
#include <stdlib.h>
#include <string.h>
char file_name[100];
char *token_array[256];
int main()
{
char ch;
FILE *fp;
int n=0;
char *str;
printf("Enter filepath\n");
gets(file_name);
fp = fopen(file_name,"r");
if( fp == NULL )
{
perror("Error opening the file.\n");
exit(EXIT_FAILURE);
}
int i = 0;
char *p;
while( ( ch = fgetc(fp) ) != EOF )
{
char *fgets(char *str, int n, FILE *stream);
p = strtok(str, " ");
i=0;
while(p!=NULL)
{
strcpy(token_array[i], p);
}
i++;
}
for(n=0;n<256;n++)
{
printf("%s", &token_array[n]);
}
return 0;
}
You can try this code instead. I changed your program so that it can read and tokenize the file.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
char *trim(char *s) {
int i = strlen(s) - 1;
if (s[i] == '\n')
s[i] = '\0';
return s;
}
#define BUFFER_SIZE 100
char *token_array[256];
int main( int argc, char** argv ){
const char *delimiter_characters = " ";
char *filename = malloc(BUFFER_SIZE);
int i = 0;
printf("Enter filepath\n");
fgets(filename, 100, stdin);
FILE *input_file = fopen( trim(filename), "r" );
char buffer[ BUFFER_SIZE ];
char *last_token;
if( input_file == NULL ){
fprintf( stderr, "Unable to open file %s\n", filename );
}else{
// Read each line into the buffer
while( fgets(buffer, BUFFER_SIZE, input_file) != NULL ){
// Write the line to stdout
//fputs( buffer, stdout );
// Gets each token as a string and prints it
last_token = strtok( buffer, delimiter_characters );
while( last_token != NULL ){
//printf( "%s\n", last_token );
token_array[i] = malloc(100);
strcpy(token_array[i], last_token);
i++;
last_token = strtok( NULL, delimiter_characters );
}
}
if( ferror(input_file) ){
perror( "The following error occurred" );
}
fclose( input_file );
}
int n;
for(n=0;token_array[n] != NULL && n<256;n++)
{
printf("%s", token_array[n]);
free(token_array[n]);
}
free(filename);
return 0;
}
data.txt
Hello Foo Bar
How are you?
Test
Debug/gnu
Enter filepath
data.txt
HelloFooBar
Howareyou?
Process finished with exit code 0
The contents of the array are
n[0] Hello
n[1] Foo
n[2] Bar
n[3] How
n[4] are
n[5] you?
You can see the contents of the array if you add debug info:
printf("n[%d] %s\n", n, token_array[n]);
This line does nothing:
char *fgets(char *str, int n, FILE *stream);
As written, that line is nothing but a declaration of a function, probably not what you want.
If you're going to use fgets(), use fgets() alone and don't mix it with fgetc():
char str[1024];
while ( fgets( str, sizeof( str ), fp )
{
.
.
.
fgets() returns NULL upon EOF or an error condition. And note that str is not a char *, it's a char array. An even better solution would be to use getline() because fgets() with a fixed-length buffer can only read entire lines that fit into the buffer. Longer lines will be split.
fgetc() returns int, not char. But you don't shouldn't use fgetc() when reading lines from a file with fgets(). Pick one and use that. But if you use fgetc(), you'll need to write code to put together each line as you read it character-by-character.
And what does token_array[i] point to? You declare token_array as an array of pointers:
char *token_array[256];
But you never allocate any memory for each pointer in the array to point to.
The easiest solution is to change
strcpy(token_array[i], p);
to
token_array[i] = strdup(p);
assuming your platform has strdup(), which is equivalent to a malloc() and strcpy() to the memory returned by malloc(), so you need to call free() on the string you get from strdup().
Your use of strtok() is wrong. See How does strtok() split the string into tokens in C? for examples of proper strtok() usage.
And since token_array is an array of char * pointers, this
printf("%s", &token_array[n]);
will take the address of the actual pointer itself, and not the string it's supposed to point to. It will then try to print out a "string" in the memory containing the pointer variable. That's won't work well. Since it's already a char *, all you need is this:
printf("%s", token_array[n]);
Related
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 4 years ago.
Improve this question
I'm working on the following pthread program that finds the number of substrings in string2 that are in string1:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <pthread.h>
#define NUM_THREADS 4
#define MAX 1024
int n1,n2,i;
char *s1,*s2;
FILE *fp;
char *substring(char *string, int position, int length);
void *occurrence();
int readf(FILE *fp)
{
if((fp=fopen("strings.txt", "r"))==NULL){
printf("ERROR: can't open strings.txt!\n");
return 0;
}
s1=(char *)malloc(sizeof(char)*MAX);
if(s1==NULL){
printf("ERROR: Out of memory!\n");
return -1;
}
s2=(char *)malloc(sizeof(char)*MAX);
if(s1==NULL){
printf("ERROR: Out of memory\n");
return -1;
}
/*read s1 s2 from the file*/
s1=fgets(s1, MAX, fp);
s2=fgets(s2, MAX, fp);
n1=strlen(s1); /*length of s1*/
n2=strlen(s2)-1; /*length of s2*/
if(s1==NULL || s2==NULL || n1<n2) /*when error exit*/
return -1;
return 0;
}
int main(void)
{
pthread_t tid;
pthread_create(&tid, NULL, occurrence, NULL);
pthread_join(tid, NULL);
exit(0);
}
char *substring(char *string, int position, int length)
{
char *pointer;
int c;
pointer = malloc(length+1);
if (pointer == NULL)
{
printf("Unable to allocate memory.\n");
exit(1);
}
for (c = 0 ; c < length ; c++)
{
*(pointer+c) = *(string+position-1);
string++;
}
*(pointer+c) = '\0';
return pointer;
}
void* occurrence()
{
char *string1;
char *string2;
char *new_str;
int counter=0;
readf(fp);
string1 = s1;
string2 = s2;
new_str = malloc(200);
for(i=1;i<=strlen(string1);i++)
{
new_str = substring(string1,i,strlen(string2));
if(strcmp(new_str, string2)==0)
{
counter++;
}
}
printf("The number of substrings is: %d \n",counter);
return 0;
}
When i compile it on codeblocks, it prints the correct number of substrings. However, when I compile it on the Linux kernel, it always prints 1 as the number of substrings, even though there's more than one. For example, a strings.txt file that has abdeabjhab in the first line and ab in the 2nd line should print 3, since there's 3 instances of ab in the first line. My Linux kernel prints 1. Is there a specific way I'm supposed to compile it for it to print the right value? I'm current using gcc -pthread substring.c -o substrings to compile and ./substrings to execute it.
There are several issues here.
First the signature for occurrence is wrong; the thread function should take a void* as argument and return a void* as required by the pthread_create API. So it should be:
void *occurrence(void*);
and
void *occurrence(void arg*) {
...
return NULL;
}
There are several other questionable things in your code.
You are passing the global variable fp to readf() function. Why do you need to pass a global variable?
You are reading only the first two lines. What if the file contains many more lines?
Why do you have s1 and s2 as global? You could easily rewrite it to pass from readf back to occurrence. Or occurrence could pass varibles that readf writes into.
You don't close the file with fclose.
You create just one thread to do the work and the main thread just waits for it. So there's no real need for threads here. You might as well let the main thread do the work and not bother with threads.
Why do you subtract here?: n2=strlen(s2)-1; /*length of s2*/.
What if the length of s1 and s2 are the same? Is "abc" not a substring of "abc"?
Your actual of problem of getting incorrect substring count is probably because fgets() reads in the newline character and thus the substring match fails.
To remove newlines, you can do in your readf function after reading s1 and s2:
char *p = strchr(s1, '\n');
if (p) *p = 0;
p = strchr(s2, '\n');
if (p) *p = 0;
This should fix the immediate problem. But there's a lot you could improve.
I am trying to read a file line by line and split it into words. Those words should be saved into an array. However, the program only gets the first line of the text file and when it tries to read the new line, the program crashes.
FILE *inputfile = fopen("file.txt", "r");
char buf [1024];
int i=0;
char fileName [25];
char words [100][100];
char *token;
while(fgets(buf,sizeof(buf),inputfile)!=NULL){
token = strtok(buf, " ");
strcpy(words[0], token);
printf("%s\n", words[0]);
while (token != NULL) {
token = strtok(NULL, " ");
strcpy(words[i],token);
printf("%s\n",words[i]);
i++;
}
}
After good answer from xing I decided to write my FULL simple program realizing your task and tell something about my solution. My program reads line-by-line a file, given as input argument and saves next lines into a buffer.
Code:
#include <assert.h>
#include <errno.h>
#define _WITH_GETLINE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define assert_msg(x) for ( ; !(x) ; assert(x) )
int
main(int argc, char **argv)
{
FILE *file;
char *buf, *token;
size_t length, read, size;
assert(argc == 2);
file = fopen(argv[1], "r");
assert_msg(file != NULL) {
fprintf(stderr, "Error ocurred: %s\n", strerror(errno));
}
token = NULL;
length = read = size = 0;
while ((read = getline(&token, &length, file)) != -1) {
token[read - 1] = ' ';
size += read;
buf = realloc(buf, size);
assert(buf != NULL);
(void)strncat(buf, token, read);
}
printf("%s\n", buf);
fclose(file);
free(buf);
free(token);
return (EXIT_SUCCESS);
}
For file file.txt:
that is a
text
which I
would like to
read
from file.
I got a result:
$ ./program file.txt
that is a text which I would like to read from file.
Few things which is worth to say about that solution:
Instead of fgets(3) I used getline(3) function because of easy way to knowledge about string length in line (read variable) and auto memory allocation for got string (token). It is important to remember to free(3) it. For Unix-like systems getline(3) is not provided by default in order to avoid compatibility problems. Therefore, #define _WITH_GETLINE macro is used before <stdio.h> header to make that function available.
buf contains only mandatory amount of space needed to save string. After reading one line from file buf is extended by the required amount of space by realloc(3). Is it a bit more "universal" solution. It is important to remember about freeing objects allocated on heap.
I also used strncat(3) which ensures that no more than read characters (length of token) would be save into buf. It is also not the best way of using strncat(3) because we also should testing a string truncation. But in general it is better than simple using of strcat(3) which is not recommended to use because enables malicious users to arbitrarily change a running program's functionality through a buffer overflow attack. strcat(3) and strncat(3) also adds terminating \0.
A getline(3) returns token with a new line character so I decided to replace it from new line to space (in context of creating sentences from words given in file). I also should eliminate last space but I do not wanted to complicate a source code.
From not mandatory things I also defined my own macro assert_msg(x) which is able to run assert(3) function and shows a text message with error. But it is only a feature but thanks to that we are able to see error message got during wrong attempts open a file.
The problem is getting the next token in the inner while loop and passing the result to strcpy without any check for a NULL result.
while(fgets(buf,sizeof(buf),inputfile)!=NULL){
token = strtok(buf, " ");
strcpy(words[0], token);
printf("%s\n", words[0]);
while (token != NULL) {//not at the end of the line. yet!
token = strtok(NULL, " ");//get next token. but token == NULL at end of line
//passing NULL to strcpy is a problem
strcpy(words[i],token);
printf("%s\n",words[i]);
i++;
}
}
By incorporating the check into the while condition, passing NULL as the second argument to strcpy is avoided.
while ( ( token = strtok ( NULL, " ")) != NULL) {//get next token != NULL
//if token == NULL the while block is not executed
strcpy(words[i],token);
printf("%s\n",words[i]);
i++;
}
Sanitize your loops, and don't repeat yourself:
#include <stdio.h>
#include <string.h>
int main(void)
{
FILE *inputfile = fopen("file.txt", "r");
char buf [1024];
int i=0;
char fileName [25];
char words [100][100];
char *token;
for(i=0; fgets(buf,sizeof(buf),inputfile); ) {
for(token = strtok(buf, " "); token != NULL; token = strtok(NULL, " ")){
strcpy(words[i++], token);
}
}
return 0;
}
Closed. This question needs debugging details. It is not currently accepting answers.
Edit the question to include desired behavior, a specific problem or error, and the shortest code necessary to reproduce the problem. This will help others answer the question.
Closed 6 years ago.
Improve this question
This code does reverse and put result in file, but not fully correct.
Like, some issues with detecting line breaker or sth. Here's an example:
Source:
This is a line.
This is another line.
Quick brown fox jumps over a lazy dog!
Result:
(blank line)
.enil a si sihT
.enil rehtona si sihT!god yzal a revo spmuj xof nworb kciuQ
#include <stdio.h>
#include <string.h>
char *reverse (char *str)
{
char *begin, *end, c;
if (!str || !(*str))
return NULL;
for (begin=str, end=str+strlen(str)-1; begin<end; begin++, end--)
{
c=*begin;
*begin=*end;
*end=c;
}
begin=str+strlen(str)+1; *begin='\0'; //??
return str;
}
void main(void)
{
char line[1000];
FILE *fsrc, *frslt;
fsrc=fopen("source.txt", "r");
if (fsrc==NULL) return;
frslt=fopen("result.txt", "w");
while (!feof(fsrc))
{
fgets (line, 1000, fsrc);
fputs (reverse(line), frslt);
}
fclose(fsrc);
fclose(frslt);
}
A couple of comments/nitpicks, which may or may not solve your problem :)
if (!str || !(*str))
return NULL;
Don't do that. Don't return NULL on empty strings, fputs() will barf. In my experience, it's better to a) assert that the str pointer is non-null, b) return the empty string.
begin=str+strlen(str)+1; *begin='\0'; //??
There should be no need to terminate the string, since it's already terminated.
void main(void)
Nah, main() returns an int.
while (!feof(fsrc))
This won't work. You need to do some IO before you can test for feof()/ferror(). IMHO it's better to simply loop on fgets().
while (fgets(line, sizeof line, fsrc) {
...
}
It may be a good idea to drop the input and output files, and simply read from stdin and write to stdout, at least while testing. The functionality you're trying to implement is already available in a UNIX shell (man rev). Using stdin/stdout makes it easier to test and compare results with the results from rev.
Also, keep in mind that fgets() won't remove the \n from the string. input like "foo\n" becomes "\noof", which is probably not what you want.
Here's a snippet which illustrates my comments in code. It doesn't solve all problems, but should be sufficient to get you going.
#include <stdio.h>
#include <string.h>
#include <assert.h>
void reverse(char *str)
{
char *begin, *end, c;
size_t n;
assert(str != NULL);
n = strlen(str);
if (n == 0)
return;
for (begin = str, end = str + n - 1; begin < end; begin++, end--) {
c = *begin;
*begin = *end;
*end = c;
}
}
int main(void)
{
char line[1000];
while (fgets(line, sizeof line, stdin)) {
reverse(line);
fputs(line, stdout);
}
}
HTH
I am working with struct types. I take in a line from my own file that says "cerberus guards the river styx". When I try to print it out, only the letter 'c' prints. I don't know why this is happening.
#define _GNU_SOURCE
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef unsigned int uint;
struct wordType
{
char word[80];
uint count;
};
struct wordType words[10];
int main( void ) {
FILE * inputFile;
char * line = NULL;
size_t len = 0;
ssize_t read;
uint index;
inputFile = fopen( "input.txt", "r");
if( inputFile == NULL )
{
printf( "Error: File could not be opened" );
/*report failure*/
return 1;
}
index = 0;
while( ( read = getline( &line, &len, inputFile ) ) != -1 )
{
printf( "%s\n", line );
*words[index].word = *line;
printf("line = %s\n", (words[index].word) );
}
free( line );
return 0;
}
*words[index].word = *line;
copies line[0] into words[index].word[0], so that's only one character. If you want to copy the entire line, you have to use
strcpy(words[index].word, line);
But you should verify that the line fits, i.e.
strlen(line) < 80
before that.
Ok this an issue with how you are allocating the line object's memory. According to your code you set up a char*, however you never allocate any memory to it. That being said your char* will only be able to hold 1 character, or more accurate the number of characters to fill a standard char in whatever system you are using.
To fix this you will want to put a malloc() call into your code to allocate the length of the string to the char*.
line = (char *)malloc(SizeofString);
This code will give your line object the correct size to hold the entire string, instead of just one character. However you will probably want to use the following as your string size to ensure platform independence.
SizeofString = sizeof(char) * numberofCharactersinString;
Then use strcpy() to copy the contents of the line.
EDIT::
It appears what I wrote above is misleading due to the way that the GetLine() call functions. which does the malloc() call for you.
In my program I am taking user input and parsing it into a 2d char array. The array is declared as:
char parsedText[10][255] = {{""},{""},{""},{""},{""},
{""},{""},{""},{""},{""}};
and I am using fgets to grab the user input and parsing it with sscanf. This all works as I think it should.
After this I want to pass parsedText into execvp, parsedText[0] should contain the path and if any arguments are supplied then they should be in parsedText[1] thru parsedText[10].
What is wrong with execvp(parsedText[0], parsedText[1])?
One thing probably worth mentioning is that if I only supply a command such as "ls" without any arguments it appears to work just fine.
Here is my code:
#include <stdio.h>
#include <string.h>
#include <unistd.h>
#include "308shell.h"
int main( int argc, char *argv[] )
{
char prompt[40] = "308sh";
char text[40] = "";
char parsedText[10][40] = {{""},{""},{""},{""},{""},
{""},{""},{""},{""},{""}};
// Check for arguments to change the prompt.
if(argc >= 3){
if(!(strcmp(argv[1], "-p"))){
strcpy(prompt, argv[2]);
}
}
strcat(prompt, "> ");
while(1){
// Display the prompt.
fputs(prompt, stdout);
fflush(stdout);
// Grab user input and parse it into parsedText.
mygetline(text, sizeof text);
parseInput(text, parsedText);
// Check if the user wants to exit.
if(!(strcmp(parsedText[0], "exit"))){
break;
}
execvp(parsedText[0], parsedText[1]);
printf("%s\n%s\n", parsedText[0], parsedText[1]);
}
return 0;
}
char *mygetline(char *line, int size)
{
if ( fgets(line, size, stdin) )
{
char *newline = strchr(line, '\n'); /* check for trailing '\n' */
if ( newline )
{
*newline = '\0'; /* overwrite the '\n' with a terminating null */
}
}
return line;
}
char *parseInput(char *text, char parsedText[][40]){
char *ptr = text;
char field [ 40 ];
int n;
int count = 0;
while (*ptr != '\0') {
int items_read = sscanf(ptr, "%s%n", field, &n);
strcpy(parsedText[count++], field);
field[0]='\0';
if (items_read == 1)
ptr += n; /* advance the pointer by the number of characters read */
if ( *ptr != ' ' ) {
strcpy(parsedText[count], field);
break; /* didn't find an expected delimiter, done? */
}
++ptr; /* skip the delimiter */
}
}
execvp takes a pointer to a pointer (char **), not a pointer to an array. It's supposed to be a pointer to the first element of an array of char * pointers, terminated by a null pointer.
Edit: Here's one (not very good) way to make an array of pointers suitable for execvp:
char argbuf[10][256] = {{0}};
char *args[10] = { argbuf[0], argbuf[1], argbuf[2], /* ... */ };
Of course in the real world your arguments probably come from a command line string the user entered, and they probably have at least one character (e.g. a space) between them, so a much better approach would be to either modify the original string in-place, or make a duplicate of it and then modify the duplicate, adding null terminators after each argument and setting up args[i] to point to the right offset into the string.
You could instead do a lot of dynamic allocation (malloc) every step of the way, but then you have to write code to handle every possible point of failure. :-)