I need to pass a char pointer and filename per reference, and allocate a size for the pointer in that same function. (in the program it reads the size it needs to allocate from the file).
I created the file and also checked it in a hex editor, and it does exist.
I have tried to run it on GCC and Cygwin, it doesn't seem to be a compiler specific problem.
The following code is just the barebones, but still contains the same error:
GDB tells me it's a segfault caused by the file not existing. ("No such file or directory").
Where did I go wrong?
#include <stdlib.h>
#include <stdio.h>
#include <string.h>
#define SIZE 50
#define NAME "name"
int loadFile(char** board, char* filename);
int main(int argc, char const *argv[])
{
char* board;
char* filename = NAME;
loadFile(&board, filename);
board[49] = '\0';
return 0;
}
int loadFile(char** board, char* filename)
{
FILE* source = fopen(filename, "rb");
if(source == NULL)
{
printf("Error loading file.\n");
return -1;
}
*board = malloc(SIZE);
if(fread(*board, sizeof(char), SIZE, source) != SIZE)
{
fclose(source);
printf("Error loading file.\n");
return -2;
}
return 0;
}
Following many comments with suggestions, I have seen strange things when a constant char literal is passed:
#define NAME "name"
char* filename = NAME;
This assigns a pointer to a constant char literal to filename. Please try:
#define NAME "name"
char filename[] = NAME;
Check your status values:
rv = loadFile(&board, filename);
if (rv == -1) {
perror("Error opening file");
return 1;
}
This should (hopefully) give you an error message you can troubleshoot further. Using a const char * as an argument to fopen() should be OK.
Related
I'm using the following code below and I'm receiving a Thread 1: EXC_BAD_ACCESS (code=1, address=0x68) error. What are some ways I can execute this better? I'm simply loading a txt file that has roughly 500000 numbers and they are each on a new line. I've looked at a few resources how to do this, but I end up with these oddities. I'm hoping a c guru can help me out.
#include <stdio.h>
#include <time.h>
#include <limits.h>
#include <math.h>
#include <stdlib.h>
#include <string.h>
#define COUNT_ARRAY_LENGTH 10
#define MAX_NUMBER 500001
int *load_file(){
FILE *file;
file = fopen("somefile.txt", "r");
int a[MAX_NUMBER];
int i=0;
int num;
while(fscanf(file, "%d", &num) > 0) {
a[i] = num;
i++;
}
fclose(file);
return a;
}
int main(int argc, const char *argv[])
{
int *a;
a = load_file();
for(int i = 0; i < MAX_NUMBER; i++){
printf("%d\n", a[i]);
}
return 0;
}
Converting comments into an answer.
My immediate guess would be that you're failing to open the file — an error you don't check for and must always check for. Files go AWOL, or the program is run from the wrong directory, or they have the wrong permissions.
if (file == NULL)
{
fprintf(stderr, "Failed to open file '%' for reading\n", "somefile.txt");
exit(EXIT_FAILURE);
}
The repeated literal for the file name shows why you should never pass a string literal as the file name to fopen(); you should have a variable so that you can report the file name in the error message too, without repeating yourself.
const char *filename = "somefile.txt";
if ((file = fopen(filename, "r")) == NULL)
{
fprintf(stderr, "Failed to open file '%' for reading\n", filename); n.
exit(EXIT_FAILURE);
}
In fact, you should probably pass the name of the file to be loaded to the load_file() function so that you can more easily change it (by command line arguments, for example). That is as well as passing the array, and the size of the array. That gives you a more generic function, one more easily adapted to other uses.
You could also #include <errno.h> and #include <string.h> and use strerror(errno) to print the system error message to give more help to the user (but knowing the file name is a huge step in the right direction).
Also, you should have while (i < MAX_NUMBER && fscanf(file, "%d", &num) > 0) so you don't overflow the array.
Also, you're returning the address of the local array in load_file() — you can't do that safely. Define the array in main() and pass the pointer as a parameter. Your main() also assumes that the array was filled. Revise load_file() to return how many numbers were loaded so you don't access unloaded numbers.
Putting all those changes together might yield:
#include <stdio.h>
#include <stdlib.h>
#define MAX_NUMBER 500001
static size_t load_file(const char *filename, size_t arrsiz, int *array)
{
FILE *file;
if ((file = fopen(filename, "r")) == NULL)
{
fprintf(stderr, "Failed to open file '%s' for reading\n", filename);
exit(EXIT_FAILURE);
}
size_t i = 0;
int num;
while (i < arrsiz && fscanf(file, "%d", &num) > 0)
array[i++] = num;
fclose(file);
return i;
}
int main(void)
{
int a[MAX_NUMBER];
size_t num = load_file("somefile.txt", MAX_NUMBER, a);
for (size_t i = 0; i < num; i++)
printf("%d\n", a[i]);
return 0;
}
That's been compiled but not run.
You could process a command-line argument like this:
int main(int argc, char **argv)
{
if (argc > 2)
{
fprintf(stderr, "Usage: %s [filename]\n", argv[0]);
exit(EXIT_FAILURE);
}
const char *filename = (argc == 2) ? argv[1] : "somefile.txt";
int a[MAX_NUMBER];
size_t num = load_file(filename, MAX_NUMBER, a);
for (size_t i = 0; i < num; i++)
printf("%d\n", a[i]);
return 0;
}
Or you could allow more than one argument and iterate over them all.
Sometimes, it's better to do the file opening and closing in the main() and pass the open file stream to the function. You can then read from stdin if there are no command-line arguments. The options are legion!
I am still very new to the c language and I am playing with reading files for the first time. I had similar code to this code which used to run perfectly fine but now I am running into issues. I keep getting the error Segmentation fault (core dumped) every time I try to run this program.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
struct student {
char first[30];
char last[30];
char ssn[9];
};
void make_arrays() {
FILE *fp = fopen("students.db", "r");
fseek(fp, 0, SEEK_END);
long size = ftell(fp);
fseek(fp, 0, SEEK_SET);
long num_students = size / sizeof(struct student);
printf("There are %ld students in the file", num_students);
fclose(fp);
}
int main(int argc, char **argv[]) {
make_arrays();
return 0;
}
The segmentation fault might be caused by fopen failing to open the file.
You should always test for such failures and exit with an informative message.
Also note that, if the file is indeed binary, it should be open in binary mode to avoid end of line translation:
FILE *fp = fopen("students.db", "rb");
Also change the prototype for main to int main(int argc, char *argv[]) or simply int main(). There are too many stars in char **argv[].
You don't have to mark my answer as accepted, just want to inspire people to write code so that it is readable and safe. Don't be lazy to write code like this where quality is a factor.
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#include <sys/stat.h>
struct student /* Magic numbers everywhere */
{
char first[30];
char last[30];
char ssn[9];
};
void* handle_nullptr_error (void* ptr, char *action, int code)
{
if(ptr == NULL)
{
fprintf(stderr, "Failed to %s\n", action);
exit(code);
}
printf("Succeeded to %s\n", action);
return ptr;
}
int handle_nonzero_error (int val, char *action, int code)
{
if(val != 0)
{
fprintf(stderr, "Failed to %s\n", action);
exit(code);
}
printf("Succeeded to %s\n", action);
return val;
}
int handle_negval_error (int val, char *action, int code)
{
if(val < 0)
{
fprintf(stderr, "Failed to %s\n", action);
exit(code);
}
printf("Succeeded to %s\n", action);
return val;
}
/** This function is not guaranteed to be portable and work (but it will at least fail properly),
* because not all systems and/or library implementations support `SEEK_END` in files
* opened in text mode, as specified by #mode
* Moreover, in binary mode it will behave in an undefined manner, because different systems
* may store files data completely differently. In most cases it will succeed, just don't
* write code that crashes if not.
*/
long int get_file_charcount (const char *filename, char* mode)
{
FILE* fp = NULL;
long int fpSize = 0L;
/* Alignment for complicated function calls (for e.g where functions are passed as arguments) */
fp = handle_nullptr_error (fopen(filename, mode), "open file.", 1);
(void)handle_nonzero_error (fseek(fp, 0, SEEK_END), "seek end position.", 2);
fpSize = handle_negval_error (ftell(fp), "tell position.", 3);
fclose(fp); /* - May fail, as well */
return fpSize;
}
/** This function depends on POSIX headers and it is unix-conformant, although there are still
* some exceptions.
*
* Note that the value returned is the length of the contents of the symbolic link,
* and does not count any trailing null pads. The value is ought to be system-specific.
*/
_off64_t get_file_size (const char *filename)
{
struct stat st = {0};
(void)handle_negval_error(stat(filename, &st), "get file size.", (-1));
return st.st_size;
}
/** A validation function should first determine whether file's size is
* actually dividable by `sizeof(struct STUDENT_DESCRIPTION);`.
*
* Further more you can use `get_file_size()` as an alternative to
* `get_file_charcount()`. In the latter case, make sure you to specify the
* appropriate mode, "r" for text files and "rb" for binary files.
*/
void make_arrays ()
{
long int size = get_file_charcount("myfile.txt", "r");
long int num_students = size / sizeof(struct STUDENT_DESCRIPTION);
printf("size of file: %ld\n", size);
printf("There are %ld students in the file", num_students);
}
int main (void)
{
make_arrays();
return EXIT_SUCCESS;
}
I have been playing around with file writing functions to study their properties in more detail, along with some other things as well (however what I was doing is ultimately irrelevant), and while I was doing that I encountered a segmentation fault. But not just the everyday type of segfault (dereferencing to unallocated space or something), the segfault is somehow caused by the declaration of a character array. In the code char name[10]. The declaration of char name[10] results in segmentation fault, and I do not understand why. Commenting this declaration removes the issue. What is going on here?
The code I wrote is given below:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <errno.h>
int main(int argc, char *argv[]){
//char name[10];
//strcpy(name, "George");
//printf("%s\n", name);
//if(argc == 2){
//char *myname = "George";
FILE *file = fopen("Readmystuff" , "rt");//fopen(argv[1],"rt");
if(file == NULL)
printf("Could not open file: %s\n", strerror(errno));
char *str, *cr;
int maxsize = 200;
cr = fgets(str, maxsize, file);
int fcl = fclose(file);
printf("\n");
int strl = strlen(str);
if(fcl == 0)
printf("File closed succesfully\ncr: %c\nstr: %s\nTotal string size - 1 (for null): %i\n", *cr, str, strl);
else
printf("File did not close");
//}
//else
//printf("There must be one argument, argv[1] = the filename, for the code to work\n");
return 0;
}
char *str, *cr;
/* ... */
cr = fgets(str, maxsize, file);
Your str pointer is not initialized, its value is indeterminate. You are writing to an invalid object. Either define an array with a sufficient size or use malloc to allocate one.
I am trying to read through the file given then tokenize it. The only problem im having is fgets.The file open recieves no errors. I have seen this elsewhere on the site however no matter how i set this up including setting fileLine to a set amount like (char fileline [200]) i get a segmentation fault. Thanks in advance for any help.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <fcntl.h>
#include <unistd.h>
int main(int argc, char *argv[]){
char *fileName = "0";
char *tokenize, *savePtr;
struct Record *database= malloc(sizeof(database[0]));
int recordNum =0;
char *fileLine = malloc(sizeof(char *));//have replaced with fileline[200] still didnt work
FILE *fd = open(fileName,O_RDWR);
if(fd< 0){
perror("ERROR OPENING FILE");
}
while(fgets(fileLine,200,fd) !=NULL){
printf("%s\n", fileLine);
tokenize = strtok_r(fileLine,",",&savePtr);
while(tokenize != NULL){
//TOKENIZING into a struct
}
}
Why use open() with FILE? Use fopen() instead.
#include <stdio.h>
#include <string.h>
int main(int argc, char *argv[]) {
char *fileName = "test.txt";
char *tokenize, *savePtr;
char fileLine[200] = {0}; // init this to be NULL terminated
FILE *fd = fopen(fileName, "r");
if (fd == 0) { // error check, equal to 0 as iharob said, not less than 0
perror("ERROR OPENING FILE");
return -1;
}
while (fgets(fileLine, 200, fd) != NULL) {
printf("%s\n", fileLine);
tokenize = strtok_r(fileLine, ",", &savePtr);
while (tokenize != NULL) {
tokenize = strtok_r(NULL, ",", &savePtr); // do not forget to pass NULL
//TOKENIZING into a struct
}
}
return 0;
}
As Weather Vane said, fd < 0 would work if you used open(). However, with fopen(), you should check to see if the pointer is NULL, ecquivalently fd == 0.
A comparison between this functions that open a file can be found in:
open and fopen function
C fopen vs open
The way I have it in mind is that fopen() is of higher level.
This line
char *fileLine = malloc(sizeof(char *));
allocates memory for a char * type, 4 or 8 bytes (depending on the platform).
So when you do
fgets(fileLine,200,fd)
it expects there to be 200 bytes of memory available.
Try this:
char *fileLine = malloc(200);
if (fileLine == NULL) { ... } // check for error
which will allocate the memory required.
You are using open() instead of fopen().
You can't be sure that the file did open correctly because fopen() does not return an integer, but a pointer to a FILE * object, on failure it returns NULL, so the right codition is
FILE *file;
file = fopen(filename, "r");
if (file == NULL)
{
perror("fopen()");
return -1;
}
In your code, you still go and use fgets() even when the fopen() fails, you should abort the program in that case.
Also, malloc() takes the number of bytes as the size parameter, so if you want fgets() to be limited to read just count bytes, then malloc() should be
char *buffer;
size_t count;
count = 200; /* or a value obtained someway */
buffer = malloc(count);
if (buffer == NULL)
{
fclose(file);
perror("malloc()");
return -1;
}
All the problems in your code would be pointed out by the compiler if you enable compilation warnings.
I wrote C program of searching string. The problem is MyStrstr() function doesn't work with
command prompt. It only works with IDE. So, can anyone advise me how to fix the code for working with command prompt. With regards...
#include <stdio.h>
#include <string.h>
#include <stdlib.h>
#define ARGUMENT_COUNT 3
#define FILE_INDEX 2
#define SEARCH_INDEX 1
#define BUFFER 256
#define SUCCESS 0
#define ERRCODE_PARAM 1
#define ERRCODE_FILENAME 2
#define MSG_USAGE "String Search Program === EXER5 === by Newbie\nUsage: %s Search_String fileName"
#define MSG_ERROR "Can not open file. [%s]"
char* MyStrstr(char* pszSearchString, char* pszSearchWord);
int main(int argc, char* argv[])
{
FILE* pFile = NULL;
char szData[BUFFER];
char* pszCutString = NULL;
if(argc != ARGUMENT_COUNT) {
printf(MSG_USAGE, argv[0]);
return ERRCODE_PARAM;
}
pFile = fopen(argv[FILE_INDEX], "r");
if(pFile == NULL) {
printf(MSG_ERROR, argv[FILE_INDEX]);
return ERRCODE_FILENAME;
}
pszCutString = MyStrstr(szData, argv[SEARCH_INDEX]);
if(pszCutString != NULL) {
printf("%s", pszCutString);
}
fclose(pFile);
pFile = NULL;
return SUCCESS;
}
char* MyStrstr(char* pszSearchString, char* pszSearchWord) {
int nFcount = 0;
int nScount = 0;
int nSearchLen = 0;
int nIndex = 0;
char* pszDelString = NULL;
char cSLen = 0;
size_t len = 0;
if(pszSearchString == NULL || pszSearchWord == NULL) {
return NULL;
}
while(pszSearchWord[nSearchLen] != '\0') {
nSearchLen++;
}
if(nSearchLen <= 0){
return pszSearchString;
}
cSLen = *pszSearchWord++;
if (!cSLen) {
return (char*) pszSearchString;
}
len = strlen(pszSearchWord);
do {
char cMLength;
do {
cMLength = *pszSearchString++;
if (!cMLength)
return (char *) 0;
} while (cMLength != cSLen);
} while (strncmp(pszSearchString, pszSearchWord, len) != 0);
return (char *) (pszSearchString - 1);
}
You want to open a file, search the contents of that file for a string and return/print that. You are instead doing:
char szData[256]; // <-- making an uninitialized buffer
char* pszCutString = NULL;
pFile = fopen(argv[2], "r"); // <-- Opening a file
pszCutString = MyStrstr(szData, argv[1]); // <-- searching the buffer
if(pszCutString != NULL) {
printf("%s", pszCutString);
}
fclose(pFile); // <-- Closing the file
So you never fill your buffer szData with the contents of the file noted in argv[2]. You're trying to search an uninitialized buffer for a string. You're luck the result is just "no output comes out".
You need to take the contents of the file in argv[2] and place it in the buffer szData then do the search. This could be accomplished by adding a call to a function like read() or fscanf()
Note 1:
I assume when you say this "worked" in the IDE, the code was a little different and you weren't using the command line arguments.
Note 2:
you should also check to fopen() worked before trying to read from/close pFile, and if your file is possibly larger than 256 characters you will need to change your code to either have a dynamically sized string, or you'll need to loop the buffer fills (but then you have to worry about breaking a word apart), or some other mechanism to check the full file.