I want to copy the content of some char-arrays passed as parameters in a function to another char-arrays. So I passed these arrays as pointers (passing by reference). Then I used memcpy to copy the content of these arrays to some other arrays. But the copying-process was not too exact, although I think that I used memcpy correctly. Some characters was deleted, while some new charcters appeared. I tried then to use strcpy, so the content of these arrays was correctly copied. So I want to understand why copying process failed when using memcpy. Here is the some of my code:
struct student{
bool statusFlag;
char lastname[20];
char firstname[20];
int mNr;
};
here is the method:
struct student getData(char * lastname, char * firstname, int matNr){
struct student st;
int i;
printf("%s\n",lastname);
if(insertCounter<=size){
//get data
st.statusFlag=1;
memcpy(st.lastname,lastname,strlen(lastname));
memcpy(st.firstname,firstname,strlen(firstname));
st.mNr=matNr;
printf("%s,%s,%d\n",st.lastname,st.firstname,st.mNr);
return st;
}else if(insertCounter>size){
st.statusFlag=0;
return st;
}
When I replaced memcpy with strcpy, The copy-operation was successful:
The statement
memcpy(target,source, strlen(source))
should copy all the chars of the string. But, it will stop just short of copying the 0-byte that marks the end of the string. So what you copied won't be a string. This will be a problem if you call any string functions on the new copy (target), basicaly if you use target in any way, you will march off the end, since the end is now unmarked. Probably you will pick up some extra bytes, anything that happens to be in memory after target, worst case you program segfalts if it marches far enough without finding a 0. The function strcpy will copy the 0-byte, I usually use
snprintf(target, sizeof target, "%s", source);
Since it does not write past the end of the target buffer, and it always makes room for the 0, protecting against trouble in the next string op.
Related
C function to remove the first string from an XOR linked list of names:
int remove_string(Node **head, char *deleted_string) {
Node *temp = *head;
*deleted_string = *(*head)->name;
*head = calculate_xor_value(NULL, temp->xor_value);
if (*head != NULL) {
(*head)->xor_value = calculate_xor_value(NULL, calculate_xor_value(temp, (*head)->xor_value));
}
free(temp);
}
In the question, one of the input parameters has to be a char pointer called deleted_string, which is the string that is being removed from the list. The code to remove the string works fine (line 4 onwards), but I am struggling to save the string to the char* deleted_string (line 3) *deleted_string = *(*head)->name;
Everytime I run the code
// printf("%s", deleted_string ); only the first character is being printed; I think I understand that this is because pointers only point to the first character of a string, but is there a way to make the pointer point to the whole string? Perhaps by somehow converting (*head)->name to a string or an array?
Any help would be appreciated, sorry if this is a silly question. I have spent hours trying to find another page about this but I didn't so I thought I'd ask.
Assuming (*head)->name is of type char*, you are dereferencing both the char *deleted_string and char *name, hence operating on something of type char.
The line
*deleted_string = *(*head)->name;
is equivalent of doing something like
char a;
char b = 0;
a = b;
If you want to copy the contents of (*head)->name into the deleted_string, you can use strcpy or strncpy like,
strncpy( deleted_string, (*head)->name, SIZE );
Where the SIZE is whatever maximum size the deleted_string can hold. strcpy is the same, just without the size argument.
As comments suggested, both should be used with care, as strcpy can attempt to copy more characters than the destination can hold, causing write violations, and strncpy will truncate if the source is bigger than the destination, the resulting string will not necessarily be null-terminated. In such case, functions that assume the string is null-terminated will misbehave, such as printf( "%s" ... ), causing read violations. For more information, you can check this post.
In a program I am writing I made a Tokenize struct that says:
TokenizerT *Tokenize(TokenizerT *str) {
TokenizerT *tok;
*tok->array = malloc(sizeof(TokenizerT));
char * arr = malloc(sizeof(50));
const char *s = str->input_strng;
int i = 0;
char *ds = malloc(strlen(s) + 1);
strcpy(ds, s);
*tok->array[i] = strtok(ds, " ");
while(*tok->array[i]) {
*tok->array[++i] = strtok(NULL, " ");
}
free(ds);
return tok;
}
where TokenizeT is defined as:
struct TokenizerT_ {
char * input_strng;
int count;
char **array[];
};
So what I am trying to do is create smaller tokens out of a large token that I already created. I had issues returning an array so I made array part of the TokenizerT struct so I can access it by doing tok->array. I am getting no errors when I build the program, but when I try to print the tokens I get issues.
TokenizerT *ans;
TokenizerT *a = Tokenize(tkstr);
char ** ab = a->array;
ans = TKCreate(ab[0]);
printf("%s", ans->input_strng);
TKCreate works because I use it to print argv but when i try to print ab it does not work. I figured it would be like argv so work as well. If someone can help me it would be greatl appreciated. Thank you.
Creating the Tokenizer
I'm going to go out on a limb, and guess that the intent of:
TokenizerT *tok;
*tok->array = malloc(sizeof(TokenizerT));
char * arr = malloc(sizeof(50));
was to dynamically allocate a single TokenizerT with the capacity to contain 49 strings and a NULL endmarker. arr is not used anywhere in the code, and tok is never given a value; it seems to make more sense if the values are each shifted one statement up, and corrected:
// Note: I use 'sizeof *tok' instead of naming the type because that's
// my style; it allows me to easily change the type of the variable
// being assigned to. I leave out the parentheses because
// that makes sure that I don't provide a type.
// Not everyone likes this convention, but it has worked pretty
// well for me over the years. If you prefer, you could just as
// well use sizeof(TokenizerT).
TokenizerT *tok = malloc(sizeof *tok);
// (See the third section of the answer for why this is not *tok->array)
tok->array = malloc(50 * sizeof *tok->array);
(tok->array is not a great name. I would have used tok->argv since you are apparently trying to produce an argument vector, and that's the conventional name for one. In that case, tok->count would probably be tok->argc, but I don't know what your intention for that member is since you never use it.)
Filling in the argument vector
strtok will overwrite (some) bytes in the character string it is given, so it is entirely correct to create a copy (here ds), and your code to do so is correct. But note that all of the pointers returned by strtok are pointers to character in the copy. So when you call free(ds), you free the storage occupied by all of those tokens, which means that your new freshly-created TokenizerT, which you are just about to return to an unsuspecting caller, is full of dangling pointers. So that will never do; you need to avoid freeing those strings until the argument vector is no longer needed.
But that leads to another problem: how will the string be freed? You don't save the value of ds, and it is possible that the first token returned by strtok does not start at the beginning of ds. (That will happen if the first character in the string is a space character.) And if you don't have a pointer to the very beginning of the allocated storage, you cannot free the storage.
The TokenizerT struct
char is a character (usually a byte). char* is a pointer to a character, which is usually (but not necessarily) a pointer to the beginning of a NUL-terminated string. char** is a pointer to a character pointer, which is usually (but not necessarily) the first character pointer in an array of character pointers.
So what is char** array[]? (Note the trailing []). "Obviously", it's an array of unspecified length of char**. Because the length of the array is not specified, it is an "incomplete type". Using an incomplete array type as the last element in a struct is allowed by modern C, but it requires you to know what you're doing. If you use sizeof(TokenizerT), you'll end up with the size of the struct without the incomplete type; that is, as though the size of the array had been 0 (although that's technically illegal).
At any rate, that wasn't what you wanted. What you wanted was a simple char**, which is the type of an argument vector. (It's not the same as char*[] but both of those pointers can be indexed by an integer i to return the ith string in the vector, so it's probably good enough.)
That's not all that's wrong with this code, but it's a good start at fixing it. Good luck.
I have this structure of Node
typedef struct Node{
unsigned int length;
char *string;
} Node;
And this operation which accepts a pointer to a Node and tries to attach the provided string:
int setString(Node *node, char *string){
char *newString;
if(!isString(node) || !string) return 0;
newString = (char *) malloc(strlen(string)+1);
if(!newString) return 0;
/*THIS PART FAILS*/
strncpy(newString,string,sizeof(newString));
node->string = newString;
node->length = strlen(newString);
/*Which can be seen here*/
printf("Original String: %s\n",string);
printf("Copied String: %s\n",node->string);
return 1;
}
At the indicated part, I can see that the original string doesn't seem be copied over to node->string. It copies over the first two characters, and then what follows is either garbage or just blank.
I checked this post and I am following the third case, which seems to work for the OP. Maybe I overlooked something, but just can't figure out where
strncpy(newString,string,sizeof(newString));
In this context sizeof doesn't do what you want. Pass the size you allocated or don't use strncpy. If you follow your own logic, you already trust string since you took its strlen when you called malloc.
So you can safely use strcpy instead.
If you're willing to go a little non-portable, you could get away with:
newString = strdup(string);
Your sizeof() call is causing your problem:
sizeof(newString);
newString is a pointer to a character is declared here:
char *newString;
And character pointers use (normally) 2,4 or 8 bytes (depending on the machines architecture).
So it's clear, that you are only copy the first 2/4/8 bytes. Use strlen(string) + 1 for the number of characters to copy.
Or you can just use strcpy(). This will take care of the terminating null byte. Since you are calling malloc() correctly with strlen there is no chance to cause a overflow with strcpy().
You can not use the sizeof() in order to determine the string length.
You have to use the strlen(string) function instead.
Also you need to set \0 after copied symbols to terminate the string.
Not sure, but try directly this:
strncpy(node->string,string,strlen(newString));
Changing the length function to strlen.
(i tried to make the changes in code to bold)
So basically strcpy assigns the address of the 2nd argument to the 1st, but how does it do it with an array as the first argument? like in my program, i tried changing the address of the array but unfortunately it wont compile. So I had to resort to making a character pointer variable to assign the return value of capitalize. Is there something I'm misunderstanding?
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
typedef char string[20];
char *Capitalize(char *str)
{
int i;
char *temp;
temp = malloc(sizeof(char)*(int)(strlen(str)+1));
for(i = 0;i < strlen(str);i++)
{
if(*(str+i) >= 'a' && *(str+i)<= 'z')
*(temp+i) = *(str+i) - 32;
else
*(temp+i) = *(str+i);
}
*(temp+i) = '\0';
return temp;
}
int main(void)
{
string word;
printf("Enter word to capitalize: ");
scanf("%19s",word);
word = Capitalize(word);
printf("%s",word);
return 0;
}
strcpy() makes a copy, just like the name implies. it's perfectly legal to copy a string in to an array.
When you make an initialization of an array such as:
char myarr[] = "hello";
You're actually copying the characters into the array.
You seem to be confusing arrays with pointers (see here for some reason you can't treat them the same)
In C, qualifying an array by name without an indexer, is equivalent to specifying a pointer to the memory address of the first element in the array, that is why you can pass as a parameter an array to functions like strcpy.
char * strcpy ( char * destination, const char * source );
strcpy will copy whatever series of characters are found, starting at memory address specified by source, to the memory address specified by destination, until a null character (0) is found (this null character is also copied to the destination buffer).
The address values specified in the parameters are not modified, they just specify from where in memory to copy and where to. It is important that destination is pointing to a memory buffer (can be a char array or a block of memory requested via malloc) with enough capacity for the copied string to fit, otherwise a buffer underrun will occur (you will write characters past the end of your buffer) and your program might crash or behave in a weird way.
Hope I have been clear and not confused you more with my explanation ;)
The thing you seem to be missing is that in c/c++ strings ARE arrays, in most practical respects declaring
char c[] = "hello";
and
char* c = "hello";
is the same thing, all strcpy does is copy the characters into the destination memory, whether that memory is allocated as an array (presumably on the stack) or pointer (presumably on the heap);it does not make a difference.
I am trying to copy certain parts of a string into other, new strings, but when i try to do it and print the results it gives me weird output.. I really hope someone can help. I have a feeling that it is something about missing pointers.. Here is my source;
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
void getData(char code[], char ware[], char prod[], char qual[])
{
printf("Bar code: %s\n", code);
/* Copy warehouse name from barcode */
strncpy(ware, &code[0], 3);
ware[4] = "\0";
strncpy(prod, &code[3], 4);
prod[5] = "\0";
strncpy(qual, &code[7], 3);
qual[4] = "\0";
}
int main(){
/* allocate and initialize strings */
char barcode[] = "ATL1203S14";
char warehouse[4];
char product[5];
char qualifier[4];
getData(&barcode, &warehouse, &product, &qualifier);
/* print it */
printf("Warehouse: %s\nID: %s\nQualifier: %s", warehouse, product, qualifier);
return 0;
}
EDIT:
The wierd output is:
Bar code: ATL1203S14
Warehouse: ATL
ID: ♫203(♫>
Qualifier: S14u♫203(♫>
I think you meant '\0' instead of "\0" and 3 instead of 4:
ware[4] = "\0";
Try:
ware[3] = 0;
Also the & in getData(&barcode, &warehouse...) are useless. Just use getData(barcode, warehouse...);.
You're writing past the end of the chars in your getData() function. You've defined char product[5], which allocates 5 bytes of memory. That gives you array indexes 0,1,2,3,4. In getData, you write the product's null terminator to index 5, which is past the end of product, and will overwrite the next var's first character.
The same applies for barecode, warehouse, and qualifier.
Arrays in C and C++ are zero-based. The last index is one less than the length. You're setting a value in the memory after the array, for each of the arrays ware, prod and qual.
For example, instead of
char warehouse[4];
ware[4] = "\0";
you'd want:
char warehouse[4];
ware[3] = "\0";
getData(&barcode, &warehouse, &product, &qualifier);
This is not the way you should call getData. getData takes pointers, arrays are automatically converted to pointers, so theres no need to use the address-of operator &.
You should use
getData(barcode, warehouse, product, qualifier);
The sizes of the strings inside main() don't include a place for the sentinel.
You need to have:
char warehouse[5];
char product[6];
char qualifier[5];
Also, You are assigning a pointer to the string "\0" into a character, where you should be assigning the character '\0' itself.
I think I'd do things a bit differently. In particular, strncpy is almost never really useful (I'm reasonably certain it was invented for file names in the original Unix FS, and while it fits their specific requirements quite nicely, those requirements are sufficiently unusual that it's rarely good for much of anything else).
Instead, I'd use sscanf: sscanf(code, "%4c%5c%4c", ware, prod, qual);
Your question does not make it clear whether this is really correct. As others have pointed out, you're writing past the ends of the space you've allocated. Above, I've assumed you specified the number of characters you want to copy, so you'd have to expand each of the allocations by one character to make room for the terminator. Alternative, if you've already left room for the terminator and want one fewer character copied, you'd have to reduce each of the lengths above by one so the format string would be "%3c%4c%3c".