When i'm using char* pilih(char teks[]) in the int main() function, it's working. But when I used this function in the new function, it said read access violation. Please help me
#include <stdio.h>
#include <time.h>
#include <stdlib.h>
#include <string.h>
#define MAXARR 1000
char *hilangkan(char[]);
char *pilih(char[]);
char *loadFile(FILE *sumber);
int main(){
FILE *sumber;
sumber=fopen("kumpulan.txt","r");
char *teks=loadFile(sumber);
char *pilihan=pilih(teks);
printf("%s",pilihan);
printf("%s",hilangkan(pilihan));
}
char *hilangkan(char teks[]){
char *penghilangan;
strcpy(penghilangan,teks);
int y=strlen(penghilangan);
srand(time(NULL));
int c=48;
for(int i=0;i<y;i++){
int hilang=rand()%y+1;
penghilangan[hilang]='_';
}
return penghilangan;
}
char *loadFile(FILE *sumber){
char *teks;
if (sumber == NULL) {
printf("ERROR!!!");
system("pause");
return 0;
}
char h;
int count=0;
while (h = fgetc(sumber) != EOF) {
teks[count] = h;
count++;
}
fclose(sumber);
return teks;
}
char *pilih(char teks[]){
char *hasil;
srand(time(NULL));
int w = rand() % 47 + 1;
char cek[3];
itoa(w, cek, 10);
char *c=strstr(teks, cek);
int lokasi = c - teks + 1;
int pan = strlen(cek);
int i;
if (pan == 2)i = -1;
else i = 0;
while (teks[lokasi]!='\n') {
hasil[i] = teks[lokasi];
i++;
lokasi++;
}
hasil[i] = NULL;
return hasil;
}
On while(teks[lokasi]!='\n') it says read violation access. teks was 0x1110113
Links are highly discouraged and expectation from you is that, you should post the whole program in your question.
From the part of code that you have posted and the error information shared, it seems that the argument passed to pilih() function is not valid which in turn makes teks pointer pointing to some invalid memory. Actual cause of problem can only be given after looking at minimal, complete and verifiable program depicting the problematic behavior.
One confirm problem in your pilih() function is that you are returning a local variable hasil from it. The scope and life of local variable hasil is limited to pilih() function and it is no more valid once pilih() function exits.
Also, this statement
hasil[i] = NULL;
is not correct. Variable hasil is array of char and hasil[i] is a character at index i. You are assigning NULL to it which is not valid. I think you wanted to do this:
hasil[i] = '\0';
EDIT:
The full code has been posted in the question. Hence editing my answer and pointing out the problems in the OP's code.
There are several issues in your code. If you are using gcc compiler, try compiling your code with "-Wall -Wextra" options and check the warnings messages given by the compiler.
In the function loadFile(), look at this statement:
while (h = fgetc(sumber) != EOF) {
First of all, the return type of fgetc() function is int and not char [the fgetc() return type is int to accommodate for the special value EOF]. In the operator precedence table, the operator != comes before =, so you will not get the read character assigned to h but the result of fgetc(sumber) != EOF will be assigned to h. This should be
while ((h = fgetc(sumber)) != EOF) { // check the parenthesis added
^ ^
In this statement:
teks[count] = h;
You are accessing a pointer which is not initialized. Any variable which is not initialized has indeterminate value and same is true for pointers. They can point to any random indeterminate address. There is no default behavior. Only behavior is indeterminate and using indeterminate values results in Undefined behavior.
You should allocate memory to teks before using it, like this:
teks = malloc(100 * sizeof (char)); //this will allocate memory for 100 characters.
if (teks == NULL)
exit(EXIT_FAILURE);
Looks like you want to store the whole file content in teks. Make sure to allocate enough memory to teks and if you are not sure about the size of memory required then realloc is your friend.
Also, after while loop, you should add the terminating null character at the end of the content stored in teks, like this:
teks[count] = '\0';
The same error of accessing uninitialized pointer exists in hilangkan() and pilih() function. Check the variable penghilangan and hasil respectively.
strstr() can return NULL pointer. You should add check for it:
char *c=strstr(teks, cek);
if (c == NULL)
return NULL; // Or whatever the way you want to handle this case
// but you should not use c
You should check the parameter value before using it in every function. If it is pointer, check whether it is NULL or not. If it is not NULL then only use it.
Also, make sure to free the dynamically allocated memory once you are done with it.
I don't what exactly you are trying to do but somewhere I feel that there is lot of scope of improvements in your code.
Hope this help.
Related
The user specifies the number of lines in the output in the arguments (as the size of the page in pagination), by pressing the key he gets the next lines. How it works now:
Let's say the user chose to receive 1 row at a time:
first string
first string
second string
first string
second string
third string
struct result {
char part[32768];
int is_end_of_file;
};
struct result readLines(int count) {
int lines_readed = 0;
struct result r;
if (count == 0) {
count = -1;
}
while (count != lines_readed) {
while (1) {
char sym[1];
sym[0] = (char) fgetc(file);
if (feof(file)) {
r.is_end_of_file = 1;
return r;
}
strcat(r.part, sym);
if (*"\n" == sym[0]) {
break;
}
}
lines_readed++;
}
return r;
}
int main(int argc, char *argv[]) {
file = fopen(argv[1], "r");
while (1) {
struct result res = readLines(atoi(argv[2]));
printf("%s", res.part);
if (res.is_end_of_file) {
printf("\nEnd of file!\n");
break;
}
getc(stdin);
}
closeFile();
return 0;
}
I know that when I define a struct in the readLines function, it is already filled with previous data. Forgive me if this is a dumb question, I'm a complete newbie to C.
I'm not sure what is the question here, however I'll do my best to address what I understand. I assume the problem lies somewhere around the "previous data" you mentioned in the title and in the comments to the question.
Let's first set an example program:
#include <stdio.h>
struct result {
char part[10];
};
int main (int argc, char *argv[]) {
struct result r;
printf(r.part);
return 0;
}
The variable r has a block scope, so it has automatic storage duration. Since it has automatic storage duration, and no initializer is provided, it is initialized to an indeterminate value (as mentioned by UnholySheep and n. 1.8e9-where's-my-share m. in the comments to the question). I don't yet get all the C intricacies, but based on this, I guess you cannot rely on what the value of r will be.
Now, in the comments to the question you try to understand how is it possible that you can access some data that was not written by the current invokation of your program. I cannot tell you exactly how is that possible, but I suspect it is rather platform-specific than C-specific. Maybe the following will help you:
What is Indeterminate value?
What happens to memory after free()?
Why memory isn't zero out from malloc?
Going further, in the line
printf(r.part);
first we try to access a member part of r, and then we call printf with the value of this member. Accessing a variable of an indeterminate value results in undefined behavior, according to this. So, in general, you cannot rely also on anything that happens after invoking r.part (it doesn't mean there is no way of knowing what will happen).
There is also another problem with this code. printf's first parameter is interpreted as having the type const char *, according to man 3 printf, but there is provided a variable that has the type struct result. Indeed, there is produced the following warning when the code is compiled with gcc with the option -Wformat-security:
warning: format not a string literal and no format arguments [-Wformat-security]
Unfortunately, I don't know C well enough to tell you what precisely is happening when you do such type mismatch in a function call. But as we know that there already happened undefined behavior in the code, this seems less important.
As a side note, a correct invokation of printf could be in this case:
printf("%p", (void *)r.part);
r.part is a pointer, therefore I use the %p conversion specifier, and cast the value to (void *).
This function is to split string based on \n and see if the row number is selected. If the row number matched, this string should be copied and used by other function:
void selectDeparment(char* departments, int selectedNum, char* selectedDepartment){
char* copyOfDepartments = malloc(strlen(departments)+1);
strcpy(copyOfDepartments,departments);
char* sav1 = NULL;
char* token = strtok_s(copyOfDepartments,"\n",&sav1);
int counter = 0;
while(token != NULL){
if(counter == selectedNum){
selectedDepartment = malloc(strlen(token)+1);
strcpy(selectedDepartment,token);
}
++counter;
token = strtok_s(NULL, "\n", &sav1);
}
}
This function is called in main like:
char* selectedDepartment;
selectDeparment(recordsPtr[0], 1, selectedDepartment);
printf(selectedDepartment);
recordsPtr[0] contains four strings with \n at the end:
aDeparment
anotherDepartment
newDepartment
otherDepartment
In C, we are encouraged to use pointer to get a value from function instead of returning a string from a function. However, the prinft in main function gives random output
I believe there is some confusion in the way you are using pointers here. Let me clarify.
In the main function, the character pointer selectedDepartment holds a certain memory in the computer. But when a function call is made to void selectDeparment(char* departments, int selectedNum, char* selectedDepartment), a new copy of selectedDepartment is created. Henceforth any changes which are made to selectedDepartment are done only at the scope of the called function and does not impact the original pointer in the main function.
Thus one clear way to solve this problem will be to pass a pointer to the character pointer defined in the main function. This will then give the correct/expected results.
Here is the modified version of the function -
void selectDeparment(char* departments, int selectedNum, char** selectedDepartment){
char* copyOfDepartments = malloc(strlen(departments)+1);
strcpy(copyOfDepartments,departments);
char* sav1 = NULL;
char* token = strtok_s(copyOfDepartments,"\n",&sav1);
int counter = 0;
while(token != NULL){
if(counter == selectedNum){
(*selectedDepartment) = malloc(strlen(token)+1);
strcpy(*selectedDepartment,token);
}
++counter;
token = strtok_s(NULL, "\n", &sav1);
}
}
And this is how it is called from the main function -
int main() {
char* recordsPtr[] = {"aDeparment\nanotherDepartment\nnewDepartment\notherDepartment"};
char* selectedDepartment;
selectDeparment(recordsPtr[0], 1, &selectedDepartment);
printf(selectedDepartment);
}
I think you are getting confused with the "A Pointer To What?" you are supposed to return. In your selectDeparment() function, if I understand what is needed, is you simply need to return a pointer to the correct department within recordsPTR. You do not need to allocate or tokenize to do that. You already have the index for the department. So simply change the return-type to char * and return departments[selectedNum];.
For example, you can whittle-down your example to:
#include <stdio.h>
char *selectDeparment (char **departments, int selectedNum){
return departments[selectedNum];
}
int main (void) {
char *selectedDepartment = NULL;
char *recordsPTR[] = { "aDepartment\n",
"anotherDepartment\n",
"newDepartment\n",
"otherDepartment\n" };
selectedDepartment = selectDeparment (recordsPTR, 1);
fputs (selectedDepartment, stdout);
}
Note: the '*' generally goes with the variable name and not the type. Why? Because:
int* a, b, c;
certainly does NOT declare three-pointers to int,
int *a, b, c;
makes clear that you have declared a single-pointer to int and two integers.
Example Use/Output
Running the example above you would have:
$ ./bin/selectedDept
anotherDepartment
You will want to add array bounds protection to ensure the index passed does not attempt to read past the array bounds. That is left to you.
If You Must Use void
If you must use a void type function, then you can pass the Address Of the pointer to the function so the function receives the original address for the pointer in main(). You can then assign the correct department to the original pointer address so the change is visible back in main(). When you pass the Address Of the pointer, it will require one additional level of indirection, e.g.
#include <stdio.h>
void selectDeparment (char **departments, int selectedNum, char **selectedDeparment) {
*selectedDeparment = departments[selectedNum];
}
int main (void) {
char *selectedDepartment = NULL;
char *recordsPTR[] = { "aDepartment\n",
"anotherDepartment\n",
"newDepartment\n",
"otherDepartment\n" };
selectDeparment (recordsPTR, 1, &selectedDepartment);
fputs (selectedDepartment, stdout);
}
(same result, same comment on adding array bounds protection)
Look this over and let me know if I filled in the missing pieces correctly. If not, just drop a comment and I'm happy to help further.
This question already has answers here:
Initializing a pointer in a separate function in C
(2 answers)
Closed 3 years ago.
My goal is to pass a pointer to double to a function, dynamically allocate memory inside of the function, fill resulted array with double values and return filled array. After lurking attentively everywhere in StackOverflow, I have found two related topics, namely Initializing a pointer in a separate function in C and C dynamically growing array. Accordingly, I have tried to write my own code. However, the result was not the same as it was described in aforementioned topics. This program was run using both gcc and Visual Studio.
First trial.
int main()
{
double *p;
int count = getArray(&p);
<...print content of p...>
return 0;
}
int getArray(double *p)
{
int count = 1;
while(1)
{
if(count == 1)
p = (double*)malloc(sizeof(double));
else
p = (double*)realloc(p, count*sizeof(double));
scanf("%lf", &p[count-1]);
<...some condition to break...>
count++;
{
<... print the content of p ...>
return count;
}
(Here comes the warning from compiler about incompatible argument type. Ignore it).
Input:
1.11
2.22
3.33
Output:
1.11
2.22
3.33
0.00
0.00
0.00
Second trial.
int main()
{
double *p;
int count = getArray(&p);
<...print content of p...>
return 0;
}
int getArray(double **p)
{
int count = 1;
while(1)
{
if(count == 1)
*p = (double*)malloc(sizeof(double));
else
{
double ** temp = (double*)realloc(*p, count*sizeof(double));
p = temp;
}
scanf("%lf", &(*p)[count-1]);
<...some condition to break...>
count++;
{
<... print the content of p ...>
return count;
}
Input:
1.11
2.22
Segmentation error.
I tried this method on several different *nix machines, it fails when the loop uses realloc. SURPRISINGLY, this code works perfect using Visual Studio.
My questions are: first code allows to allocate and reallocate the memory and even passes all this allocated memory to main(), however, all the values are zeroed. What is the problem? As for the second program, what is the reason of the segmentation error?
The right way of doing it is like this:
int getArray(double **p)
{
int count = 0;
while(1)
{
if(count == 0)
*p = malloc(sizeof(**p));
else
*p = realloc(*p, (count+1)*sizeof(**p));
scanf("%lf", &((*p)[count]));
<...some condition to break...>
count++;
{
<...print content of p...>
return count;
}
If you pass a pointer to a function and you want to change not only the value it is pointing at, but change the address it is pointing to you HAVE to use a double pointer. It is simply not possible otherwise.
And save yourself some trouble by using sizeof(var) instead of sizeof(type). If you write int *p; p = malloc(sizeof(int));, then you are writing the same thing (int) twice, which means that you can mess things up if they don't match, which is exactly what happened to you. This also makes it harder to change the code afterwards, because you need to change at multiple places. If you instead write int *p; p = malloc(sizeof(*p)); that risk is gone.
Plus, don't cast malloc. It's completely unnecessary.
One more thing you always should do when allocating (and reallocating) is to check if the allocation was successful. Like this:
if(count == 0)
*p = malloc(sizeof(**p));
else
*p = realloc(*p, (count+1)*sizeof(**p));
if(!p) { /* Handle error */ }
Also note that it is possible to reallocate a NULL pointer, so in this case the malloc is not necessary. Just use the realloc call only without the if statement. One thing worth mentioning is that if you want to be able to continue execution if the realloc fails, you should NOT assign p to the return value. If realloc fails, you will lose whatever you had before. Do like this instead:
int getArray(double **p)
{
int count = 0;
// If *p is not pointing to allocated memory or NULL, the behavior
// of realloc will be undefined.
*p = NULL;
while(1)
{
void *tmp = realloc(*p, (count+1)*sizeof(**p));
if(!tmp) {
fprintf(stderr, "Fail allocating");
exit(EXIT_FAILURE);
}
*p = tmp;
// I prefer fgets and sscanf. Makes it easier to avoid problems
// with remaining characters in stdin and it makes debugging easier
const size_t str_size = 100;
char str[str_size];
if(! fgets(str, str_size, stdin)) {
fprintf(stderr, "Fail reading");
exit(EXIT_FAILURE);
}
if(sscanf(str, "%lf", &((*p)[count])) != 1) {
fprintf(stderr, "Fail converting");
exit(EXIT_FAILURE);
}
count++;
// Just an arbitrary exit condition
if ((*p)[count-1] < 1) {
printf("%lf\n", (*p)[count]);
break;
}
}
return count;
}
You mentioned in comments below that you're having troubles with pointers in general. That's not unusual. It can be a bit tricky, and it takes some practice to get used to it. My best advice is to learn what * and & really means and really think things through. * is the dereference operator, so *p is the value that exists at address p. **p is the value that exists at address *p. The address operator & is kind of an inverse to *, so *&x is the same as x. Also remember that the [] operator used for indexing is just syntactic sugar. It works like this: p[5] translates to *(p+5), which has the funny effect that p[5] is the same as 5[p].
In my first version of above code, I used p = tmp instead of *p = tmp and when I constructed a complete example to find that bug, I also used *p[count] instead of (*p)[count]. Sorry about that, but it does emphasize my point. When dealing with pointers, and especially pointers to pointers, REALLY think about what you're writing. *p[count] is equivalent to *(*(p+count)) while (*p)[count] is equivalent to *((*p) + count) which is something completely different, and unfortunately, none of these mistakes was caught even though I compiled with -Wall -Wextra -std=c18 -pedantic-errors.
You mentioned in comments below that you need to cast the result of realloc. That probably means that you're using a C++ compiler, and in that case you need to cast, and it should be (double *). In that case, change to this:
double *tmp = (double*)realloc(*p, (count+1)*sizeof(**p));
if(!tmp) {
fprintf(stderr, "Fail allocating");
exit(EXIT_FAILURE);
}
*p = tmp;
Note that I also changed the type of the pointer. In C, it does not matter what type of pointer tmp is, but in C++ it either has to be a double* or you would need to do another cast: *p = (double*)tmp
This is a part of my program that I want to create a vector of struct
typedef struct {
char nome[501];
int qtd;
int linha;
int coluna;
} tPeca;
tPeca* criarPecas(FILE *pFile, int tam) {
int i;
tPeca *pecaJogo = (tPeca*)malloc(tam*sizeof(tPeca));
if (pecaJogo == NULL)
return NULL;
for (i = 1; i <= tam; i++) {
fscanf (pFile, "%[^;]", pecaJogo[i].nome);
fscanf (pFile, "%d", pecaJogo[i].qtd);
fscanf (pFile, "%d", pecaJogo[i].linha);
fscanf (pFile, "%d\n", pecaJogo[i].coluna);
}
return pecaJogo;
}
If I change
tPeca *pecaJogo = (tPeca*)malloc(tam*sizeof(tPeca));
if (pecaJogo == NULL)
return NULL;
to
tPeca pecaJogo[tam];
It works fine but give some warning
[Warning] function returns address of local variable [-Wreturn-local-addr]
The message states it clearly: using malloc, you are allocating space that persists once the function that created it, criarPecas, returns. Your change allocates space that gets reclaimed when the function returns, and thus is free to be used for other things, and can thus be overwritten by another part of the program.
If your program is truly "working fine," you may just be getting lucky.
What is happening is that
tPeca pecaJogo[tam];
is a local variable, and as such the whole array is allocated in the stack frame of the function, which means that it will be deallocated along with the stack frame where the function it self is loaded.
The reason it's working is because that causes undefined behavior, on of the outcomes could be that it works correctly, but it's not really working correctly, it's just that nothing is overwriting the location where the array was allocated.
By changing the compilation flags or altering the funcion a little bit, it could stop working.
I know my title isn't clear, It will be clearer with code + examples.
I want to initialize a char* ("motSecret" in the main, "mot" in my function) containing a word selected randomly into a file, doing this into a function. This array is made dynamic using memory allocation.
The variable in my function get well initialized, but when I print the value just after I exited the function, the value change and become something like "0#"
Here is the part concerned in the main :
int main()
{
FILE* dico =NULL;
char *motSecret, *motRes;
char lettre=' ';
int check=0, nbCoups=10, longueur=0, nbMots=0;
Bool erreur = TRUE;
srand(time(NULL));
nbMots = scanDico(dico);
getWord(dico, nbMots, motSecret);
printf("Mot : %s", motSecret);
The problem appears after the function getWord(). Here is the code of this function :
void getWord(FILE* dico, int nbLignes, char *mot)
{
int numMotChoisi=rand() % nbLignes, nbChar=0;
char charActuel=' ';
dico = fopen("dico.txt", "r");
rewind(dico);
if(dico != NULL)
{
while (numMotChoisi > 0)
{
charActuel = fgetc(dico);
if (charActuel == '\n')
numMotChoisi--;
}
charActuel = ' ';
while(charActuel != '\n')
{
charActuel = fgetc(dico);
nbChar++;
}
fseek(dico,-(nbChar)-1,SEEK_CUR);
mot = malloc(nbChar * sizeof(char));
if(mot == NULL)
{
printf("Probleme d'allocation memoire");
exit(0);
}
fgets(mot, SIZE, dico);
mot[strlen(mot) - 1] = '\0';
printf("Mot = %s ", mot);
}
fclose(dico);
}
The printf at the end of the function return a good value, and the printf just after the getWord() in the main show that the value changed in the function haven't been "saved"...
Other thing, that works fine without memory allocation.
I hope I'm clear enough. If I forgot to tell something or if you need more informations, please tell me.
C uses pass by value in function parameter passing.
You need a double pointer, something like void getWord(FILE* dico, int nbLignes, char **mot) if you want to allocate memory inside another function.
As a cascased effect, printf("Mot : %s", motSecret); is trying to access uninitialized memory, causing undefined behaviour.
Suggestions:
I see no reason to use FILE *dico as a parameter in getWord(). In can very well be a local.
instead of using double pointer, i would like to recommend returning the allocated pointer from getWord(), i.e., change void getWord() to char * getWord(), add return mot and use like motSecret = getWord(<params>)
char *motSecret;
motSecret is a local variable withing main() and it is not initilized.
By calling
getWord(dico, nbMots, motSecret);
You are passing some uninitialized pointer to a function getword().
Inside getword() you are assigning some memory to
char *mot;
and writing some data to this memory.
Now this memory is not known to motSecret You have to return this memory address to the uninitialized pointer in main()
char *motSecret = getWord(dico, nbMots);
Your getword() should be like,
char *getWord(dico, nbMots);
and inside this after performing everything do,
return mot;