Hi i am trying to figure out how to copy only part of a line being read from a text file. I want to copy a line from a file called fileLine to a variable called line. The problem is, is that i only want to copy starting at index 10 in fileLine but memcpy dislikes that. How can i change this to make memcpy happy?
int stringLength = 0;
stringLength = strlen(fileLine);
memcpy(line, fileLine[10], stringLength); //this is where things go wrong.
You have passed in a char type to something that expected a const void*. This would have been okay if you had passed it a char*. You can do that as either &fileLine[10] or fileLine + 10.
Since you are offsetting by 10, you also want to ensure you copy 10 fewer characters:
memcpy(line, &fileLine[10], stringLength-10);
Although you probably want to copy the string terminator too...
memcpy(line, &fileLine[10], stringLength-9);
Yuck!
Instead, you could use strcpy:
strcpy(line, fileLine + 10);
In all cases, make sure that line is an array or a pointer to memory that is actually allocated to your process.
You can use getline function to get part of the string. But first, you have to move your read pointer to the position from which you want to read using seekg function.
seekg(ios flag, bytes);
cin.getline(source, number of characters, ending character);
Related
I'm a beginner in programming and I'm currently learning C, but I've come across something that confuses me.
In my while loop i have:
char* bword = word
fscanf(fp, "%s", word);
Where word is a char[46], bword is a char* and fp is the file (a word dictionary in this case). I wanted to keep track of the word before it gets replaced when scanning fp. And it seemed logical to me to asign the word to a variable before it gets changed. But if I print bword after fscanf(fp, '%s", word) then it's changed to the new word! I don't really understand why and how.
If I do this:
bword = word;
printf("1.%s\n", word);
printf("2.%s\n", bword);
// scan the file for a for a word and store in word
fscanf(fp, "%s", word);
printf("3.%s\n", word);
printf("4.%s\n", bword);
I get these results in the command line:
1.
2.
3.a
4.a
(You don't see anything before 1 and 2 because the word was empty at the time).
I also tried assigning word to something "bar" before the loop but then I got:
1.bar
2.bar
3.a
4.a
So how do I solve this? I don't want bword to change.
You need to understand that this
char *bword = word;
declares a pointer to the first element of the array word, which means that modifiying bword modifies word too, because bword is just a reference1 to the real data location which is the array word
If you want bword and word to be independent of each other then make bword an array so it's stored in a different location, like this
char bword[SOME_REASONABLE_SIZE];
from here you can call fscanf() and pass the appropriate array and the result will be the one you expected before.
Notice, that when you pass the array to fscanf(), essentially you are passing a pointer to the first element of it, just what your bword was in the first place.
1A reference in a general sense, not in c++ sense.
First you must learn about pointers (you can see tutorialspoint).
Then you find out array is a pointer to a memory so when you assigning them you just assign addresses so if one of them change other one is also changed. if you want to copy strings you can not assign then you must copy them and you can use strcpy() function. as it man page says it have following syntax:
char *strcpy(char *dest, const char *src);
The strcpy() function copies the string pointed to by src, including the terminating null byte ('\0'), to the buffer pointed to by dest. The strings may not overlap, and the destination string dest must be large enough to receive the copy. Beware of buffer overruns!
I want to declare character array and later want to fill it. But getting error:
char line[BUFSIZE+1];
strcpy(line,"Memory is Full", sizeof(line));
Error is:
wrong number of arguments in call to strcpy.
Is there any alternative to achive this?
If you have it, use strlcpy(). It does what you might expect strncpy() to do.
Failing that, I would recommend using snprintf(), if you have it.
strcpy() takes 2 arguments, strncpy() takes 3.
I think you were thinking about using strncpy, that takes destination, source, and size.
ie:
int main()
{
char i[6];
strncpy(i, "Hello", sizeof(i));
printf("%s\n", i);
return 0;
}
>> ./a.out
>> Hello
Note: You have to append the '\0' yourself if you completly fill your char[], otherwise strncpy() will do it for you (as in my example).
strcpy doesn't take a size/length argument. Use memcpy instead, but give it the size (length+1) of the string being copied, not the size of the buffer, or you risk undefined behavior/segfaults.
i have two different filenames, which are defined in a header file:
1: "physio_sensor_readout.csv"
2: "statethresh_configuration.csv"
they are initialised by
char* filename;
and later
filename = FILENAMEINAMACRO; which is the corresponding filename above
Later, filename is passed to another function which alters the ending:
filename[strnlen(filename, FILENAME_LENGTH) - 4] = '\0';
This should remove the ending .csv and i strncat a new one afterwards.
FILENAME_LENGTH is 60, so enough space.
It works if i pass "statetresh_...."(even the strncat afterwards) but not with "physio_se.....". This throws a segment fault
strnlen(filename,FILENAME_LENGTH - 4)
returns 21 in case 1 and 25 in case 2. this is the correct position of the dot, where i want to put the terminating null.
Is this a problem with char* and should i initialise filename with char filename[60]?
Regards and thank you
edit:
your suggestions solved the problem. thanks!
I think you declare FILENAMEINAMACRO as string literal [Without more code I cannot be sure about it].
string literals might be saved on read only memory - so you might not be able to change them.
In any way, trying to change string literals results in undefined behavior.
You might want to make a copy of FILENAMEINAMACRO and work on it using strcpy()
It is not safe to modify the contents of a character literal. Something like this:
char *filename = "yes";
filename[2] = 'p'; // change to "yep"
is undefined behavior, and can cause disastrous results, because filename can be pointing to memory that can't be modified. Instead, try something like this:
char filename[] = "yes";
filename[2] = 'p'; // change to "yep"
which will allocate a new array filename and initialize its contents with "yes".
You are appear to be pointing your char* pointer filename at a character constant. I assume you have defined #define FILENAMEINAMACRO "physio_sensor_readout.csv". This makes your assignment filename = "physio_sensor_readout.csv";. You then use the filename pointer to modify the string constant. Here is a more suitable sequence:
char filename[256]; // choose a size that is suitably large
...
strcpy(filename, FILENAMEINAMACRO); // also look at strncpy for safer copying
...
... manipulate the content of filename as you wish ...
Because you have made a copy of the string literal, modifying it is safe (as long as you stay within the bounds of the declared size of filename -- which includes keeping any terminating null also within the bounds.
You should be careful using the char filename[] = "..." form. It allocates enough space for the string literal you give it, but if later you copying some other string literal into that space you must be certain that the second literal is no longer than the first. A safer practice is to dimension the space to be large enough that you're certain your code will never attempt to use any more than what you have dimensioned. If you accept input from outside the program (or from other person's code), you should check the length of what you are accepting before trying to copy it into the space you have dimensioned. Any use of space beyond the dimensioned size is likely to cause issues that can be hard to diagnose. In the example above, you must make all efforts to ensure you never use more space (including the terminating nul char) than 256 chars (because filename is dimensioned at 200).
I have the following piece of code in C:
char a[55] = "hello";
size_t length = strlen(a);
char b[length];
strncpy(b,a,length);
size_t length2 = strlen(b);
printf("%d\n", length); // output = 5
printf("%d\n", length2); // output = 8
Why is this the case?
it has to be 'b [length +1]'
strlen does not include the null character in the end of c strings.
You never initialized b to anything. Therefore it's contents are undefined. The call to strlen(b) could read beyond the size of b and cause undefined behavior (such as a crash).
b is not initialized: it contains whatever is in your RAM when the program is run.
For the first string a, the length is 5 as it should be "hello" has 5 characters.
For the second string, b you declare it as a string of 5 characters, but you don't initialise it, so it counts the characters until it finds a byte containing the 0 terminator.
UPDATE: the following line was added after I wrote the original answer.
strncpy(b,a,length);
after this addition, the problem is that you declared b of size length, while it should be length + 1 to provision space for the string terminator.
Others have already pointed out that you need to allocate strlen(a)+1 characters for b to be able to hold the whole string.
They've given you a set of parameters to use for strncpy that will (attempt to) cover up the fact that it's not really suitable for the job at hand (or almost any other, truth be told). What you really want is to just use strcpy instead. Also note, however, that as you've allocated it, b is also a local (auto storage class) variable. It's rarely useful to copy a string into a local variable.
Most of the time, if you're copying a string, you need to copy it to dynamically allocated storage -- otherwise, you might as well use the original and skip doing a copy at all. Copying a string into dynamically allocated storage is sufficiently common that many libraries already include a function (typically named strdup) for the purpose. If you're library doesn't have that, it's fairly easy to write one of your own:
char *dupstr(char const *input) {
char *ret = malloc(strlen(input)+1);
if (ret)
strcpy(ret, input);
return ret;
}
[Edit: I've named this dupstr because strdup (along with anything else starting with str is reserved for the implementation.]
Actually char array is not terminated by '\0' so strlen has no way to know where it sh'd stop calculating lenght of string as as
its syntax is int strlen(char *s)-> it returns no. of chars in string till '\0'(NULL char)
so to avoid this this we have to append NULL char (b[length]='\0')
otherwise strlen count char in string passed till NULL counter is encountered
Yo!
I'm trying to copy a few chars from a char[] to a char*. I just want the chars from index 6 to (message length - 9).
Maybe the code example will explain my problem more:
char buffer[512] = "GET /testfile.htm HTTP/1.0";
char* filename; // I want *filename to hold only "/testfile.htm"
msgLen = recv(connecting_socket, buffer, 512, 0);
strncpy(filename, buffer+5, msgLen-9);
Any response would help alot!
I assume you meant...
strncpy(filename, buffer+5, msgLen-9);
The problem is you haven't allocated any memory to hold the characters you're copying. "filename" is a pointer, but it doesn't point at anything.
Either just declare
char filename[512];
or malloc some memory for the new name (and don't forget to free() it...)
There are a few problems with the use of strncpy() in your code.
buffer+5 points to the sixth character in string (the "T"), while you said you wanted the backslash.
The last parameter is the maximum number of bytes to copy, so should probably be msglen-13.
strncpy() won't null terminate the copied string, so you need to do that manually.
Also, from a readabilty perspective,
I prefer
strncpy(filename, &buffer[4], msgLen-(9 + 4));
&buffer[5] is the address of the character at the fifth position in the array. That's a personal thing, though.
Also, worth pointing out that the result of "recv" could be one byte or 512 bytes. It won't just read a line. You should really loop calling recv until you have a complete line to work with.
First of all you should allocate a buffer for filename. The next problem is your offset.
char buffer[512] = "GET /testfile.htm HTTP/1.0";
char filename[512]; // I want *filename to hold only "/testfile.htm"
msgLen = recv(connecting_socket, buffer, 512, 0);
strncpy(filename, buffer+4, msgLen-4-9);
//the first parameter should be buffer+4, not 5. Indexes are zero based.
//the second parameter is count, not the end pointer. You should subtract
//the first 4 chars too.
Also you should make sure you add a null at the end of string as strncpy doesn't do it.
filename[msgLen-4-9] = 0;
You could also use memcpy instead of strncpy as you want to just copy some bytes:
memcpy(filename, buffer+4, msgLen-4-9);
fileName[msgLen-4-9] = 0;
In either case, make sure you validate your input. You might receive invalid input from the socket.
Your example code has the line:
char* filename;
This is an uninitialised pointer - it points nowhere, and isn't backed by any storage. You need to allocate some memory for it, e.g. using malloc() (and remember to free() it when you're done), or, in this case, you can probably simply declare it as a character array, e.g.
char filename[SOME_BUFFER_SIZE];
Declaring an array on the stack has the advantage that you don't need to explicitly free it up when you're done with it.
Fundamentally, arrays in C are just syntactic sugar that hide pointers, so you can (usually) treat a char[] as a char*.
You've not allocated any space for the filename
Either replace the declaration of filename with something like
char filename[512]
or (probably better) allow enough space for the filename
filename = (char *)malloc(msgLen - 9 - 6 + 1 ); /* + 1 for the terminating null */
You have not allocated any memory space to filename yet.
It is a pointer... but until initialized, it is pointing to some random area of memory.
You need to allocate memory for filename. As Roddy said, you could declare filename to be 512 bytes. Or you could:
filename = (char*)malloc(512*sizeof(char));
(note: sizeof(char) isn't strictly needed, but I think helps clarify exactly what is being allocated).
After this statement, filename is a pointer to allocated memory, you are free to use it, including copying data to it from buffer. If you copy only a limited region, be sure you leave filename null-terminated.