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 have an unused variable in my function. If I remove it, the program crashes. I'm having trouble understanding why. I assume its because I'm accessing out of bounds for dataArr.
For definitions:
userFile is an argv input text file to be read
dataArr is the lines of that text file, stored into a string array.
n[80] was a previously used array of pointers that stored individual values (wrote it into a different function)
strdup duplicates the string (non-standard library)
If it helps, switching the value of n[80] to n[20] gives errors, but n[21] does not.
char ** read_file(char * userFile)
{
char * n[80]; // DO NOT REMOVE THIS LINE UNDER ANY CIRCUMSTANCES. IT IS BLACK VOODOO MAGIC.
char currLine[256];
char * dataArr[80];
char * eof;
int lineCount = 0;
int i = 0;
int j = 0;
FILE * fp;
fp = fopen(userFile, "r");
while((eof = fgets(currLine, sizeof(currLine), fp)) != NULL)
/* Stores the file into an array */
{
if (fp == NULL)
{
fprintf(stderr, "Can't open input file in.list!\n");
exit(1);
}
dataArr[i] = strdup(eof);
i++;
}
return dataArr;
}
EDIT:
I call the function using
dataArr = read_file(argv[1]);
I have a bad habit of using the same variable name for functions.
This happens because the array allocates memory and modifies the way your program is stored.
You cause Undefined Behavior when you do:
return dataArr;
since this array is a local variable:
char * dataArr[80];
thus it will go out of scope when the function terminates. That means that when the caller tries to use it, it will be most likely have gone out of scope.
By the way, you first read the file and then check if it opened. You should it like this instead:
fp = fopen(userFile, "r");
if (fp == NULL)
{
fprintf(stderr, "Can't open input file in.list!\n");
exit(1);
}
while((eof = fgets(currLine, sizeof(currLine), fp)) != NULL) {
...
This line:
return dataArr;
will cause undefined behaviour which is among the worst problems you can face. The reason why this is so bad is that very often it is hard to pinpoint. UD very often manifests itself in strange ways like this.
This has absolutely nothing to do with char * n[80] at all.
In short, UD means that anything can happen. See this link for more info: Undefined, unspecified and implementation-defined behavior
Related
Closed. This question is opinion-based. It is not currently accepting answers.
Want to improve this question? Update the question so it can be answered with facts and citations by editing this post.
Closed 2 years ago.
Improve this question
What is best practice when dealing with functions which return malloc'd pointers to C-strings?
Here's an example:
FILE *f;
char *tmp;
for (i = 0; i <= 10; i++) {
tmp = concat(fn, i);
f = fopen(tmp, "w");
free(tmp);
// read f, do something useful ...
fclose(f);
}
char* concat(char *a, int b) returns a pointer to a new C-string which contains the concatenation of a and b.
Not only do I have to specify a temporary pointer which is then passed to fopen, I also have to free(tmp) every time. I would rather prefer something like this:
FILE *f;
char *tmp;
for (i = 0; i <= 10; i++) {
f = fopen(concat(fn, i), "w");
// read f, do something useful ...
fclose(f);
}
But this of course leads to memory leaks. So what is best practice here? Something like concat(char *a, int b, char *result) where result is expected to be a pre-allocated memory for the resulting C-string? This solution has its disadvantages like limited or not optimal size of result.
A more solid design:
FILE *open_file_number(const char *str, int number)
{
size_t size = strlen(str) + 32;
char *path = malloc(size);
if (path == NULL)
{
return NULL;
}
snprintf(path, size, "%s%d", str, number);
FILE *file = fopen(path, "w");
free(path);
return file;
}
for (i = 0; i <= 10; i++)
{
FILE *file = open_file_number(some_path, i);
if (file != NULL)
{
// Do your stuff
fclose(file);
}
}
Both approaches are used in the industry. In your example, people could make an assumption about the maximum size for the resulting filename and use a local array this way:
for (int i = 0; i <= 10; i++) {
char filename[1024];
snprintf(filename, sizeof filename, "%s%d", fn. i);
FILE *f = fopen(filename, "w");
if (f != NULL) {
// read f, do something useful ...
fclose(f);
} else {
// report the error?
}
}
Note that the truncation can be detected with if (snprintf(filename, sizeof filename, "%s%d", fn. i) >= (int)sizeof filename).
If no assumption should be made about the filename length or if the filename composition method is more complicated, returning an allocated string may be a more appropriate option, but testing for memory allocation errors should also be done:
for (int i = 0; i <= 10; i++) {
char *filename = concat(fn, i);
if (filename == NULL) {
/* handle the error */
...
// break / continue / return -1 / exit(1) ...
}
FILE *f = fopen(filename, "w");
if (f == NULL) {
/* report this error, using `filename` for an informative message */
} else {
// read f, do something useful...
// keep `filename` available for other reporting
fclose(f);
}
free(filename);
}
If you are not ready to perform all this bookkeeping, you should probably use a different language with more elaborate object life cycle management or with a garbage collector.
Finally, using C99 compound literals, you could define concat to fit your simplified use case:
char *concat(char *dest, const char *s, int b) {
sprintf(dest, "%s%d", s, b);
return dest;
}
#define CONCAT(a, b) concat((char[strlen(a) + 24]){""}, a, b)
CONCAT defines an unnamed local variable length char array of the appropriate size and constructs the concatenation of string a and int b into it. I changed the case to uppercase to underscore the fact that a is evaluated twice in the expansion, and thus should not be an expression that involve side-effects.
You could use this macro as expected in your second code fragment:
FILE *f;
char *tmp;
for (i = 0; i <= 10; i++) {
f = fopen(CONCAT(fn, i), "w");
// read f, do something useful ...
fclose(f);
}
I probably would not recommend this type of usage, but this is only my opinion.
What is best practice when dealing with functions which return malloc'd pointers to C-strings?
Best practice: don't use them. A library expecting the caller to free returned data is almost certainly badly designed, with very few exceptions. We know this from 40 years of C language history, where crappily written libraries have created millions upon millions of memory leak bugs.
The basic rule of sane, useful library API design is:
Whoever allocates something is responsible for cleaning up their own mess.
Since C doesn't have RAII or constructors/destructors, that unfortunately means that the sane library needs to provide you with a function for the clean-up and you need to remember to call it. If it doesn't provide such a function, you might want to consider writing wrapper functions that do this - correcting the bad library design for them.
If you are the one implementing the library, you should always try to leave memory allocation to the caller, whenever possible. This is traditionally done by the function taking a pointer to a buffer which it writes to. Then either leaves it to the caller to allocate enough memory (like strcpy/strcat), or alternatively provide a variable with maximum buffer size, after which the function returns how much of the buffer it actually used (like fgets).
In your example, a soundly designed concat would perhaps look like
const char* concat (char* restrict dst, const char* restrict src, int i);
Where src is the source string, i is the integer to add and dst is a large-enough buffer provided by the caller. Optionally, the function returns a pointer equivalent to dst, for convenience. The above also implements proper const correctness plus a micro-optimization with restrict that means that the pointers passed aren't allowed to overlap.
Usage:
char buf [LARGE_ENOUGH];
fp = fopen(concat(buf, foo, i), "w");
Your first code snippet, where you save the returned pointer and free it when you're done using it, is the proper way to work with a function returning malloc'ed memory.
There are several POSIX functions, such as strdup and getline, that work in this manner, so this is a well known idiom.
Alternatives are:
Return a pointer to a static buffer. This has the disadvantage that it is not thread safe and also can't be called twice in one expression.
Accept a pointer to a properly sized buffer, in which case properly sizing the buffer is up to the caller.
If you know the maximum size of your strings, you could also do something like this:
char* concat_(char* buf, size_t s, char *a, int b)
{
/* ... your code ... */
return buf;
}
#define concat(a, b) concat_((char[100]){""}, 100, (a), (b))
The macro allocates an unnamed local variable and passes it on to the concat_ function. This function can then do whatever it did before, and just return the pointer to that same object. No malloc, no free, no worries (other than possibly blowing up your stack, if you make the buffer too big).
Edit:
Please note that, as Gerhardh pointed out in the comments, this creates a local object (which has automatic storage duration), so the pointer returned by the macro is only valid within the same block where that macro was actually called. Therefore you can't for instance use that pointer as a return value of the functoin which called the macro.
Closed. This question does not meet Stack Overflow guidelines. It is not currently accepting answers.
Closed 3 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 was caused by a typo or a problem that can no longer be reproduced. While similar questions may be on-topic here, this one was resolved in a way less likely to help future readers.
Improve this question
i got this warning " assignment makes pointer from integer without a cast "
(MARKED IN CODE PIECE) the code works fine, what i'm doing wrong and how can i fix this warning? thanx
void Read_Keys(char *keys[MAX_LEN]) //Read the keys from input file
{
char c,Fname[MAX_LEN];
gets(Fname);
FILE *fptr = (fopen(Fname, "r")); // Input stream pointer assume
if(fptr == NULL)
{
printf("No Such File...");
exit(EXIT_FAILURE);
}
if(fptr) //if not empty get in
{
int i = 0;
while((c = getc(fptr)) != EOF) //while loop copies each char from file
{ //to keys array
** keys[i] = c; // ** WARNING IS HERE
i++;
}
keys[i+1] = END; //ending point assume
}
fclose(fptr); //Close file for security issues
} ```
The parameter keys is declared like
char *keys[MAX_LEN]
the compiler adjusts it to the following declaration
char **keys
So in this statement
keys[i] = c;
the left operand has the type char * that is it is a pointer while the right operand has the type char.
So the compiler issues a warning because this assignment does not make sense.
I suspect that in any case the parameter is declared incorrectly. It seems you mean the following declaration
void Read_Keys(char ( *keys )[MAX_LEN]);
that is you are trying to pass a two dimensional array to the function. But in any case this code snippet
int i = 0;
while((c = getc(fptr)) != EOF) //while loop copies each char from file
{ //to keys array
keys[i] = c; // ** WARNING IS HERE
i++;
}
keys[i+1] = END; //ending point assume
}
is invalid because it trues to write all the file in one record instead of an array of records.
You keys parameter is an array of MAX_LEN pointers to char. So, if you want to assign a value inside this array, it should be a pointer to a character type. Here, getc() returns a character, not a pointer.
I think what you expect is void Read_Keys(char *keys), with the following calling code:
char keys[MAX_LEN];
Read_Keys(keys);
Thus, your keys array is decayed into a char * pointer when Read_Keys is called. Inside Read_Keys, you can access all your array elements using an index, like keys[2].
Obviously, you also need to pass you array length to Read_Keys, so the function knows which array index is valid and which one is not.
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 5 years ago.
Improve this question
Currently I have the following code below. char **arr is initially set to NULL. then it stores in words while reading from a file. I just randomly chose a large number like 5000 because I don't understand how to do malloc business properly, even after looking online and trying to learn.
Also, when I try to free char **arr (the last section of my code), sometimes I get segmentation faults, sometimes abort traps, etc. If someone could show me how to do something like this properly that would be highly appreciated! Thanks!
char **arr = NULL
File *fp = fopen("file.txt", "r")
char string[3000];
char counter = 0;
//to store
while(fscanf(fp, "%s", string)!=EOF){
arr = realloc(arr, 5000); //arbitrarily used a large number like 5000
arr[counter] = malloc(5000);
strcpy(arr[counter++], string);
}
//to free
for(i=0; i<counter; i++){
free(arr[i])
}
free(arr);
Don't use arbitrary numbers.
The size argument passed to realloc is the new number of bytes to allocate. In your case it could be (counter + 1) * sizeof(char *) bytes. If the file contains more than around a thousand words then 5000 will not be enough. Not to mention you call realloc to not change the size after the first call.
And don't use arbitrary values for the malloc call either. Either use strlen(string) + 1, or if available then you could use strdup instead.
Lastly, don't reassign back to the variable you pass as pointer to realloc. If realloc fails and returns NULL you will have lost your original pointer.
Instead use a temporary variable that you check before assigning backt o the original pointer variable:
char **temp = realloc(arr, ...);
if (temp == NULL)
{
// ERRORO: Do something appropriate
}
arr = temp;
Check the manual of getline(), this function allocate the line for you if the * is NULL. Use this function could be a proper way to do it instead of using strlen and fscanf.
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
+I'm trying to pass from the main an array of CustomStruct by reference, but im doing something wrong:
I think i'm asking correctly for memory, but it doesn't seem so, because when i try to force some values, i get core dumped and i absolutely don't know why.
void readFile(OwnStruct **restaurant){
FILE *f;
int numTaules = 0;
f = fopen("hello.txt", "r");
if(f == NULL){
printf("Error at opening!\n");
exit(0);
}
fscanf(f,"%d",&numTaules);
//Asking for memory
*restaurant = (OwnStruct*)malloc(sizeof(OwnStruct) * numTaules);
//From here, at some point: Core Dumped
restaurant[0]->ocupades = 1;
restaurant[0]->disponibles = 2;
restaurant[1]->ocupades = 3;
restaurant[1]->disponibles = 4;
printf("%d\n",restaurant[0]->ocupades);
printf("%d\n",restaurant[0]->disponibles);
printf("%d\n",restaurant[1]->ocupades);
printf("%d\n",restaurant[1]->disponibles);
}
int main(){
typedef struct(){
int ocupades;
int disponibles;
}
OwnStruct *restaurant;
readFile(&restaurant);
return 0;
}
You are referencing the array wrong:
So far so good:
*restaurant = (OwnStruct*)malloc(sizeof(OwnStruct) * numTaules);
This is wrong:
restaurant[0]->ocupades = 1;
It should be:
(*restaurant)[0].ocupades = 1;
You must dereference the pointer to your pointer. That expression then points to the first element of the allocated array. The parentheses are needed, because postfix operators like EXPR[0] take precedence over unary operators like *EXPR, so *EXPR[0] is treated as *(EXPR[0]).
Suggestion: Work with a local pointer which is just Ownstruct *ptr. Then, just before returning from the function, store that pointer:
*restaurant = ptr;
Then you can just have ptr[0]->field = value type code in your function.
Your problem is that your function
void readFile(char fileName[], OwnStruct **restaurant)
expects two parameter, but you pass just one.
readFile(&restaurant);
Just write
readFile("myFile.txt", &restaurant);
or define your function as
void readFile(OwnStruct **restaurant)
The example you give should not currently compile - readFile expects a filename and a pointer to a pointer of OwnStruct. Your main is just providing the pointer.
The struct should defined somewhere at the top (before its use in main and readFile)
readFile is also reading numTauls from a file but then assuming it is at least 2 when assigning values to the allocated memory.
So i need help returning a pointer of string arrays from a function obtained from a file. The strings being no larger than 10.
Input file:
3
102
A3B
50
The first number being how many strings I need, the following numbers being what I need to store in the strings.
The function:
char ** buildArray(){
int x, i;
fscanf(fp, "%d", &x);
char answer[x][10];
for(i=0; i<x; i++){
fscanf(fp, "%s", answer[i]);
}
return answer;
}
I can get the values to be stored on the string array 'answer' properly, i just cant return it properly.
Main Function:
int main() {
char * answers;
fp = fopen("data.txt", "r");
if(fp == NULL){
printf("Could not find file.\n");
exit(EXIT_FAILURE);
}
answers = buildAnsArray();
printf("%s", answer[1]); //used as a test to see if i passed the array of strings correctly
fclose(fp);
return 0;
}
in the main function when i try and print a value it just ends up crashing, or printing weird symbols
Assuming this is some flavor of C, you are trying to return a pointer to a variable, answer, which was automatically allocated inside a function, which means it gets automatically deallocated when you exit that function. So either create answer outside of this function and pass it in to be filled, or allocate the space for it explicitly so it can live once the function returns.
As #Scott Hunter pointed out, when you exit the function buildArray, answer goes out of scope, and the memory it occupied is free to be used by another variable. If you want to allocate the memory within buildArray, then you will need to use malloc. A starting point would be:
char *answer;
answer = malloc(x * 10 * sizeof(*answer));
But, using malloc does require you to pay attention to memory and manage it appropriately. This means:
1) Checking that malloc was successful in allocating memory. If it fails it returns Null, so you can add
if(answer == NULL){
//Error Code here
}
2) Freeing the memory when you are done. This should also be done safely. I would suggest the following just before fclose
if(answer != NULL)
{
free(answer);
}
3) Performing your own handling the double indexing yourself. This means that answer[i] becomes either answer + i*10 or &(answer[i*10])
Also, not related to your question, but important to notice:
1) You have a type mismatch between your definition char *answer in main and returning a char** from buildArray. Turning on -Wall and -Wextra on your compiler should warn you about these types of things. And you should try to clean up all of the warnings that are generated. They tend to mean that you either made a subtle mistake, or are using a bad coding practice that you should get out of the habit of, before it creates a major debugging headache.
2) You appear to be using fp as a global variable. You should be trying to avoid global variables as much as possible. There may be times when they are necessary, but you should think about that long and hard before comitting to it.
3) You (correctly) checked that fopen was successful. But, you didn't check that fscanf was successful. You should get in this habit as a failed read from file won't automatically generate a runtime error. You will just get strange results when it uses whatever bits were already in memory for your logic later on.
sample code
#include <stdio.h>
#include <stdlib.h>
#define STRING_SIZE 10
#define S_(x) #x
#define S(x) S_(x)
char (*buildAnsArray(FILE *fp))[STRING_SIZE+1]{
int x, i;
char (*answer)[STRING_SIZE+1];
fscanf(fp, "%d", &x);
answer = malloc(x * sizeof(*answer));
for(i=0; i<x; i++){
fscanf(fp, "%" S(STRING_SIZE) "s", answer[i]);//fscanf(fp, "%10s", answer[i]);
}
return answer;
}
int main(void) {
char (*answers)[STRING_SIZE+1];
FILE *fp = fopen("data.txt", "r");//error proc omit
answers = buildAnsArray(fp);
printf("%s\n", answers[1]);//A3B
fclose(fp);
free(answers);
return 0;
}