I want to add a directory to a filename in c but i get an error like:
Segmentation fault (core dumped)
Here is my code:
char fname[255];
char directoryTmp[262];
/*Working Code for entering the filename fname with fgets() */
...
/* specify the directory */
directoryTmp[0] = "/";
directoryTmp[1] = "f";
directoryTmp[2] = "i";
directoryTmp[3] = "l";
directoryTmp[4] = "e";
directoryTmp[5] = "s";
directoryTmp[6] = "/";
/* Copy fname at the end of directoryTmp */
strcat(directoryTmp,fname);
/* new fname with the directory, should look like: "/files/afilename */
for(i=0;i<strlen(directoryTmp);i++){
fname[i] = directoryTmp[i];
}
//edit
OK this is my new code, but I still get the same error code:
char fname[255];
char directory[262];
directory[sizeof(directory) - 1] = '\0';
strncpy(directory,sizeof(directory) - 1, "/files/");
for(i=0;i<strlen(directory);i++){
fname[i] = directory[i];
}
puts(fname);
fname[sizeof(fname) - 1] = '\0';
chars are put in single quotation marks (''), not double (""). You're assigning string literals to each array index.
The error is that you forgot to NUL terminate your string when filling directoryTmp (in C strings are array of char that by convention ends at the first char whose value is 0). Then, when strcat try to append fname it begins by iterating over directoryTmp looking for a NUL character. As the array is initialized on the stack (at least I guess from the code snippet), its content is undefined, and strcat scan past the end of the array which is undefined behavior (in your particular case this cause a segmentation fault).
So, the correct code would be:
/* specify the directory */
directoryTmp[0] = '/';
directoryTmp[1] = 'f';
directoryTmp[2] = 'i';
directoryTmp[3] = 'l';
directoryTmp[4] = 'e';
directoryTmp[5] = 's';
directoryTmp[6] = '/';
directoryTmp[7] = 0; // NUL terminate the string
Or as mentioned by others, just use strncpy:
memset(directoryTmp, 0, sizeof(directoryTmp));
strncpy(directoryTmp, "/files/", sizeof(directoryTmp) - 1);
Note that strncpy does not guarantee that the string will be NUL terminated, so we have to take care of that ourselves.
You can simply do like this
char fname[255];
char directoryTmp[262];
/*Working Code for entering the filename fname with fgets() */
...
/* specify the directory */
strcpy(directoryTmp,"/files/");
/* Copy fname at the end of directoryTmp */
strcat(directoryTmp,fname);
/* new fname with the directory, should look like: "/files/afilename */
for(i=0;i<strlen(directoryTmp);i++){
fname[i] = directoryTmp[i]; //You need to take care here. Because size of the fname is 255 and size of the directoryTmp is 262. you should check length of the fname in for loop.
}
Related
I have encountered a problem with my homework. I need to scan some data from a text file, to a struct.
The text file looks like this.
012345678;danny;cohen;22;M;danny1993;123;1,2,4,8;Nice person
223325222;or;dan;25;M;ordan10;1234;3,5,6,7;Singer and dancer
203484758;shani;israel;25;F;shaninush;12345;4,5,6,7;Happy and cool girl
349950234;nadav;cohen;50;M;nd50;nadav;3,6,7,8;Engineer very smart
345656974;oshrit;hasson;30;F;osh321;111;3,4,5,7;Layer and a painter
Each item of data to its matching variable.
id = 012345678
first_name = danny
etc...
Now I can't use fscanf because there is no spacing, and the fgets scanning all the line.
I found some solution with %[^;]s, but then I will need to write one block of code and, copy and past it 9 times for each item of data.
Is there any other option without changing the text file, that similar to the code I would write with fscanf, if there was spacing between each item of data?
************* UPDATE **************
Hey, First of all, thanks everyone for the help really appreciating.
I didn't understand all your answers, but here something I did use.
Here's my code :
#define _CRT_SECURE_NO_WARNINGS
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef struct
{
char *idP, *firstNameP, *lastNameP;
int age;
char gender, *userNameP, *passwordP, hobbies, *descriptionP;
}user;
void main() {
FILE *fileP;
user temp;
char test[99];
temp.idP = (char *)malloc(99);
temp.firstNameP = (char *)malloc(99);
temp.lastNameP = (char *)malloc(99);
temp.age = (int )malloc(4);
temp.gender = (char )malloc(sizeof(char));
temp.userNameP = (char *)malloc(99);
fileP = fopen("input.txt", "r");
fscanf(fileP, "%9[^;];%99[^;];%99[^;];%d;%c", temp.idP,temp.firstNameP,temp.lastNameP,&temp.age, temp.gender);
printf("%s\n%s\n%s\n%d\n%c", temp.idP, temp.firstNameP, temp.lastNameP, temp.age, temp.gender);
fgets(test, 60, fileP); // Just testing where it stop scanning
printf("\n\n%s", test);
fclose(fileP);
getchar();
}
It all works well until I scan the int variable, right after that it doesn't scan anything, and I get an error.
Thanks a lot.
As discussed in the comments, fscanf is probably the shortest option (although fgets followed by strtok, and manual parsing are viable options).
You need to use the %[^;] specifier for the string fields (meaning: a string of characters other than ;), with the fields separated by ; to consume the actual semicolons (which we specifically requested not to be consumed as part of the string field). The last field should be %[^\n] to consume up to the newline, since the input doesn't have a terminating semicolon.
You should also (always) limit the length of each string field read with a scanf family function to one less than the available space (the terminating NUL byte is the +1). So, for example, if the first field is at most 9 characters long, you would need char field1[10] and the format would be %9[^;].
It is usually a good idea to put a single space in the beginning of the format string to consume any whitespace (such as the previous newline).
And, of course you should check the return value of fscanf, e.g., if you have 9 fields as per the example, it should return 9.
So, the end result would be something like:
if (fscanf(file, " %9[^;];%99[^;];%99[^;];%d;%c;%99[^;];%d;%99[^;];%99[^\n]",
s.field1, s.field2, s.field3, &s.field4, …, s.field9) != 9) {
// error
break;
}
(Alternatively, the field with numbers separated by commas could be read as four separate fields as %d,%d,%d,%d, in which case the count would go up to 12.)
Here you have simple tokenizer. As I see you have more than one delimiter here (; & ,)
str - string to be tokenized
del - string containing delimiters (in your case ";," or ";" only)
allowempty - if true allows empty tokens if there are two or more consecutive delimiters
return value is a NULL terminated table of pointers to the tokens.
char **mystrtok(const char *str, const char *del, int allowempty)
{
char **result = NULL;
const char *end = str;
size_t size = 0;
int extrachar;
while(*end)
{
if((extrachar = !!strchr(del, *end)) || !*(end + 1))
{
/* add temp variable and malloc / realloc checks */
/* free allocated memory on error */
if(!(!allowempty && !(end - str)))
{
extrachar = !extrachar * !*(end + 1);
result = realloc(result, (++size + 1) * sizeof(*result));
result[size] = NULL;
result[size -1] = malloc(end - str + 1 + extrachar);
strncpy(result[size -1], str, end - str + extrachar);
result[size -1][end - str + extrachar] = 0;
}
str = end + 1;
}
end++;
}
return result;
}
To free the the memory allocated by the tokenizer:
void myfree(char **ptr)
{
char **savedptr = ptr;
while(*ptr)
{
free(*ptr++);
}
free(savedptr);
}
Function is simple but your can use any separators and any number of separators.
I am reading from a file using fgetc and doing that makes it so that I have a char. However, I want to convert this char to a string such that I can use the strtok function upon it. How would I go about doing this?
int xp;
while(1) {
xp = fgetc(filename);
char xpchar = xp;
//convert xpchar into a string
}
Simply create an array with two items, your character and the null terminator:
char str[] = {ch, '\0'};
Or if you will, use a compound literal to do the same:
(char[]){ch, '\0'}
Compound literals can be used to convert your character directly, inside an expression:
printf("%s", (char[]){ch, '\0'} );
I suppose, you are going to read not just one character from file, so look at the following example:
#define STR_SIZE 10
// STR_SIZE defines the maximum number of characters to be read from file
int xp;
char str[STR_SIZE + 1] = { 0 }; // here all array of char is filled with 0
// +1 in array size ensure that at least one '\0' char
// will be in array to be the end of string
int strCnt = 0; // this is the conter of characters stored in the array
while (1) {
xp = fgetc(f);
char xpchar = xp;
//convert xpchar into a string
str[strCnt] = xpchar; // store character to next free position of array
strCnt++;
if (strCnt >= STR_SIZE) // if array if filled
break; // stop reading from file
}
And name of your file-pointer-variable - filename looks strange (filename is good name for string variable that store name of file, but fgetc and getc need FILE *), so check that in your program you have something like:
FILE * f = fopen(filename, "r");
or think over changing name for filename.
This question already has answers here:
What is the difference between char a[] = ?string?; and char *p = ?string?;?
(8 answers)
How do I concatenate const/literal strings in C?
(17 answers)
Closed 10 years ago.
How can I take a C string pointer like
char *a = "asdf";
and change it so that it becomes
char *a = "\nasdf\n";
When you assign string like tihs
char *a = "asdf";
you are creating a string literal. So it cannot be modified. It is already explained here.
You can't modify a string literal, so you would have to create a second string with that new format.
Or, if the formatting is just for display, you can hold off on creating a new string by just applying the formatting when you display it. Eg:
printf("\n%s\n", a);
I don't know whether this is what you were looking for, but it looks like you want to concatenate strings: How do I concatenate const/literal strings in C?
Use "\n" as your first and last string, and the string given as the second one.
You can't do that if you are using pointers to string literals, the reason being that a string literal is constant and can't be changed.
What you can do is declare an array, with enough space to accommodate the extra characters, something like
char a[16] = "asdf";
Then you can e.g. memmove to move the string around, and add the new characters manually:
size_t length = strlen(a);
memmove(&a[1], a, length + 1); /* +1 to include the terminating '\0' */
a[0] = '\n'; /* Add leading newline */
a[length + 1] = '\n'; /* Add trailing newline */
a[length + 2] = '\0'; /* Add terminator */
char* a = "asdf";
char* aNew = new char[strlen(a) + 2]; //Allocate memory for the modified string
aNew[0] = '\n'; //Prepend the newline character
for(int i = 1; i < strlen(a) + 1; i++) { //Copy info over to the new string
aNew[i] = a[i - 1];
}
aNew[strlen(a) + 1] = '\n'; //Append the newline character
a = aNew; //Have a point to the modified string
Hope this is what you were looking for. Don't forget to call "delete [] aNew" when you're finished with it to prevent it from leaking memory.
As simple as that. I'm on C++ btw. I've read the cplusplus.com's cstdlib library functions, but I can't find a simple function for this.
I know the length of the char, I only need to erase last three characters from it. I can use C++ string, but this is for handling files, which uses char*, and I don't want to do conversions from string to C char.
If you don't need to copy the string somewhere else and can change it
/* make sure strlen(name) >= 3 */
namelen = strlen(name); /* possibly you've saved the length previously */
name[namelen - 3] = 0;
If you need to copy it (because it's a string literal or you want to keep the original around)
/* make sure strlen(name) >= 3 */
namelen = strlen(name); /* possibly you've saved the length previously */
strncpy(copy, name, namelen - 3);
/* add a final null terminator */
copy[namelen - 3] = 0;
I think some of your post was lost in translation.
To truncate a string in C, you can simply insert a terminating null character in the desired position. All of the standard functions will then treat the string as having the new length.
#include <stdio.h>
#include <string.h>
int main(void)
{
char string[] = "one one two three five eight thirteen twenty-one";
printf("%s\n", string);
string[strlen(string) - 3] = '\0';
printf("%s\n", string);
return 0;
}
If you know the length of the string you can use pointer arithmetic to get a string with the last three characters:
const char* mystring = "abc123";
const int len = 6;
const char* substring = mystring + len - 3;
Please note that substring points to the same memory as mystring and is only valid as long as mystring is valid and left unchanged. The reason that this works is that a c string doesn't have any special markers at the beginning, only the NULL termination at the end.
I interpreted your question as wanting the last three characters, getting rid of the start, as opposed to how David Heffernan read it, one of us is obviously wrong.
bool TakeOutLastThreeChars(char* src, int len) {
if (len < 3) return false;
memset(src + len - 3, 0, 3);
return true;
}
I assume mutating the string memory is safe since you did say erase the last three characters. I'm just overwriting the last three characters with "NULL" or 0.
It might help to understand how C char* "strings" work:
You start reading them from the char that the char* points to until you hit a \0 char (or simply 0).
So if I have
char* str = "theFile.nam";
then str+3 represents the string File.nam.
But you want to remove the last three characters, so you want something like:
char str2[9];
strncpy (str2,str,8); // now str2 contains "theFile.#" where # is some character you don't know about
str2[8]='\0'; // now str2 contains "theFile.\0" and is a proper char* string.
I am trying to iterate through char*
Is there any way to like reset these char* strings back to blank?
I am trying to reset from1 and send1.
Is there anything else wrong with my code.. it is only copying the first file in my array
for(i = 0; i < 3; i++)
{
from1 = " ";
send1 = " ";
from1 = strncat(fileLocation,filesToExport[i],50);
send1 = strncat(whereAmI,filesToExport[i],50);
CopyFile(from1,send1,TRUE);
printf("%s\n",from1);
printf("%s",send1);
}
THe strings are nul terminated, which means they have a zero character at the end. You can set the first char in the string to zero to truncate it back to being empty:
from1[0] = '\0';
Another way would be to copy a blank string:
strcpy(from1, "");
What do you mean by "blank"? Zeroed, spaces, or empty?
For filling a memory area you're best off using memset(), so
#include <string.h>
memset(pBuffer, ' ', length); /* Fill with spaces */
pBuffer[length] = '\0'; /* Remember to null-terminate manually when using memset */
memset(pBuffer, '\0', length); /* Fill with zeroes */
pBuffer[0] = '\0'; /* Set first element to null -- effectively set the string
* to length 0
*/
The easiest way is to set the first byte to 0. Like this:
from1[0] = 0;
send1[0] = 0;
C/C++ checks the end of a char* string by looking for the 0 byte. It doesn't care what follows that.
To clear a string to empty, so that strncat() has an empty string to concatenate to, just do:
from1[0] = '\0';
This sets the first character to the zero terminator that indicates end of string, thus making the string have length 0. This assumes that from1 is an actual modifiable char buffer, but your call to strncat() implies that it is.
You are copying into filelocation and whereami. Are they buffers or strings? You may be writing off the end of your string.
I think you would do better to allocate a suitably sized buffer
fromLen = strlen(fileLocation);
fileLen = strlen(filesToExport[i]);
from1 = malloc(fromLen + fileLen + 1);
/* add check here that string fits */
strcpy( from1, filelocation);
strcat( from1 + fromLen, filesToExport[i]);
/** etc **/
free(from1);
you mean like
send1[0] = 0;
from1[0] = 0;
?