How to assign a string to struct variable in C? - arrays

I am unable to figure out how to assign a string to a struct variable using only <stdio.h> header file.
The following code gives me an error and I am unable to fix it.
#include <stdio.h>
struct Student
{
char name[50];
};
int main()
{
struct Student s1;
printf("Enter studen's name:\n");
scanf("%s",s1.name);
printf("Name : \n",s1.name);
s1.name={"Hussain"};
printf("Name : \n",s1.name);
}
It gives the following error while compilation:
test.c: In function 'main':
test.c:12:12: error: expected expression before '{' token
s1.name={"Hussain"};
^
I have tried initializing it in the following way:
s1.name="Hussain";
But this doesn't work too.
I could avoid this by the use of pointers as follows:
#include <stdio.h>
struct Student
{
char *name;
};
int main()
{
struct Student s1;
printf("Enter studen's name:\n");
scanf("%s",s1.name);
printf("Name : %s\n",s1.name);
s1.name="Hussain";
printf("Name : %s\n",s1.name);
}
This code works perfectly fine with no errors.
But I want to know where exactly I am doing wrong with the array, which is making my code not work.

A char array (and arrays in general) can't be assigned a value directly, only initialized. To write a string into a char array, use strcpy.
strcpy(s1.name, "Hussain");
The latter code where the name member is a pointer works for the assignment because the pointer is assigned the start address of the start of the string constant. Also note that you can't (at least not yet) use strcpy in that case because s1.name doesn't point anywhere. You would first need to allocate memory using malloc, or perform both steps at once using strdup. Also for this reason, you can't yet use scanf until you allocate memory.
If you're not allowed to use functions from string.h, then you would need to write the characters into the array one at a time, and then write a terminating null byte at the end.

Arrays do not have the assignment operator. So these assignment statements
s1.name = { "Hussain" };
s1.name = "Hussain";
are invalid.
You could use the standard C string function strcpy to copy elements of the string literal to the array s1.name like
#include <string.h>
//...
strcpy( s1.name, "Hussain" );
If you may not use standard string functions then you need to write a loop as for example
const char *p = "Hussain";
for ( char *t = s1.name; ( *t++ = *p++ ) != '\0'; );
Or
for ( char *t = s1.name, *p = "Hussain"; ( *t++ = *p++ ) != '\0'; );
Pay attention to that the second your program has undefined behavior. The pointer s1.name is not initialized and does not point to a valid object of an array type. So the call of scanf in this code snippet invokes undefined behavior.
struct Student s1;
printf("Enter studen's name:\n");
scanf("%s",s1.name);

If you can't use <string.h>, then you have to implement your own version of strcpy():
void copystring(char *dest, const char *src)
{
const char *p = src;
while (*p) {
*dest = *p;
p++;
dest++;
}
*dest = '\0'; // Null-terminate string (as pointed by #Ted)
}
Make sure that dest has enough space to hold src.
Also, avoid using scanf() in your code. Use fgets() as an alternative.
EDIT: As pointed by Jabberwocky, fgets() leaves \n read in the string. But since using <string.h> is not allowed, you have to implement your own function to replace it with a null-terminator:
int findchar(const char *str, char c)
{
int pos;
for (pos = 0; str[pos]; ++pos)
if (str[pos] == c)
return pos;
return -1;
}
You can use it like:
char str[100];
if (!fgets(str, sizeof str, stdin)) {
// fgets() failed. Do something.
} else {
int nwln = findchar(str, '\n');
if (nwln == -1) {
// You probably entered more than 100 characters
// because \n couldn't be found.
} else {
str[nwln] = '\0';
}
}

Related

Adding to an array in main via function argument

I'm not sure if I even worded the title correctly, but basically. I want to know if there is a way to add to the buff array from the hey function using the pointers in the arguments and why does it work if it does?
buf[100].
example:
int main(){
char buf[100];
hey("320244",buf);
printf("%s", buf);
}
void hey(char* s, char* result){
/*
some code that appends to result using pointers
do some stuff with s and get the result back in buf without using return.
*/
}
I have modified your code with some comments :-
#define LEN 100 //Use a macro instead of error prone digits in code
void hey(char* s, char* result); //Fwd declaration
int main(){
char buf[LEN] = {0}; //This will initialize the buffer on stack
hey("320244",buf);
printf("%s", buf);
hey("abc", buf); //Possible future invocation
printf("%s", buf);
}
void hey(char* s, char* result){
if(strlen(result) + strlen(s) < LEN ) //This will check buffer overflow
strcat(result, s); //This will concatenate s into result
else
//Do some error handling here
}
Let's do the right thing, and use a structure to describe a dynamically allocated, grow-as-needed string:
#include <stdlib.h>
#include <string.h>
#include <stdio.h>
struct mystring {
char *ptr; /* The actual string */
size_t len; /* The length of the string */
size_t max; /* Maximum number of chars allocated for */
};
#define MYSTRING_INIT { NULL, 0, 0 }
If we want to append something to a struct mystring, we define a function that takes a pointer to the structure the function can modify. (If it only needed a char pointer instead of a structure, it'd take a char **; a pointer to a char pointer.)
void mystring_append(struct mystring *ms, const char *s)
{
const size_t slen = (s) ? strlen(s) : 0;
/* Make sure ms points to a struct mystring; is not NULL */
if (!ms) {
fprintf(stderr, "mystring_append(): No struct mystring specified; ms == NULL!\n");
exit(EXIT_FAILURE);
}
/* Make sure we have enough memory allocated for the data */
if (ms->len + slen >= ms->max) {
const size_t max = ms->len + slen + 1;
char *ptr;
ptr = realloc(ms->ptr, max);
if (!ptr) {
fprintf(stderr, "mystring_append(): Out of memory!\n");
exit(EXIT_FAILURE);
}
ms->max = max;
ms->ptr = ptr;
}
/* Append. */
if (slen > 0) {
memmove(ms->ptr + ms->len, s, slen);
ms->len += slen;
}
/* We allocated one char extra for the
string-terminating nul byte, '\0'. */
ms->ptr[ms->len] = '\0';
/* Done! */
}
The (s) ? strlen(s) : 0; expression uses the ?: conditional operator. Essentially, if s is non-NULL, the expression evaluates to strlen(s), otherwise it evaluates to 0. You could use
size_t slen;
if (s != NULL)
slen = strlen(s);
else
slen = 0;
instead; I just like the concise const size_t slen = (s) ? strlen(s) : 0 form better. (The const tells the compiler that the slen variable is not going to be modified. While it might help the compiler generate better code, it is mostly a hint to other programmers that slen will have this particular value all through this function, so they do not need to check if it might be modified somewhere. It helps code maintenance in the long term, so it is a very good habit to get into.)
Normally, functions return success or error. For ease of use, mystring_append() does not return anything. If there is an error, it prints an error message to standard output, and stops the program.
It is a good practice to create a function that releases any dynamic memory used by such a structure. For example,
void mystring_free(struct mystring *ms)
{
if (ms) {
free(ms->ptr);
ms->ptr = NULL;
ms->len = 0;
ms->max = 0;
}
}
Often, you see initialization functions as well, like
void mystring_init(struct mystring *ms)
{
ms->ptr = NULL;
ms->len = 0;
ms->max = 0;
}
but I prefer initialization macros like MYSTRING_INIT, defined earlier.
You can use the above in a program like this:
int main(void)
{
struct mystring message = MYSTRING_INIT;
mystring_append(&message, "Hello, ");
mystring_append(&message, "world!");
printf("message = '%s'.\n", message.ptr);
mystring_free(&message);
return EXIT_SUCCESS;
}
Notes:
When we declare a variable of the structure type (and not as a pointer to the structure, i.e. no *), we use . between the variable name and the field name. In main(), we have struct mystring message;, so we use message.ptr to refer to the char pointer in the message structure.
When we declare a variable as a pointer to a structure type (as in the functions, with * before the variable name), we use -> between the variable name and the field name. For example, in mystring_append() we have struct mystring *ms, so we use ms->ptr to refer to the char pointer in the structure pointed to by the ms variable.
Dynamic memory management is not difficult. realloc(NULL, size) is equivalent to malloc(size), and free(NULL) is safe (does nothing).
In the above function, we just need to keep track of both current length, and the number of chars allocated for the dynamic buffer pointed to by field ptr, and remember that a string needs that terminating nul byte, '\0', which is not counted in its length.
The above function reallocates only just enough memory for the additional string. In practice, extra memory is often allocated, so that the number of reallocations needed is kept to a minimum. (This is because memory allocation/reallocation functions are considered expensive, or slow, compared to other operations.) That is a topic for another occasion, though.
If we want a function to be able to modify a variable (be that any type, even a structure) in the callers scope -- struct mystring message; in main() in the above example --, the function needs to take a pointer to variable of that type, and modify the value via the pointer.
The address-of operator, &, takes the address of some variable. In particular, &message in the above example evaluates to a pointer to a struct mystring.
If we write struct mystring *ref = &message;, with struct mystring message;, then message is a variable of struct mystring type, and ref is a pointer to message; ref being of struct mystring * type.
If I have understood you correctly you mean the following
#include <string.h>
//...
void hey(char* s, char* result)
{
strcpy( result, s );
}
Here is a demonstrative program
#include <stdio.h>
#include <string.h>
void hey( const char* s, char* result);
int main(void)
{
char buf[100];
hey( "320244", buf );
printf( "%s\n", buf );
return 0;
}
void hey( const char* s, char* result )
{
strcpy( result, s );
}
Its output is
320244
If the array buf already stores a string then you can append to it a new string. For example
#include <string.h>
//...
char buf[100] = "ABC";
strcat( buf, "320244" );
Take into account that the function hey should be declared before its usage and according to the C Standard the function main shall be declared like
int main( void )

Memset and characters

I aim to copy source string to dest string. If i compile the following program:
#include <stdio.h>
int main(void) {
char dest[6];
char source[6];
strcpy(dest,source);
while (*dest) { printf("%c",*dest++); }
while (*source) {printf("%c",*source++); }
return 0;
}
I get a runtime error. I suspect it is because strcpy copies from source to destination till it encounters \0. It did not,however,encounter the null character and kept on copying from the buffer till the runtime error occurred. To solve this problem, i modified the code as follows:
#include <stdio.h>
int main(void) {
char dest[6];
char source[6];
memset(dest, '\0', 6*sizeof(dest)); //trying to set dest to '/0'
strcpy(dest,source);
while (*dest) { printf("%c",*dest++); }
while (*source) {printf("%c",*source++); }
return 0;
}
i get the following errors:
prog.c:11:38: error: lvalue required as increment operand
while (*dest) { printf("%c",*dest++); }
^
and
prog.c:11:38: error: lvalue required as increment operand
while (*dest) { printf("%c",*source++); }
^
Why does this happen?
For starters it is the source array that shall be zero terminated if you are going to copy it in another character arrays using the standard C function strcpy. So instead of this statement
memset(dest, '\0', 6*sizeof(dest));
you should at least write
memset(source, '\0', 6*sizeof(source));
^^^^^^ ^^^^^^^
However even this statement is wrong because it overwrites the memory allocated for the array. sizeof( source ) is already equal to 6 bytes as it is followed from the array declaration
char source[6];
Thus you have to write
memset(source, '\0', sizeof(source));
^^^^^^^^^^^^^
In fact there was enough to write either like
char source[6] = { '\0' };
or like
char source[6] = "";
or like
char source[6];
source[0] = '\0';
Arrays are non-modifiable lvalues. Thus you may not write for example the following way
while (*dest) { printf("%c",*dest++); }
Instead of this statement you could write
for ( char *p = dest; *p; ++p ) { printf("%c", *p); }
Take into account that nothing will be outputted because the array contains an empty string. You could initialize the source array with some non-empty string literal.
the following code cleanly compiles, and performs the desired operation.
The differences between the posted code and this are commented.
#include <stdio.h> // printf()
#include <string.h> // strcpy()
int main(void)
{
char dest[6]; // declared, containing garbage
char source[6] = "12345"; // declared, containing the string "12345\0"
strcpy(dest,source);
// now both arrays contain the string "12345\0"
// best to use a 'for()' statement for indexing through an array
for( size_t i=0; dest[i]; i++ ) { printf("%c", dest[i]); }
printf( "\n" ); // output the buffered data to the terminal
for( size_t i=0; source[i]; i++ ) { printf("%c", source[i]);}
printf( "\n" ); // output the buffered data to the terminal
// note, the following lines contain a precedence problem in
// the increment expressions and
// the address of an array declaration cannot be incremented
//while (*dest) { printf("%c",*dest++); }
//while (*source) {printf("%c",*source++); }
//return 0;// with modern C compilers,
// this line is not necessary in a 'main()' function
// when returning 0
} // end function: main
strcpy is not a safe function, prefer using strncpy.
The error is due to the fact that you try to increment the array, which is an rvalue (i.e. a constant, you can not put it to the left side of a sign =).
The common approach to iterate over an array is to use a pointer like so:
char *p = dest;
while (*p) { printf("%c",*p++); }

What's wrong with my code function to make strcat function in C?

#include <stdio.h>
#include <stdlib.h>
char wordsum(char FW[256],char SW[256]){
int i;
int j=strlen(FW);
for (i=0;i<=strlen(SW);i++)
FW[i+j+1]=SW[i];
printf("%c",FW);
return FW;
}
int main()
{
char F[256];
char S[256];
printf("Enter the first word\n");
gets(F);
printf("Enter the Second word\n");
gets(S);
wordsum(F,S);
return 0;
}
I don't know what is wrong with my code to make strcat function. I hope to find the answer.
I assume that the code is written to learn more about the C language. If so, may I present an alternative implementation which does not use strlen(). The intention is to present some of the really nice features in the language. It may be a bit complicated to wrap ones head around the first time, but IIRC the code can be found in K&R's book The C Programming Language.
Here we go:
char* mystrcat(char *dest, const char *src)
{
char *ret = dest;
while (*dest)
dest++;
while ((*dest++ = *src++))
;
return ret;
}
The first while-loop finds the end of the destination string. The second while-loop appends the source string to the destination string. Finally, we return a pointer to the original dest buffer.
The function could've been even nicer if it didn't return a pointer.
void mystrcat(char *dest, const char *src)
{
while (*dest)
dest++;
while ((*dest++ = *src++))
;
}
HTH
There are several mistakes in your code. They are:
1) A function can't return an array in C and you don't need to do so. Change the return type from char to void of wordsum and erase the line return FW;
2) You want to print a string, right? Format specifier for string is %s. So write printf("%s",FW); instead of printf("%c",FW);.
3) Do this: FW[i+j]=SW[i];. Why did you add an extra 1 to i+j? Just think logically.
4) Add header file for strlen(), it's <string.h>.
5) Erase those asterisk marks before and after FW[i+j]=SW[i];.
There are a few problems in your function, I've changed and commented them below:
char *wordsum(char FW[256],char SW[256]){ // correct function type
int i;
int j=strlen(FW);
for (i = 0; i <= strlen(SW); i++)
FW[i+j] = SW[i]; //change 'i + j + 1' to 'i + j'
printf("%s",FW); //change format specifier as you are printing string not character
return FW;
}
Then dot forget to capture the returned pointer using a char* variable in the calling function (here main())
char *result;
result = wordsum(F,S);
printf("\n%s\n", result);
Working example: https://ideone.com/ERlFPE

simple strcat implementation with pointers

so I was practicing writing c code with pointers using the K&R. For one problem with strcat function, I couldn't find out what was wrong with my code, which according to Visual Studio, returned the destination string unchanged after the strcat function. Any suggestion is appreciated!
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
int strcat(char* s, char* t);
int main(void)
{
char *s="hello ", *t="world";
strcat(s,t);
printf("%s",s);
return 0;
}
int strcat(char* s,char* t)
{
int i;
i=strlen(s)+strlen(t);
s=(char*) malloc(i);
while(*s!='\0')
s++;
while('\0'!=(*s++=*t++))
;
return 0;
}
I'm pretty sure that strcat returns a char* in the real implementation (holding the original value of the first string).
strcat is not supposed to alter the first parameter's address, so you shouldn't call malloc.
Point #2 means that you need to declare char *s as char s[20] in main (where 20 is some arbitrary number big enough to hold the whole string).
If you really want to alter the value of the an input parameter you will need to pass the address of the value - so it would need to be strcat(char **s, ...) in the function declaration/definition, and called with strcat(&s, ...) in main.
1) defining string in this way
char *s="hello "
means that you are defined a literal string. a literal string is saved into read only memory so you can not edit it
you have to define your string as a char array in order to be able to edit it
char s[100] = "hello ";
2) when you define your function in this way
int strcat(char* s,char* t)
you can not change the address of s into the function strcat(). So assigning memory with malloc() into the function will not change the s address when leaving the function
3) change your function strcat to
int strcat(char** s,char* t)
{
int i;
char *u, *v;
i=strlen(*s)+strlen(t);
v = *s;
u=(char*) malloc(i+1);
while(*v!='\0')
*u++ = *v++;
while('\0'!=(*u++=*t++));
*s = u;
return 0;
}
and you call it in the main with:
char *s="hello ", *t="world";
strcat(&s,t);
In
strcat(char* s, char* t)
the 's' is send by value. The value of 's' at call time is copied into the stack then strcat() is call. At the return of strcat the modified version is discard from the stack. So the calling value of 's' is never changed (and you create a memory leak).
Beward, in C every memory cell can be change, even parameters or instructions sections; some changes can be very hard to understand.
Since you are trying to do like the real strcat it's said that the first parameter
The string s1 must have sufficient space to hold the result.
so you don't need to use malloc
char *strcat(char* s, const char* t);
int main(void)
{
char s[15] = {0}; //
char *t = "world"; //const char * so you can't change it
strcpy(s, "Hello ");
strcat(s,t);
printf("%s\n",s);
return (0);
}
char *strcat(char* s, const char* t)
{
int i = 0;
while (s[i] != '\0')
i++;
while (*t != '\0')
s[i++] = *t++;
s[i] = '\0'; //useless because already initialized with 0
return (s);
}
#include<stdio.h>
#include<string.h>
#define LIMIT 100
void strcatt(char*,char*);
main()
{
int i=0;
char s[LIMIT];
char t[LIMIT];
strcpy(s,"hello");
strcpy(t,"world");
strcatt(s,t);
printf("%s",s);
getch();
}
void strcatt(char *s,char *t)
{
while(*s!='\0')
{
s++;
}
*s=' ';
++s;
while(*t!='\0')
{
*s=*t;
s++;
t++;
}
*s=*t;
}
Dear user,
you don't have to complicate things that much. The simpliest code for strcat, using pointers:
void strcat(char *s, char *t) {
while(*s++); /*This will point after the '\0' */
--s; /*So we decrement the pointer to point to '\0' */
while(*s++ = *t++); /*This will copy the '\0' from *t also */
}
Although, this won't give you report about the concatenation's success.
Look at this main() part for the rest of the answer:
int main() {
char s[60] = "Hello ";
char *t = "world!";
strcat(s, t);
printf("%s\n", s);
return 0;
}
The s[60] part is very important, because you can't concatenate an another string to it's end if it doesn't have enough space for that.

Tokenizing a string in C

I'm trying to store a string with a first and last name from a string into a struct but I'm getting (warning: passing argument 1 of strcpy makes pointer from integer without a cast), and I'm not sure on where to put strcpy tried putting it in the while loop got the error which makes sense. But not sure on where to place strcpy
EDITED
struct trip
{
char first_name;
char last_name;
}
int main(void)
{
struct trip travel[12];
}
char input_name(struct trip travel[MAXTRIP], int index)
{
int name_read, length;
int name_bytes = 100;
char *name, *word;
getchar();
printf("Please enter name:\n");
name = (char *)malloc(name_bytes + 1);
name_read = getline (&name, &name_bytes, stdin);
word = strtok(name, ",");
while (word != NULL)
{
strcpy(travel[index].first_name, word);
word = strtok(NULL, ",");
}
}
Ignoring the (MANY) errors in your code, you are putting the strcpy() in the right place.
However, you are not calling it with the correct arguments: strcpy() needs 2 arguments.
Basically, both are of type char*; you are passing a char and a char* and that is why the compiler complains (for the compiler the char behaves like an int so it says "strcpy makes pointer from integer").
You need to review your data structure and pass the right char*s to strcpy().

Resources