how to load a char[] that's a member of Stuct[i]? - c

Let's say we have this struct
struct Foo{
int FooLength; //length of Foo
char FooChar[4];
};
and then in the main we have
int sizeFoo = 100; struct Foo myFooList[sizeFoo];
what would be the best way to input data for FooChar? Would strncpy, or memcpy, or snprintf, or sprintf?
what I wish to do is something like
myFooList[0].FooLength = 3;
myFooList[0].FooChar = "dog";
myFooList[1].FooLength = 3;
myFooList[1].FooChar = "cat";
.
.
.
with a correct syntax since in C you can't just = "string"; here, and I'm not sure what would be the best way to go about it? I have look at similar topics, but I just get more confused with how strncpy or sprintf are not good or you have to have a \0 added at the end or some other detail that makes picking what to do more difficult.
Also if all the values of myFooList[] are already know (they are const or static) is there a way to initialize like one would do any other array?

If your input is always 3 characters, you can use strcpy, otherwise use strncpy(myFooList[0].FooChar, "dog", 3). You must add the terminating null character if using strncpy. strcpy will add the termination null character automatically, just like VHS has in his answer. In either case, you should still validate that your input does not exceed the maximum length. To find the length of a string(i.e. the number of char characters up to the first null character), you would use strlen. To determine the capacity of a char a[], you can use _countof(a). Don't forget that one of those has to be a '\0'.
memcpy would also work, but it would be unusual to do that with a string.
You wouldn't use sprintf here. sprintf would normally be used when you need to create a unique string using dynamic data at runtime. This is not what you're doing here. If you have any experience with .NET, it is the C equivalent of string.Format.
To initialize an array of 'Foo', you will just need to write a function that will do that. Even if you figure out the syntax to do it in one line, it'll be very difficult to read and maintain. Here's an example without validation, I will leave that task to you.
myFooList[0].FooLength = 3;
strncpy(myFooList[0].FooChar, "dog", 3);
myFooList[0].FooChar[3] = '\0';
myFooList[1].FooLength = 3;
strncpy(myFooList[1].FooChar, "cat", 3);
myFooList[1].FooChar[3] = '\0';

Your integer assignment is correct, but the string assignment is not. Following is the right way:
myFooList[0].FooLength = 3;
strcpy( myFooList[0].FooChar, "dog");
myFooList[1].FooLength = 3;
strcpy(myFooList[1].FooChar, "cat");

what would be the best way to input data for FooChar? Would strncpy,
or memcpy, or snprintf, or sprintf? ...
but I just get more confused with how strncpy or sprintf are not good
or you have to have a \0 added at the end or some other detail that
makes picking what to do more difficult.
Well, memcpy is a good choice if you don't want terminate nul byte. I don't really understand what is your question here.
Also if all the values of myFooList[] are already know (they are const
or static) is there a way to initialize like one would do any other
array?
In your example, no, because you use VLA who can't be initialize. But you could do the following:
#include <stdio.h>
struct Foo {
int FooLength; // length of Foo
char FooChar[4];
};
int main(void) {
struct Foo myFooList[] = {{3, "dog"}, {3, "cat"}};
size_t size = sizeof myFooList / sizeof *myFooList;
}

Related

Can I emulate strcpy using malloc?

I'm trying to make a strcpy function from scratch for a class. While I could do it with a for loop and copy the individual characters, I think I could just make a swap using malloc and pointers to make it more efficient. Here's my code, but I've been getting a lot of confusing errors.
void notStrcpy(char s1[], char s2[]) { //copies string s1 into s2
char *s3 = (char *) malloc(strlen(s1)); //s3 is now an alias of s1
s2 = *s3;} //dereference s3 to dump s1 into s2
Why is this happening, and is there any way to make this code work the way I intended it?
You cannot do that: strcpy expects both chunks of memory to be ready - one for reading the string, and the other one for writing the string. Both addresses are expected to have enough memory for the actual content of a null-terminated C string.
On the other hand, malloc gives you a third chunk of memory (you need to allocate strlen(s)+1, but that's a completely different story). String copy algorithm has no use for that chunk of memory. On top of that, assigning parameters of a function has no effect on the values passed into your function, so s2 = *s3 is not doing what you think it should be doing.
Long story short, while ((*s1++ = *s2++)); is your simplest strcpy implementation.
Note: malloc could come in handy in an implementation of string duplication function, e.g. strdup. If you decide to give it a try, don't forget to allocate space for null terminator.
#dasblinkenlight Thank you. My new code is as follows:
void totallyNotstrcpy(char s1[], char s2[]) {
int x = 0;
while (x < strlen(s1)+1) {
s2[x] = s1[x];
x++;
}
}
As a quick side question, how does your code snippet work? Doesn't the while loop need a condition?

How to modify the content in one single string in C?

It's simple question but i just couldn't figure out. I've been trying to make an approach to replace the content of one string by part of it's content like, replace "He is a boy" to "is a boy" as follow:
int main() {
char array[] = "he is a boy";
strcpy(array, &array[3]);
printf("%s\n", array);
}
But the program just stopped at strcpy statement.
Is there any problem using strcpy or any other method to achieve the same purpose??
BTW, I'm using X-code on my mac. Thx~
Yes, you cannot use strcpy() when the source and destination overlap. This is clearly stated in the manual page:
The strings may not overlap, and the destination string dest must be large enough to receive the copy.
You can use memmove(), but then you have to specify the length and probably deal with termination issues yourself since it's a general-purpose memory-manipulation function, and not designed for strings specifically.
In your case since you're copying the tail, we can just include the termination and be fine:
int main(void) {
char array[] = "he is a boy";
memmove(array, array + 3, 9);
printf("%s\n", array);
return 0;
}

Copying a string to a pointer doesn't seem to work

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)

Char x[50] and Char x[100] Output

I'm not used to C as I'm primarily a Java guy, with some knowledge of C++, so forgive me if this is a trivial question. I could not seem to find an answer while searching online.
I'm initializing a char array...
char tcp[50];
So that I can concatenate a const char and a char. In examples I saw an easy way to do this was by creating that empty char array and then using...
strcat(x,y);
To stick them together.
Problem is, printing out the blank char array when it is set to "50" gives me a result of:
X??|?
When I change it to...
char tcp[100];
And print it, its blank. Why is this?
The array contents are undefined, assuming it is a local (automatic) array.
Use:
char tcp[50] = "";
Or:
char tcp[50] = {0};
Or:
char tcp[50];
tcp[0] = 0;
Or:
char tcp[50];
memset(tcp, 0, sizeof(tcp));
As you like.
Always null terminate you char arrays before doing anything:
tcp[0] = '\0';
C happily allocates the space for the array you declare, but it does not set its content to 0.
Therefore, the content of the array you're printing is random (or rather depending in the previous contents of the memory)
When creating an array, the compiler puts it somewhere in memory but does not initialize it, so whatever is in that memory when the program is started will be the initial "string".
Terminate the string manually after you created the array, either by making the whole array "zeroed" out, or just put zero as the first character:
char tcp[50] = { '\0' };
Or
char tcp[50];
/* ... */
tcp[0] = '\0';
The difference here is, you're essentially working with two empty arrays trying to merge them in the memory space of one (not sure if that makes sense for you).
First of all, in C you have to terminate strings with \0. That's something not exposed or visible in Java. Also you essentially used two undefined strings (as there's no value set).
#include <stdio.h>
#include <string.h>
char target[256];
const char source_a[] = "Hello";
const char source_b[] = "World!";
int void(main)
{
target[0] = '\0'; // this essentially empties the string as we set the first entry to be the end. Depending on your language version of C, you might as well write "char target[256] = {'\0'};" above.
strcat(target, source_a); // append the first string/char array
strcat(target, " "); // append a const string literal
strcat(target, source_b); // append the second string
printf("%s\n", target);
return 0;
}
Important: Using strcat() can be unsave, as there's no length check performed, and other than Java, these "strings" have a fixed length (the one you set when defining the variables). If there's no length given, but you copy a string on initialization, that length is taken (e.g. char test[] = "Hello!"; will be 7 chars long (due to terminating \0)).
If you'd like a more Java like approach on strings, use C++ and the std::string class, that performs a lot more similar to Java's strings.

C program giving weird output

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".

Resources