C multi-thread wordcount program segmentation fault issue - c

I've been racking my brain against this program for a couple months now. This was an assignment of a class I took last semester and while I passed, I could never make this one assignment work correctly (Seg Fault). I welcome any help or tips but I greatly appreciate explanations with answers to follow along.
This program is supposed to receive a filename that contains a list of filenames (240 for my example). Those files are located in a folder within the same directory as the list and the program. This program is supposed to take this list and parse it for 4 threads, splitting the filenames evenly for each thread (60 per thread for my example). Each thread then takes this list of 60 file names and opens each file one by one performing a WordCount function on each file. Once the threads complete their tasks, they are supposed to print the results for each file in order with each thread in its own block(i.e. Thread1 Results | Thread2 Results | Thread 3 Results, etc...).
I've debugged quite a bit and know that up until the threads are created everything works as it is supposed to. My problem seems to be during thread launch/execution. I've tried adding mutex to the mix but sadly it hasn't helped. I seem to be missing something or over thinking something as some of my class mates have shown me their much more compact code. Please assist. Thanks!
Here is the Main:
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <time.h>
#define MaxLine 200
#define NUMTHREADS 4
char Line[MaxLine];
pthread_mutex_t Lock = PTHREAD_MUTEX_INITIALIZER;
typedef struct thread {
int id;
char file;
}ThreadData;
/* ThreadFunction will give each thread its processes to execute */
void *threadFunc (void *td) {
ThreadData *data = (ThreadData*)td;
int thread_num=data->id;
char filename=data->file;
printf("thread debug tid: %d and file: %c",thread_num, filename);
pthread_mutex_trylock(&Lock);
FILE *fn = fopen(filename, "r");
if (fn == NULL) {
error("ERROR: Opening file");
return 1;
}
while (fgets(Line, sizeof(Line), fn) != NULL) {
CountWord(thread_num, Line);
}
fclose(fn);
free(data);
pthread_mutex_unlock(&Lock);
pthread_exit(NULL);
}
int main(int argc, char *argv[]){
char buf[20];
int c, i, t, tnum, QUEUETOTAL;
pthread_t thread[NUMTHREADS];
ThreadData td[NUMTHREADS];
if (argc != 2){
fprintf(stderr,"ERROR: Usage must be Countfile filename\n", argv[0]);
exit(0);
}
char const* const filename = argv[1];
FILE* file = fopen(filename, "r");
if ( file == 0 ){
printf( "Could not open file!\n" );
exit(0);
}
/* Count iterations of while loop to divide files among threads. */
while (fgets(Line, sizeof(Line), file)){
QUEUETOTAL++;
}
/* Divide work for threads. */
int thread2taskstart=(QUEUETOTAL/NUMTHREADS); //60
int thread3taskstart=(QUEUETOTAL/NUMTHREADS)*2; //120
int thread4taskstart=(QUEUETOTAL/NUMTHREADS)*3; //180
// QUEUETOTAL = 240
rewind(file);
FILE *tempfile1 = fopen("temp1.txt","w");
for (i=0; i<thread2taskstart; i++) {
// populate tempfile1 with entries 1-60
if(fgets(Line,sizeof(Line),file)!=NULL) {
fputs(Line,tempfile1);
//printf("Debug temp1: %s",Line);
}
}
fclose(tempfile1);
FILE *tempfile2 = fopen("temp2.txt","w");
for (i=thread2taskstart; i<thread3taskstart; i++) {
// populate tempfile2 with entries 60-120
if(fgets(Line,sizeof(Line),file)!=NULL) {
fputs(Line,tempfile2);
//printf("Debug temp2: %s",Line);
}
}
fclose(tempfile2);
FILE *tempfile3 = fopen("temp3.txt","w");
for (i=thread3taskstart; i<thread4taskstart; i++) {
// populate tempfile3 with entries 120-180
if(fgets(Line,sizeof(Line),file)!=NULL) {
fputs(Line,tempfile3);
//printf("Debug temp3: %s",Line);
}
}
fclose(tempfile3);
FILE *tempfile4 = fopen("temp4.txt","w");
for (i=thread4taskstart; i<=QUEUETOTAL; i++) {
// populate tempfile3 with entries 180-240
if(fgets(Line,sizeof(Line),file)!=NULL) {
fputs(Line,tempfile4);
//printf("Debug temp4: %s",Line);
}
}
fclose(tempfile4);
fclose(file);
/* Prepare parameters & launch (4) threads. Wait for threads
to finish & print out results as specified in assignment. */
printf("Counting files …\n");
for(t=0;t<NUMTHREADS;t++){
tnum=t+1;
snprintf(buf, "temp%d.txt", tnum);
printf("debug tnum and array: %d and %s\n",tnum, buf);
td[t].id = tnum;
td[t].file = buf;
// Creates a new thread for each temp file.
pthread_create(&thread[t], NULL, threadFunc, td);
}
// Joins threads.
printf("debug: printing threads \n");
for(t=0;t<NUMTHREADS;t++){
pthread_join(thread[t], NULL);
printf("------------------------- Processes finished for Thread %d ----------------------- \n",t+1);
}
return 0;
}
Here is the Count Function:
#include <stdio.h>
int CountWord(int tinfo, char cfile){
int i;
int ccount = 0;
int wcount = 0;
int lcount = 0;
FILE *fname;
char fn[strlen(cfile) + 18];
sprintf(fn, "./CountingFolder/%s", cfile);
printf("Debug: %s\n", fn);
fname = fopen(fn, "r");
if (fname == NULL) {
error("ERROR: Opening file");
}
while ((i = fgetc(fname)) != EOF){
if (i == '\n') {
lcount++;
}
if (i == '\t' || i == ' '){
wcount++;
}
ccount++;
}
printf("Threadid %d processes %s which has %d characters, %d words and %d lines\n", tinfo, cfile, ccount, wcount, lcount);
fclose(fname);
return 0;
}

1) Probably a typo. But
int CountWord(int tinfo, char cfile){ .. }
should be
int CountWord(int tinfo, char *cfile){ .. }
2) You are passing the same buf to all threads from main(). Data race and undefined behaviour.
3) None of the snprintf() calls take the size argument. Undefined behaviour.
4) Since all threads work on different data, you don't need a lock at all.
5) You didn't allocate td array. So you can't call free(data); in the thread function. Undefined behaviour.
There may be more issues with the code but the segfault is likely because of (3) or (5).

In your code here
snprintf(buf, "temp%d.txt", tnum);
printf("debug tnum and array: %d and %s\n",tnum, buf);
td[t].id = tnum;
td[t].file = buf;
the last line assigns a pointer into the file field of this struct
typedef struct thread {
int id;
char file;
}ThreadData;
Shouldn't it be char *file; ? I don't have thread.h in MSVC so I can't compile it. Surely you have all warnings enabled??

Related

In C, how can I pass the strings from a file into a string array. Notice that main objective is to order the students with respect to their id

The program given below is equalize all name and surname with last ones. The contents of the students.dat ;
2020102054 Name1 Surname1
2021202051 Name2 Surname2
2020302057 Name3 Surname3
2020802053 Name4 Surname4
2020602059 Name5 Surname5
2019452065 Name6 Surname6
#include <stdio.h>
#include <stdlib.h>
int main()
{
FILE *stdFptr, *orderFptr;
int student_id ,temp_id[20],ordered_id[20], a=0,i,j;
char student_name[32], student_surname[32];
char *ordered_name[32],*ordered_surname[32],*temp_string[32];
stdFptr = fopen("students.dat","r");
orderFptr = fopen("order.dat","w");
if(!stdFptr || !orderFptr){
puts("File Error, Exiting The Program");
exit(0);
}
else{
puts("Before ordering");
fscanf(stdFptr, "%d %s %s ",&student_id,student_name,student_surname);
while(!feof(stdFptr)){
ordered_name[a] = student_name;
ordered_surname[a] = student_surname;
ordered_id[a] = student_id;
a++;
fprintf(stdout,"%d %s %s\n",student_id,student_name,student_surname);
fscanf(stdFptr, "%d %s %s ",&student_id,student_name,student_surname);
}
ordered_name[a] = student_name;
ordered_surname[a] = student_surname;
ordered_id[a] = student_id;
fprintf(stdout,"%d %s %s\n",student_id,student_name,student_surname);
for(i=0;i<a;i++){
for(j=i+1;j<=a;j++){
if(ordered_id[i]>ordered_id[j]){
temp_string[i] = ordered_name[i];
ordered_name[i] = ordered_name[j];
ordered_name[j] = temp_string[i];
temp_string[i] = ordered_surname[i];
ordered_surname[i] = ordered_surname[j];
ordered_surname[j] = temp_string[i];
temp_id[i] = ordered_id[i];
ordered_id[i] = ordered_id[j];
ordered_id[j] = temp_id[i];
}
}
}
rewind(stdFptr);
fclose(stdFptr);
}
stdFptr = fopen("students.dat","r");
if(!stdFptr || !orderFptr){
puts("File Error, Exiting The Program");
exit(0);
}
else{
puts("After ordering");
i=0;
while(i<=a){
fprintf(orderFptr,"%d\t%s\t\t\t%s\n",ordered_id[i],ordered_name[i],ordered_surname[i]);
fprintf(stdout,"%d %s %s\n",ordered_id[i],ordered_name[i],ordered_surname[i]);
i++;
}
fclose(stdFptr);
fclose(orderFptr);
}
return 0;
}
You have multiple errors in your program.
Errors:
ordered_name[a] = student_name;
You only have pointers in your array. And you only have one single array for the name. That means you just assign the address of the same array to each of your entries in ordered_name. Same for the other fields.
while(!feof(stdFptr)){
Just don't do this. See Why is “while ( !feof (file) )” always wrong? why this is wrong.
temp_id[i] = ordered_id[i];
You use array temp_id to swap your array entries.
First of all, that is very inefficient as you only need a single variable, not an array.
Second, this is wrong because you only have 20 elements in temp_id and ordered_id but 32 elements in the other ordered* arrays.
Also you do not care about the number of entries in your file and might overflow both arrays.
Bad practice:
int student_id ,temp_id[20],ordered_id[20], a=0,i,j;
char student_name[32], student_surname[32];
char *ordered_name[32],*ordered_surname[32],*temp_string[32];
You are using corresponding arrays to store each field of your data sets. That is terrible to maintain.
Use a struct instead:
#define NAME_LENGTH 32
#define MAX_NUMBER 50
struct student {
int id;
char name[NAME_LENGTH];
char surname[NAME_LENGTH];
};
fscanf(stdFptr, "%d %s %s ",&student_id,student_name,student_surname);
You do not check the result of fscanf which you should always do.
Even better, use fgets followed by sscanf to parse your content.
stdFptr = fopen("students.dat","r");
You open the file again after you already read all the content. That's not needed.
Your sorting is also inefficient:
for(i=0;i<a;i++){
for(j=i+1;j<=a;j++){
if(ordered_id[i]>ordered_id[j]){
This can be used to fully sort an unsorted array.
You do this for each new line. Therefore you can rely on the array being sorted. You onle need to find the place where to put the new entry. For this, a single loop would be sufficient.
Or you can move that sorting after you have finished reading the file.
You exit your program in case of an error but you don't report an error to the calling environment
exit(0);
That is same as exit(EXIT_SUCCESS);. If terminate due to an error, you should also indicate that condition.
An improved version could look like this:
#include <stdio.h>
#include <stdlib.h>
#define NAME_LENGTH 32
#define MAX_NUMBER 50
struct student {
int id;
char name[NAME_LENGTH];
char surname[NAME_LENGTH];
};
int main(void)
{
struct student students[MAX_NUMBER];
int count = 0;
FILE *infile = fopen("students.dat","r");
if (infile == NULL) {
fprintf(stderr, "Input file cannot be openend.");
exit(EXIT_FAILURE);
}
// PART 1: Read the file content
puts("Before ordering");
char line[2*NAME_LENGTH + 20];
while (fgets(line, sizeof (line), infile) != NULL
&& count < MAX_NUMBER)
{
int result = sscanf(line, "%d %31s %31s", &students[count].id, students[count].name, students[count].surname);
if (result != 3)
{
fprintf(stderr, "Invalid line ignored: <%s>", line);
}
else
{
fprintf(stdout,"%d %s %s\n", students[count].id, students[count].name, students[count].surname);
count++;
}
}
fclose(infile);
// PART 2: Sort the array
struct student temp;
for (int i = 0; i < count-1; i++) {
for (int j = i+1; j < count; j++) {
if (students[i].id > students[j].id) {
temp = students[i];
students[i] = students[j];
students[j] = temp;
}
}
}
// Note: You could also just use qsort() function from standard library.
// PART 3: Write to output file
FILE *outfile = fopen("order.dat","w");
if (outfile == NULL) {
fprintf(stderr, "Output file cannot be openend.");
exit(EXIT_FAILURE);
}
puts("After ordering");
for (int i=0; i < count; i++) {
fprintf(outfile,"%d\t%s\t\t\t%s\n", students[i].id, students[i].name, students[i].surname);
fprintf(stdout,"%d %s %s\n", students[i].id, students[i].name, students[i].surname);
}
fclose(outfile);
}

c program crashes when retrieving sizeof(buff)

I am creating a program in C that splits a large text file into 10 segments, and then creates 10 threads with each thread generating a word count for each segment. I took the function word_count from this code: https://github.com/prateek-khatri/seaOfC/blob/master/frequencyMultiThread.c. That program works fine for me, but when I tried to use word_count in my own program, it crashes when trying to get the size of the buffer.
It seems like everything is ok in the function getCurrentSegmentWordcount, but when that function calls word_count, it crashes (segmentation fault) at the line printf("sizeof Buff: %d", sizeof(buff));.
#define _GNU_SOURCE
#include <pthread.h>
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
#include <unistd.h>
#define NUMBER_OF_THREADS 10
//struct taken from reference:
struct return_val{
char wordlist[100][100]; //[chars][lines]
int count[100];
} *arr; //array of words
void *print_hello_world(void * tid)
{
//This function prints the thread’s identifier and then exits.
printf("Hello World. Greetings from thread %d\n", tid);
pthread_exit(NULL);
}
void *word_count(void* num)
{
int *ln = num;
unsigned int line_number = *ln;
//line_number++;
printf("Thread %d\n",line_number);
char cmd_p1[9] = "sed -n '\0";
char cmd_p2[2];
sprintf(cmd_p2,"%d",line_number); //stores string in buffer
char cmd_p3[21] = "p' 'maintainers.txt'\0";
char command[100];
command[0] = '\0';
//char * strcat ( char * destination, const char * source );
//appends a copy of source to destination
strcat(command,cmd_p1);
strcat(command,cmd_p2);
strcat(command,cmd_p3);
usleep(line_number);
char cmd[100] = " | tr [:space:] '\\n' | grep -v '^\\s*$' | sort | uniq -c | sort\0";
strcat(command,cmd);
printf("Command: %s\n",command);
//fflush(stdout);
FILE *in;
in= popen(command, "r"); //read command and pipe into the shell
rewind(in); //set file position to beginning of 'in'
char buff[50];
int counter = 0;
//char * fgets ( char * str, int num, FILE * stream );
//reads chars from stream and stores them as string into buff until all of buffer has been read
printf("before\n");
bool testBool = fgets(buff,sizeof(buff),in);
printf("testBool: %d\n", testBool);
//CRASH HAPPENS HERE:
//buff
printf("sizeof Buff: %d", sizeof(buff));
while(fgets(buff,sizeof(buff),in))
{
printf("fire 0.5");
char c=' ';
int i = 0;
int cnt = atoi(buff); //converts string to int.. buff == # of chars in file?
arr[line_number-1].count[counter] = cnt; //at this point line_number == 1
printf("fire1\n");
while(c!='\0')
{
c=buff[i];
buff[i]=buff[i+6];
i++;
}
int cnnt = 0;
while(c!=' ')
{
c = buff[cnnt];
cnnt++;
}
i=0;
while(c!='\0')
{
c=buff[i];
buff[i]=buff[i+cnnt];
i++;
}
sprintf(arr[line_number-1].wordlist[counter],"%s",buff);
printf("%d %s",arr[line_number-1].count[counter],arr[line_number-1].wordlist[counter]);
counter++;
}
printf("final count: %d", counter);
arr[line_number-1].count[counter] = -1;
fclose(in);
//pthread_exit(NULL); //didn't help to move here from getCurrentSegment...()
return NULL;
}
void *getCurrentSegmentWordcount(void * tid) { //declaring file pointer (value?)
int segment = tid;
segment = segment + 1; //converts to int
printf("segment/thread: %d \n", segment);
char text[1000];
//char buffer[150];
FILE *fp = fopen("words.txt", "r");
if(fp == NULL) {
printf("null file");
}
int i = 0;
long lSize;
char *buffer;
if( !fp ) perror("words.txt"),exit(1);
fseek( fp , 0L , SEEK_END);
lSize = ftell( fp );
rewind( fp );
buffer = calloc( 1, lSize+1 );
if( !buffer ) fclose(fp),fputs("memory alloc fails",stderr),exit(1);
if( 1!=fread( buffer , lSize, 1 , fp) )
fclose(fp),free(buffer),fputs("entire read fails",stderr),exit(1);
//printf(buffer);
char *token = strtok(buffer, "~");
if(segment == 1) {
printf("segment 1: %s", token);
word_count(&segment);
}
if(segment == 2) {
token = strtok(NULL,"~");
printf("segment 2: %s", token);
}
if(segment == 3) {
token = strtok(NULL,"~");
token = strtok(NULL,"~");
printf("segment 3: %s", token);
}
if(segment == 4) {
token = strtok(NULL,"~");
token = strtok(NULL,"~");
token = strtok(NULL,"~");
printf("segment 4: %s", token);
}
fclose(fp);
free(buffer);
//pthread_exit(NULL);//moving to end of word_count()
}
int main(int argc, char *argv[])
{
//The main program creates x threads and then exits.
pthread_t threads[NUMBER_OF_THREADS];
int status, i;
for(i=0; i < NUMBER_OF_THREADS; i++) {
printf("Main here. Creating thread %d\n", i+1);
status = pthread_create(&threads[i], NULL, getCurrentSegmentWordcount, (void * )i);
if (status != 0) {
printf("Oops. pthread create returned error code %d\n", status);
exit(-1);
}
}
sleep(8);
exit(NULL);
}
Output:
Main here. Creating thread 1
Main here. Creating thread 2
segment/thread: 1
Main here. Creating thread 3
segment 1: test(segment 1, handled my thread 1)
Thread 1
Main here. Creating thread 4
Command: sed -n '1p' 'maintainers.txt' | tr [:space:] '\n' | grep -v '^\s*$' | sort | uniq -c | sort
Main here. Creating thread 5
segment/thread: 2
before
segment/thread: 4
Main here. Creating thread 6
segment 4:
test test test test (segment 4, handled by thread 4)
Main here. Creating thread 7
segment 2:
test test (segment 2, handled by thread 2)
Main here. Creating thread 8
Main here. Creating thread 9
Main here. Creating thread 10
segment/thread: 3
segment 3:
test test test (segment 3, handled by thread 3)
segment/thread: 10
segment/thread: 9
segment/thread: 8
segment/thread: 5
segment/thread: 6
segment/thread: 7
testBool: 1
Makefile:20: recipe for target 'all' failed
make: *** [all] Segmentation fault (core dumped)
There are many issues with this code, some have been already mentioned by
user3629249, so I'll try to summarize the errors here.
Passing (void * )i for the argument for the thread is rather ugly. Sure it
works but this is for me sloppy programming, I'd declare an int array and fill
it with the id values and pass a pointer to the locations.
int ids[NUMBER_OF_THREADS];
for(i=0; i < NUMBER_OF_THREADS; i++) {
ids[i] = i+1;
status = pthread_create(&threads[i], NULL, getCurrentSegmentWordcount, ids + i);
...
}
and then in the thread function:
void *getCurrentSegmentWordcount(void * tid) { //declaring file pointer (value?)
int segment = *((int*) tid);
// segment = segment + 1; not needed anymore
...
}
This code is more clean, easier to understand for you and for the code reviewer,
does not relay on ugly unnecessary casts and is more portable.
Same thing with
void *print_hello_world(void *tid)
{
//This function prints the thread’s identifier and then exits.
printf("Hello World. Greetings from thread %d\n", tid);
pthread_exit(NULL);
}
This is uggly, you are trying to pass a pointer as an int. The size of a
pointer may not be the same as the size of an int. Using the same way of
passing a pointer to int (like for getCurrentSegmentWordcount):
void *print_hello_world(void *tid)
{
//This function prints the thread’s identifier and then exits.
printf("Hello World. Greetings from thread %d\n", *((int*) tid));
pthread_exit(NULL);
}
Write error messages to stderr. This FILE buffer is opened for that reason,
that's what people expect from programs to do. When you execute a program, you
can do this:
$ program 2>/tmp/error.log
or this
$ program 2>/dev/null | some_other_tool
so that you can separate the normal output from the error outputs.
And when a system function fails, the errno variable is set to the error code.
You can use perror for a standard error message or if you want a custom one,
use strerror:
pid_t p = fork();
if(p < 0)
{
perror("fork failed");
// or
fprintf(stderr, "Error while executing fork: %s\n", strerror(errno));
return; // or exit or whatever
}
You can write code in one line if you want to enter the C obfuscated contest,
otherwise don't do that. It's hard to read for you, it's hard to read for the
code reviewer/co-worker/superior. You gain nothing from it.
Instead of
if( !buffer ) fclose(fp),fputs("memory alloc fails",stderr),exit(1);
do
if(buffer == NULL)
{
fclose(fp);
fputs("memory alloc fails", stderr);
exit(EXIT_FAILURE); // or exit(your_exit_status)
}
It's easier to read for everyone.
You should always check the return value of functions that return a pointer.
Check the return value of malloc, calloc, realloc, strtok, etc.
if(segment == 2) {
token = strtok(NULL,"~");
printf("segment 2: %s", token);
}
If strtok returns NULL, then the printf line yields undefined behaviour.
See 3.5.3.3 comment 2:
3.5.3.3:
Synopsis
#define __STDC_WANT_LIB_EXT1__ 1
#include <stdio.h>
int printf_s(const char * restrict format, ...);
[...]
2 format shall not be a null pointer. The %n specifier (modified or not by flags, field width, or precision) shall not appear in the string pointed to by format. Any argument to printf_s corresponding to a %s specifier shall not be a null pointer.
[...]
4 The printf_s function is equivalent to the printf function except for the explicit runtime-constraints listed above.
Some libc implementation may forgive you to pass NULL to printf with %s
and print (null), but this is not portable and is undefined behaviour. So you
can only do the printf if token is not NULL.
The word_count function is a little bit horrible, specially how you construct
the commands.
char cmd_p1[9] = "sed -n '\0";
can be rewritten as
char cmd_p1[] = "sed -n '";
This will create a char array with the correct amount of bytes and initialize
it with a valid 0-terminated string, no need to add the '\0' yourself.
The commands that are the same, meaning that they don't need a value from a
variable can be store in a char[] or even in a const char*. Then construct
the whole thing with snprintf and sprintf, less lines, less mistakes:
void *word_count(void* num)
{
...
const char *pipe_cmd = "| tr [:space:] '\\n' | grep -v '^\\s*$' | sort | uniq -c | sort";
const char *format = "sed -n '%dp' 'maintainers.txt' %s";
int cmd_size = snprintf(NULL, 0, format, line_number, pipe_cmd);
char *command = malloc(cmd_size + 1);
if(command == NULL)
return NULL;
sprintf(command, format, line_number, pipe_cmd);
...
FILE *in;
in= popen(command, "r");
free(command);
...
}
Also note that
char cmd_p2[2];
sprintf(cmd_p2,"%d",line_number); //stores string in buffer
will overflow the buffer if the line number is greater than 9.
bool testBool = fgets(buff,sizeof(buff),in);
printf("testBool: %d\n", testBool);
fgets returns a pointer to char, not a bool. The printf will print the
value of a pointer as an integer. A pointer size is not necessarily the same as
an int size, in fact on my system a pointer is 8 bytes long, int is 4 bytes
long. You should do:
if(fgets(buff, sizeof(buff), in))
puts("fgets success");
//CRASH HAPPENS HERE:
//buff
printf("sizeof Buff: %d", sizeof(buff));
It won't crash because of the sizeof. sizeof is evaluated at compile time,
not at run-time.
The sizeof-operator returns a size_t.
%d is not the correct specifier for size_t, %lu is, it should be
printf("sizeof buff: %lu\n", sizeof buff);
It will most probably crash because of all the undefined behaviour before
this point.
arr[line_number-1].count[counter] = cnt;
In your whole code, arr is uninitialized, so you are accessing a value
through an uninitialized pointer. That's undefined behaviour and might lead to a
segfault.
I want to quote user3629249 here:
user3629249 wrote:
the main() function is starting several threads, then immediately exiting. The process of exiting also eliminates the threads Suggest: in main() calling pthread_join() for each thread. in the thread, at the end, call pthread_exit()
Please don't ignore compiler warnings, they are not there to annoy you, they are
there to help you. They are a hint that what you are doing may not be what you
really want. Undefined behaviour, segfaults etc. are often a consequence of
that. So heed warnings of the compiler and when you see one, look at your code,
try to understand it and fix it. If you don't understand the warning, you can
come here and ask a question about it. But having thousand of warning and
ignoring them will lead to headaches and quite franky a lot of wasted time on
your side and ours.
So, please fix all this warnings and details, look at the warning messages of
the compiler and the code might run without problems.

C read values from text file

I'm writing a c program to simulate FCFS scheduling algorithm. It will accept a command line argument as a file and calculate turnaround time and wait time for every process. However it can not read values from text file into variables successfully.
Here is the code
#include <stdio.h>
#define N 50
int main(int argc, char** argv)
{
int i = 0;
char line[20];
int n=0;
typedef struct
{
char name; //process name
int at; //arrive time
int pt; //process time
int ft; //finish time
int rt; //round time
int wt; //wait time
} Process;
Process pcs[N];
FILE* file = fopen( argv[1], "r");
while (fgets(line,sizeof(line),file) != NULL)
{
sscanf(line, "%s %d %d", pcs[i].name, pcs[i].at, pcs[i].pt);
line[strlen(line)-1] = '\0';
printf("%s %d %d\n",pcs[i].name, pcs[i].at, pcs[i].pt);
i++;
}
fclose(file);
pcs[0].ft=pcs[0].at+pcs[0].pt;
pcs[0].rt=pcs[0].ft-pcs[0].at;
pcs[0].wt=0;
for (n;n<4;n++)
{
if (pcs[n].at<pcs[n-1].ft)
{
pcs[n].ft=pcs[n-1].ft+pcs[n].pt;
pcs[n].rt=pcs[n].ft-pcs[n].at;
pcs[n].wt=pcs[n-1].ft-pcs[n].at;
}
else
{
pcs[n].ft=pcs[n].at+pcs[n].pt;
pcs[n].rt=pcs[n].ft-pcs[n].at;
pcs[n].wt=pcs[n-1].ft-pcs[n].at;
}
}
int x = 0;
for (x;x<n;x++)
{
printf("process name: %s", pcs[x].name);
printf("Turnaround Time: %d", pcs[x].rt);
printf("Wait Time: %d\n", pcs[x].wt);
}
return(0);
}
Here is the input file
And the output is
Thanks for any help and advice.
As pointed by alk, you're doing some mistakes:
In your struct declaration you have declared name as a single character, but in your file reading code(while loop containing fgets) you're passing %s which is for strings, so better change your declaration to a char name[SIZE] rather than char name. Bdw you should read the compiler warning and try to understand it, since that's what is creating problem.
You are supposed to pass address of variables in sscanf and it's variants, so change line 26 to:
sscanf(line, "%s %d %d", pcs[i].name, &pcs[i].at, &pcs[i].pt);

Debug Assertion Error in C

got some code here that won't compile correctly because it is saying that my pointer is already null when i am testing for a not null expression in my main function. here is the code :
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#define MAXCODE 53
#define MAXMESSAGE 256
void getCode(char *codeIn, char *filename) {
FILE *codeFile;
/* Open the file with the code */
codeFile = fopen(filename, "r");
if (codeFile == NULL) {
printf("Error opening the code file - program terminated\n");
exit(1);
}
/* Read the first (and assumed only) line from the file */
fgets(codeIn, MAXCODE, codeFile);
/* Terminate the string with /0 */
codeIn[MAXCODE] = '\0';
/* Close the file */
fclose(codeFile);
return;
}
int getMessage(int *message, char *filename) {
FILE *messageFile;
int counter = 0;
/* Open the file with the message */
messageFile = fopen(filename, "r");
if (messageFile == NULL) {
printf("Error opening the message file - program terminated\n");
exit(1);
}
/* Read one number at a time from the file and store it */
while (!feof (messageFile))
{
fscanf (messageFile, "%d", (message+counter));
counter++;
}
/* Close the file */
fclose(messageFile);
return (counter);
}
void sortMessage(int *message, int size) {
int i, j, temp;
for (i=0; i<size-1; i++) {
for (j=i; j<size; j++) {
if (message[i]>message[j]) {
temp = message[i];
message[i] = message[j];
message[j] = temp;
}
}
}
return;
}
void decodeMessage(char *codeIn, int *message, int size) {
FILE *outputFile;
int i = 0;
/* Open the output file */
outputFile = fopen("csis.txt", "w");
if (outputFile == NULL) {
printf("Error opening the output file - program terminated\n");
exit(1);
}
for (i=0; i< size; i++) {
fprintf(outputFile, "%c", codeIn[message[i]%100]);
printf("%c", codeIn[message[i]%100]);
}
printf("\n");
/* Close the file */
fclose(outputFile);
return;
}
int main(int argc, char *argv[])
{
char code[MAXCODE];
int msg[MAXMESSAGE];
int msgSize;
if (argc != 3) {
printf("This program takes two arguments: the name of the file with the code, and the name of the file with the encoded message\n");
}
getCode(code, argv[1]);
msgSize = getMessage(msg, argv[2]);
sortMessage(msg, msgSize);
decodeMessage(code, msg, msgSize);
return;
}
So basically my code is using two files called codefile.txt and msgfile.txt to decode the secret message and write the decoded sequence to a new text file called csis.
As woolstar pointed out in the comments, you don't need to NUL terminate your codeIn array following fgets, because fgets will do that for you. In fact, this constitutes an overflow which we can best see by considering what happens when MAXCODE is 1: codeIn contains only one element: codeIn[0], and accessing codeIn[1] is an error.
Similarly, since MAXCODE is 53 and that's how many elements pointed to by codeIn, codeIn[message[i]%100] is suspicious because there's a potential for message[i]%100 to be an invalid index. While we're on this note, it might be wise to make message[i] an unsigned int so that it can't be negative. The format specifier (for printf and scanf) corresponding to unsigned int is %u.
while ( !feof(messageFile) ) is wrong because the EOF flag isn't set until an attempt is made at reading. Between attempting to read and your EOF test, however, you've incremented counter which means you've counted one too many items. Perhaps your loop should look like this:
while (fscanf(messageFile, "%d", (message+counter)) == 1)
{
counter++;
}
Note that this code assumes you've chosen to keep message[i] as an int. If you've chosen to use unsigned int instead, of course you'll want to use the %u format specifier.
You can probably see that feof is mostly superfluous... You can usually test for erroneous reads by checking the return value. Try to avoid feof in the future.
Your main function has a return type of int, yet at the end of it you have a return; statement which doesn't return an int value. Remove that. It's probably causing errors during compilation.
Presumably, when argv != 3 you want to return from main so you don't end up processing invalid arguments... Make sure you return an int value, e.g.
if (argc != 3) {
printf("This program takes two arguments: the name of the file with the code, and the name of the file with the encoded message\n");
return 0;
}

Accessing a global Array causes a segmentation fault

I am trying to do an assignment in which I am to use multiple threads to sort input from a file, but when I try to use the array of structs to store the information I need to recover after the threads, I get a segmentation fault. I am not sure why it is causing the fault, as according to the sources I have.
This is the main file, Threads.c The seg fault is in the for loop, and the causing line is desginated by a comment. Sort Method is another function I did not in
#include "threads.h"
Threads* threadArray[4];
int linesPerThread;
int extraLines;
main(int argc, char *argv[]){
int n;
if( argc != 4){
printf("Wrong Number of Arguements!\n");
return;
}
n = atoi(argv[1]);
char *inName = argv[2];
*threadArray = (Threads*) (*threadArray, n*sizeof(Threads));
FILE* file = fopen(inName, "r");
if(!file){
printf("invalid file Name \n");
return;}
int lines = 0;
char xyz[5000]; //makes fgets happy
while(fgets(xyz, 5000, file) != NULL){
lines = lines+1;
}
fclose(file);
linesPerThread = lines / n;
extraLines = lines - linesPerThread;
int i =0;
int methodCounter =1;
printf("Right before Loop \n \n");
for(i; i < n; i++){
printf("first part of loop \n");
\\The ling below here Seg Faults.
(*threadArray + i)->id = i;
printf("right after first ThreadArray access \n");
if(methodCounter < 3){
printf("method counter 1\n");
(*threadArray+i)->methodID = methodCounter;
methodCounter++;
}else{
printf("method counter condition 2 \n");
(*threadArray + i)->methodID = 3;
methodCounter = 1;}
if(extraLines > 0){
printf("extra Lines condition 1 \n");
(*threadArray+i)->lines = linesPerThread +1;
extraLines= extraLines -1;
}else{
printf("extraLines condition 2 \n");
(*threadArray+i)->lines = linesPerThread;
}
printf("Right before Thread Creation \n \n");
pthread_t tID;
pthread_create(&tID, NULL, sortMethod, (void*) &((*threadArray+i)->id));
(*threadArray+i)->threadID = tID;
printf("right after thread creation \n \n");
}
printf("right after loop \n \n");
int c=0;
printf("before thread joining \n");
for(c; c< n; c++){
pthread_join( (*threadArray+ c)->threadID, NULL);
}
}
And this is the header file, Threads.h
#include <sys/time.h>
#include <stdio.h>
#include <pthread.h>
#include <stdlib.h>
#include <string.h>
typedef struct{
int id;
int lines;
pthread_t threadID;
int methodID;
}Threads;
void* sortMethod(void*ptr);
int main(int argc, char *argv[]);
Any help you can offer would be greatly appreciated.
In the line
*threadArray = (Threads*) (*threadArray, n*sizeof(Threads));
you are setting threadArray[0] to (Threads*)(n*sizeof(Threads). You probably want a realloc or a calloc in that line.
As it stands,
(*threadArray, n*sizeof(Threads))
is a comma-expression, and the value of that comma-expression is cast to Threads*.
Since you never allocated memory to any of the elements of threadArray,
(*threadArray + i)->id = i;
dereferences invalid pointers. Since the array is static, the pointers are originally initialised to null pointers, you only set threadArray[0] to a different value (but that doesn't point to valid memory either, in all probability).

Resources