This is my first question here so i apologize if its not a useful question.
I have this project of a simulator where the user calls the program via command line with some parameters. Like, MYPROG [options] filename.
I need to make sure the filename is valid, where it is (directory) and get the name for further use.
Here is part of the code:
char* ExtrairNome(char* alvo){
char* teste = alvo;
char* nome = NULL;
int barras = 0;
while(strcmp(teste, "") != 0){ //look for "/"
if (teste[0] == '/') barras++;
teste++;
}
teste = alvo;
if (barras > 0){
while(barras > 0){ //remove everything leaving the "filename.ias"
if (teste[0] == '/') barras--;
teste++;
}
}
int i = 0;
char aux[strlen(teste) - 4];
while (strcmp(teste, ".ias")){ //remove the ".ias"
aux[i] = teste[0];
teste++;
i++;
}
printf("random %d\n", barras); //this line fixes the bug!!
aux[i] = '\0';
nome = aux;
return nome;
}
This function receives the string with the full filename and should return only the name, without extention or path. But it only works when i printf some variable before returning. If i remove that line the function returns nothing.
I think it has something to do with scope but i don't know for sure. How can i fix this?
nome is a pointer, so you can return the address of the solution.
Problem is aux, which is in the stack, and once you return, it doesn't exist anymore, so behaviour is unknown. You have two choices, declaring "aux" in a higher scope and pass it to your function, and passing a pointer to the buffer solution or allocate in the function(using malloc) and then free(when its not necessary).
i mean:
char name[100];
ExtrairNome(alvo, name);//pass a pointer to the function
void ExtrairNome(char * alvo, char * aux)
{
...;//everything is the same
//except you don't create aux here, you use the one you created in your main function
}
or
char * ExtrairNome(char * alvo, char * aux)
{
...;//everything is the same
char * aux = (char*)malloc((strlen(teste)-4 )* sizeof(char));
...;//everything the same
}
//remember to free() when you are done using it
You are returning a pointer to a local automatic (stack) variable - aux. That does not exist after the function returns. This is undefined behavior. The fact that it 'works' when you print a variable is one possibility for undefined behavior.
Related
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.
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.
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;
I have the following structs in my on-going struggle to eventually create some kind of shell (based eventually around execvp().
struct commands {
char cmdname[30]; // The name of the command
enum ActionType action; /* char action[30]; what action to take */
};
struct userinput {
struct commands theaction; //The chosen action
char cmdentered[100]; // The cmd entered
char **anyargs; //The tokenised command
int argcount; //Argument count
};
And I initialise anyargs using malloc and create an array of strings with one string per argument to be passed on to the execvp.
I then get user input, convert the input into tokens stored in anyargs and examine the strings to find out what sort of action needs to be taken and store that in an enum.
All these methods are done by passing the pointer to the struct userinput as method parameters - which works fine. HOWEVER when I pass the pointer to the struct to a nested function, the char** anyargs becomes empty.
I hope the code I've added provides a solution to the answer! On another observation - when passed to a function inside a function, the actual value of the pointer doesn't change - only the dereferenced contents of the pointer.
Any help would be most gratefully received! I've tried to strip the code down to the areas I think are causing the issue!
Thank you!
int main() {
struct commands cmdlist[4]; //Array of structures with all commands in them
memset(cmdlist, 0, sizeof(cmdlist));
struct userinput userentry = { { { 0 } } }; //Structure containing input
userentry.theaction = cmdlist[0]; //Initialize empty command
userentry.anyargs = calloc(100, sizeof(char));
runEntry(&userentry, cmdlist); //Pass struct to function
free(userentry.anyargs);
return 0;
}
int runEntry(struct userinput *userentry, struct commands thecmds[]) {
int retval = 0;
int childpid = 0;
int processStatus;
printf("\n ... running cmd: \n\n");
printUserEntry(userentry); //in printUserEntry,
//userentry->anyargs[0] = NULL - why?
}
You've allocated 100 bytes worth of char * elements in anyargs. You haven't initialized those pointers, though. The fact that anyargs[0] happens to contain NULL is nice, but not guaranteed. malloc() doesn't initialize the allocated space.
In other words, when you say:
userentry.anyargs = malloc(100);
you've created:
userentry.anyargs = {
???, // uninitialized char *
???, // and another
???, // and another
...
??? // (100 / sizeof(char *)) entries later
};
You can explicitly initialize those to NULL in a loop:
for ( i = 0; i < (100 / sizeof(char *)); ++i )
userentry.anyargs[i] = NULL;
(or use calloc() instead of malloc() to ensure everything is zeroed out).
or you can allocate some space to them:
for ( i = 0; i < (100 / sizeof(char *)); ++i )
userentry.anyargs[i] = malloc(50); // or some other length
or just set them directly in runEntry():
userentry.anyargs[0] = "foo";
userentry.anyargs[1] = strdup(something);
I am using some C with an embedded device and currently testing some code to read file details from an SD card. I am using a proprietary API but I will try to remove that wherever possible.
Rather than explaining, I will try to let me code speak for itself:
char* getImage() {
int numFiles = //number of files on SD card
for(int i=0; i<numFiles;i++) {
\\lists the first file name in root of SD
char *temp = SD.ls(i, 1, NAMES);
if(strstr(temp, ".jpg") && !strstr(temp, "_")) {
return temp;
}
}
return NULL;
}
void loop()
{
\\list SD contents
USB.println(SD.ls());
const char * image = getImage();
if(image != NULL) {
USB.println("Found an image!");
USB.println(image);
int byte_start = 0;
USB.print("Image Size: ");
**USB.println(SD.getFileSize(image));
USB.println(SD.getFileSize("img.jpg"));**
}
The two lines at the bottom are the troublesome ones. If I pass a literal string then I get the file size perfectly. However, if I pass the string (as represented by the image variable) then I am given a glorious -1. Any ideas why?
For clarity, the print out of image does display the correct file name.
EDIT: I know it is frowned upon in C to return a char and better to modify a variable passed to the function. I have used this approach as well and an example of the code is below, with the same result:
char * image = NULL;
getSDImage(&image, sizeof(image));
void getSDImage(char ** a, int length) {
int numFiles = SD.numFiles();
for(int i=0; i<numFiles;i++) {
char *temp = SD.ls(i, 1, NAMES);
if(strstr(temp, ".jpg") && !strstr(temp, "_")) {
*a = (char*)malloc(sizeof(char) * strlen(temp));
strcpy(*a, temp);
}
}
}
EDIT 2: The link to the entry is here: SD.ls and the link for the file size function: SD.getFileSize
From the return, it seems like the issue is with the file size function as the return is -1 (not 0) and because a result is returned when listing the root of the SD.
Thanks!
UPDATE: I have added a check for a null terminated string (it appears that this was an issue) and this has been addressed in the getSDImage function, with the following:
void getSDImage(char ** a, int length) {
int numFiles = SD.numFiles();
for(int i=0; i<numFiles;i++) {
char *temp = SD.ls(i, 1, NAMES);
if(strstr(temp, ".jpg") && !strstr(temp, "_")) {
*a = (char*)malloc(sizeof(char) * strlen(temp));
strncpy(*a, temp, strlen(temp)-1);
*a[strlen(*a)-1] = '\0';
}
}
}
This seems to work and my results to standard output are fine, the size is now not shown as the error-indicating -1 but rather -16760. I thought I should post the update in case anyone has any ideas but my assumption is that this is something to do with the filename string.
There are several things that could be wrong with your code:
1) You might be passing "invisible" characters such as whitespaces. Please make sure that the string you are passing is exactly the same, i.e. print character by character including null termination and see if they are the same.
2) The value that is getting returned by API and latter used by other API may not be as expected. I would advise that (if possible) you look at the API source code. If you can compile the API itself then it should be easy to find the problem (check what API getFileSize() gets from parameters). Based on the API documentation you have sent check the value stored in buffer[DOS_BUFFER_SIZE] after you get -1 from.
EDIT (after looking at the API source code):
On line 00657 (func find_file_in_dir) you have:
if(strcmp(dir_entry->long_name, name) == 0)
it seems as the only reason why you would have different reply when using string literal as opposed to the getting name from your function. So it is very likely that you are not passing the same values (i.e. you are either passing invisible chars or you are missing string termination).
As final note: Check the content of buffer[DOS_BUFFER_SIZE] before each code to SD API.
I hope this helps.
Kind regards,
Bo
This:
if(strstr(temp, ".jpg") && !strstr(temp, "_")) {
*a = (char*)malloc(sizeof(char) * strlen(temp));
strcpy(*a, temp);
}
is broken, it's not allocating room for the terminator and is causing a buffer overflow.
You should use:
*a = malloc(strlen(temp) + 1);
There's no need to cast the return value of malloc() in C, and sizeof (char) is always 1.