How to add text to a variable in C? - c

I'm learning C at the moment and I run into some problem, hard to understand what is going on with variables and adding text to variable in C.
I know C is not treating the strings and character as in other programming language.
If I understand it correctly from my book:
I have to define a variable before I can use it, that's ok for me.
So, If I do this code, where I wish to print the variable text_1 it is failing:
#include <stdio.h>
int main()
{
char text_1[];
text_1[] = "Testing";
printf("Test 1 is: %s", text_1);
return(0);
}
But if I do this way, this is working:
#include <stdio.h>
int main()
{
char text_1[] = "Testing";
printf("Test 1 is: %s", text_1);
return(0);
}
In some other programming language I can do this way:
Dim a as string
a="Testing"
print("Testing 1 is:", a) --> or similar option to print out the variable 'a'.
What is the correct way to do this in C?
Thank you.

Oops... C language is a rather low level language if you compare it to Java, Python or Ruby, or even Basic or JavaScript:
it has no notion of text string but only uses null terminated character arrays in its standard library
arrays by themselves are not first class citizens: except at initialization time, the language can only process arrays elements and not the full array
Long story made short, an array has a size that is defined only once (at definition time) and will never change during the life time of the array. char text_1[] = "Testing"; is an idiomatic initialization: the size of the array is set to the number of characters of the literal string + 1 for the terminating null, so here 8. After that text_1 will be able to contain other strings of at most 7 characters + 1 terminating null if you copy the relevant character for example with strcpy.
To go back to your code, char text_1[]; declares an incomplete array with a declared size of 0 bytes. That means that you cannot use it. The 2 correct ways would be:
char text_1[] = "Testing"; // idiomatic initialization of a 8 characters array
or
char text_1[8]; // definition of an uninitialized char array of size 8
strcpy(text_1, "Testing"); // copy a string into the array
Not really sexy, but C language is like that...

Ok, for conclusion, what is the correct way to learn how to set up a variable with string in a way I can print it to the screen or use it for compare with other variables who are also holding strings?
I like this way but I'm not sure is it correct to use:
char * text_1; // btw. what is this `*` meaning here?
text_1 = "Some text...";
printf("Variable text is: %s\n",text_1);
but this way is also acceptable by me:
char text_1[n]; // where n is a number of max char
strcpy(text_1, "Some text...");
printf("Variable text is: %s\n",text_1);

Related

Is it possible to extract the size of an array of char pointers in C [duplicate]

This question already has an answer here:
Number of elements in static array and dynamic array
(1 answer)
Closed 4 years ago.
I need to specify the length of an array of char pointers as an input to a function in C. I don't think it is possible to know this in C without some trick (like iterating until a certain sentinel string is found), but I'm wondering if perhaps gcc has some function that would extract this for me?
const char *names[] = {"string1","next_string","test"};
//Later in code
int n_fields = <magic>(names);
In this case I would be looking for n_fields to be 3.
My current alternative is to manually count and specify the length, but this means I need to ensure that these two values stay linked manually.
Edit regarding duplicate question: Unlike arrays of integers it was not obvious to me what the two sizeof parameters in other examples would be measuring for an array of char pointers. Specifically I thought the denominator might be measuring string length, when in reality it was measuring the size of a pointer. Pretty much every example online is for an array of ints, not char pointers.
Sure thing:
#define ARRAY_SIZE(names) (sizeof(names)/sizeof((names)[0]))
#include <stdio.h>
const char *names[] = {"string1","next_string","test"};
//Later in code
int n_fields = ARRAY_SIZE(names);
int main()
{
printf("%d\n", n_fields); //prints 3
}
Keep in mind that you need to make sure you're applying ARRAY_SIZE to a real array, not a pointer.
void f (const char *names[])
{
//!WRONG: names is actually a pointer here
printf("%d\n", (int)ARRAY_SIZE(names));
}
To protect yourself, you can beef up ARRAY_SIZE with some gcc/clang/tcc extensions so that the erroneous code in the snippet above no longer compiles but the example with a real array continues to:
#define ARRAY_SIZE(X) ( 0*sizeof(char [ \
__builtin_types_compatible_p(__typeof(X),__typeof((X)+0)) ?-1:1 ] ) \
+sizeof(X)/sizeof((X)[0]) )
Once the array decays to a pointer, the original size can no longer be recovered through standards means, which is why functions taking array parameters (really pointer parameters) where the array isn't terminated with a sentinel usually also accept an array size parameter.

Segmentation fault of small code

I am trying to test something and I made a small test file to do so. The code is:
void main(){
int i = 0;
char array1 [3];
array1[0] = 'a';
array1[1] = 'b';
array1[2] = 'c';
printf("%s", array1[i+1]);
printf("%d", i);
}
I receive a segmentation error when I compile and try to run. Please let me know what my issue is.
Please let me know what my issue is. ? firstly char array1[3]; is not null terminated as there is no enough space to put '\0' at the end of array1. To avoid this undefined behavior increase the size of array1.
Secondly, array1[i+1] is a single char not string, so use %c instead of %s as
printf("%c", array1[i+1]);
I suggest you get yourself a good book/video series on C. It's not a language that's fun to pick up out of the blue.
Regardless, your problem here is that you haven't formed a correct string. In C, a string is a pointer to the start of a contiguous region of memory that happens to be filled with characters. There is no data whatsoever stored about it's size or any other characteristics. Only where it starts and what it is. Therefore you must provide information as to when the string ends explicitly. This is done by having the very last character in a string be set to the so called null character (in C represented by the escape sequence '\0'.
This implies that any string must be one character longer than the content you want it to hold. You should also never be setting up a string manually like this. Use a library function like strlcpy to do it. It will automatically add in a null character, even if your array is too small (by truncating the string). Alternatively you can statically create a literal string like this:
char array[] = "abc";
It will automatically be null terminated and be of size 4.
Strings need to have a NUL terminator, and you don't have one, nor is there room for one.
The solution is to add one more character:
char array1[4];
// ...
array1[3] = 0;
Also you're asking to print a string but supplying a character instead. You need to supply the whole buffer:
printf("%s", array1);
Then you're fine.
Spend the time to learn about how C strings work, in particular about the requirement for the terminator, as buffer overflow bugs are no joke.
When printf sees a "%s" specifier in the formatting string, it expects a char* as the corresponding argument, but you passed a char value of the array1[i+1] expression. That char got promoted to int but that is still incompatible with char *, And even if it was it has no chance to be a valid pointer to any meaningful character string...

2-dimensional array of chars returns SEGFAULT

I'm beginner with C and I'm trying to create an array of strings saved like this:
[1][firststring]
[2][secondstring]
[2][thirdstring]
.
.
.
My implementation looks like:
int counter = 0;
char for_pole[50][50];
strcpy(for_pole[counter][50],"hello");
counter++;
//then i want to print it:
printf("my string: %s", for_pole[0][50]); //prints out first string
printf("my string: %s", for_pole[1][50]); //...and second one
but returns segmentation fault.
Should i use some dynamic allocation of memory?
As I've told I'm novice, so sorry for bad question.
I do not see where in your code there is the second string. I see only one string `"hello".
You can write for example the following way
int counter = 0;
char for_pole[50][50];
strcpy(for_pole[counter],"hello");
counter++;
strcpy(for_pole[counter],"world");
//then i want to print it:
printf("my string: %s\n", for_pole[0]); //prints out first string
printf("my string: %s\n", for_pole[1]); //...and second one
As for this expression
for_pole[counter][50]
then 1) index 50 is outside the array because the valid range of indices is 0 - 49 and 2) it has type char instead of to be an array or a pointer to char that is required by function strcpy or by the format specifier %s. of function printf.
When you write
strcpy(for_pole[counter][50],"hello");
You're writing the string "hello" to a char. Moreover, it is on the position 50 of an array that goes from 0 to 49.
you should change it to
strcpy(for_pole[counter],"hello");
because "for_pole[i]" is the i-th string and "for_pole[i][j]" is the j-th character of that string.
Similarly that printf should be
printf("my string: %s", for_pole[0]);
I would add a '\n' to get things a little bit more organized
Finally, the code would be like this
int counter = 0;
char for_pole[50][50];
strcpy(for_pole[counter],"hello");
counter++;
printf("my string: %s\n", for_pole[0]); //prints out first string
printf("my string: %s\n", for_pole[1]); //prints out second string
initialize for_pole variable with zero.
char for_pole[50][50] = {0,};
Jon.e, there are some reasons for SEGFAULT.
Even when there is no bug at all, but rather there are a lack of memory.
Some guys tell you, to pay attention to compiler message and warning, yes, but that's just a part of story.
Related to SEGFAULT there are the following most notable kinds of SEGFAULTS, that I can tell you by my own experience:
1. You are trying to access to indices which do not exist.
Array has the size, exactly same size which you have specified while declaring an array.
Review this code:
/* "Array out of bounds" error
valid indices for array foo
are 0, 1, ... 999 */
int foo[1000];
for (int i = 0; i <= 1000 ; i++)
foo[i] = i;
Here we have one illegal access to an index which does not exist.
2. You are trying to access to the value which does not exist.
In this case memory exists but the value...
/* Illegal memory access if value of n is
not in the range 0, 1, ... 999 */
int n;
int foo[1000];
for (int i = 0; i < n ; i++)
foo[i] = i;
This is also one of the most common pitfalls.
This pitfall is so fundamental, even experienced developers sometime make such mistake. The problem is in uninitialized memory for variable n.
Initialization is process of putting value of the variable its first value, If you want, we can say that it's process of losing virginity of the variable.
There are very chaotic rule of when variable is initialized and when - not. To complex for remembering. Just always initialize variables.
3. You are trying to access to the memory via pointers.
And that pointer does not point anywhere. You are trying to read something from NOWHERE? It does not make sense, does it?
/* Illegal memory access because no memory
is allocated for foo2 */
float *foo, *foo2;
foo = (float*)malloc(1000);
foo2[0] = 1.0;
What happens, if you forget to initialize variable( 2-nd ) or pointer (3-rd case). The answer is broad: from nothing to catastrophe.
Why so? Because memory is the something which has been used by a lot of applications, and it's shared between hundreds of thousands applications running on a computer. So when you create a variable it creates the segment in the memory for that variables, but does not clean that memory (to be precise, in some cases it has been nulled, in others - not) Just assume that is never cleared. So in such situations, no matter the problem caused by variable or by pointer (which is actually is a variable too, but that's another story), we say that, variable stores 'garbage'.
Note, it's not obvious, to find those kind of SEGFAULTS, sometimes it's almost impossible, so you must be ready for such situations, and should use debugger for example gdb, to eliminate the bug.
Also avoid such dummy errors, like. The practice with my students show that it's very very common error.
int n = 100;
int foo[n];
use instead
int foo[100]
or
const int n = 100;
int foo[n];
or
enum N { N = 100 };
int is[N];
Additional references:
Can a const variable be used to declare the size of an array in C?
https://kb.iu.edu/d/aqsj
You misunderstand...
...how strings and array indexing work together. A string is an array of characters. For example this is a string:
char some_string[20] = "Hello";
And this is how you print it:
printf("%s\n", some_string);
And this is how you use strcpy() with it:
strcpy(some_string, "Goodbye");
And this is how you access the i-th character in the string:
/* Not compilable by itself; just an example. */
some_string[i]
Notice how the only time you used [...] was in declaring it and accessing a specific character in the array of characters. However, that is for a single string.
For an array of strings, you declare it as a 2-dimensional array of characters, just as you've done with for_pole:
/* An array of 50 strings, all of which can store a maximum of 49
* characters, plus a null termination character for each string.
*/
char for_pole[50][50];
To use strcpy() with the counter-th string:
strcpy(for_pole[counter], "hello");
And to print the first (0-th) string:
printf("my string: %s", for_pole[0]);
And to print the i-th character of the first string:
printf("string[%d]: %c", i, for_pole[0][i]);
Again, notice how I didn't use [50] every time here. If you have a string, you access it using its name and each character using string[i]. If you have an array of strings, you access the array using its name and each string using array[i] notation. To access the j-th character of the i-th string in the array:
/* Not compilable by itself; just an example. */
array[i][j]
Why your version segfaults
You don't need to use [50] in every expression the way you do. Notice the last expression array[i][j] to access a single character. Since a character is represented by an integer value, the compiler will then convert that integer to a pointer where necessary.
This means that doing something like strcpy(for_pole[counter][50],"hello"); will try to copy the string "hello" to whatever memory address the compiler thinks the character for_pole[counter][50] holds. For example, if the character is the letter A, represented by the integer 65 on my system, then the program would try to copy all 6 bytes of the string "hello" to memory address 65. My program doesn't have permission to write to that memory address, so it segfaults. And that's the problem you are experiencing.

Pointers and Arrays in C, Need for more Understanding

I was doing some pointers and arrays practice in C and I noticed all my four methods returned the same answer.My question is are there disadvantages of using any one of my below methods? I am stunned at how all these four give me the same output. I just noticed you can use a pointer as if it was an array and you can also use an array as if it was a pointer?
char *name = "Madonah";
int i= 0;
for (i=0;i<7; i++){
printf("%c", *(name+i));
}
char name1 [7] = "Madonah";
printf("\n");
int j= 0;
for (j=0;j<7; j++){
printf("%c", name1[j]);
}
char *name2 = "Madonah";
printf("\n");
int k= 0;
for (k=0;k<7; k++){
printf("%c", name2[k]);
}
char name3 [7] = "Madonah";
printf("\n");
int m= 0;
for (m=0;m<7; m++){
printf("%c", *(name+m));
}
Results:
Madonah
Madonah
Madonah
Madonah
It is true that pointers and arrays are equivalent in some context, "equivalent" means neither that they are identical nor even interchangeable. Arrays are not pointers.
It is pointer arithmetic and array indexing that are equivalent, pointers and arrays are different.
which one is preferable and the advantages/Disadvantages?
It depends how you want to use them. If you do not wanna modify string then you can use
char *name = "Madonah";
It is basically equivalent to
char const *name = "Madonah";
*(name + i) and name[i] both are same. I prefer name[i] over *(name + i) as it is neat and used most frequently by C and C++ programmers.
If you like to modify the string then you can go with
char name1[] = "Madonah";
In C, a[b], b[a], *(a+b) are equivalent and there's no difference between these 3. So you only have 2 cases:
char *name = "Madonah"; /* case 1 */
and
char name3 [7] = "Madonah"; /* case 2 */
The former is a pointer which points to a string literal. The latter is an array of 7 characters.
which one is preferred depends on your usage of name3.
If you don't intend to modify then the string then you can use (1) and I would also make it const char* to make it clear and ensure the string literal is not modified accidentally. Modifying string literal is undefined behaviour in C
If you do need to modify it then (2) should be used as it's an array of characters that you can modify. One thing to note is that in case (2), you have explicitly specified the size of the array as 7. That means the character array name3 doesn't have a null terminator (\0) at the end. So it can't be used as a string. I would rather not specify the size of the array and let the compiler calculate it:
char name3 [] = "Madonah"; /* case 2 */
/* an array of 8 characters */
Just in addition to what others said, I will add an image for better illustration. If you have
char a[] = "hello";
char *p = "world";
What happens in first case enough memory is allocated for a (6 characters) on the stack usually, and the string "hello" is copied to memory which starts at a. Hence, you can modify this memory region.
In the second case "world" is allocated somewhere else(usually in read only region), and a pointer to that memory is returned which is simply stored in p. You can't modify the string literal in this case via p.
Here is how it looks:
But for your question stick to notation which is easier, I prefer [].
More info on relationship between arrays and pointers is here.
In all cases, in C pointer + index is the same as pointer[index]. Also, in C an array name used in an expression is treated as a pointer to the first element of the array. Things get a little more mystifying when you consider that addition is commutative, which makes index + pointer and index[pointer] legal also. Compilers will usually generate similar code no matter how you write it.
This allows cool things like "hello"[2] == 'l' and 2["hello"] == 'l'.
it is convenient to use array syntax for random access
int getvalue(int *a, size_t x){return a[x];}
and pointer arithmetic syntax for sequential access
void copy_string(char *dest, const char *src){while((*dest++=*src++));}
Many compilers can optimize sequential accesses to pointers better than using array indices.
For practicing pointer and array idioms in C, those are all valid code blocks and illustrative of the different ways of expressing the same thing.
For production code, you wouldn't use any of those; you would use something both easier for humans to read and more likely to be optimized by the compiler. You'd dispense with the loop entirely and just say:
printf("%s", name);
(Note that this requires name include the \0 character at the end of the string, upon which printf relies. Your name1 and name3 definitions, as written, do not allocate the necessary 8 bytes.)
If you were trying to do something tricky in your code that required one of the more verbose methods you posted, which method you chose would depend on exactly what tricky thing you were trying to do (which you would of course explain in code comments -- otherwise, you would look at your own code six months later and ask yourself, "What the heck was I doing here??"). In general, for plucking characters out of a string, name[i] is a more common idiom than *(name+i).
char name[] = "Madonah";
char* name = "Madonah";
When declared inside a function, the first option yields additional operations every time the function is called. This is because the contents of the string are copied from the RO data section into the stack every time the function is called.
In the second option, the compiler simply sets the variable to point to the address of that string in memory, which is constant throughout the execution of the program.
So unless you're planning to change the contents of the local array (not the original string - that one is read-only), you may opt for the second option.
Please note that all the details above are compiler-implementation dependent, and not dictated by the C-language standard.
can I know which one is easy to use [...]
Try sticking to use the indexing operator [].
One time your code gets more complex and you then notice that things are "more easy" to code using pointer arithmetical expressions.
This typically will be the case when you also start to use the address-of operator: &.
If for example you see your self in the need to code:
char s[] = "Modonah";
char * p = &s[2]; /* This gives you the address of the 'd'. */
you will soon notice that it's "easier" to write:
char * p = s + 2; /* This is the same as char * p = &s[2];. */
An array is just a variable that contains several values, each value has an index, you probably know that already.
Pointers are one of those things you dont need to know about until you realize you need to use them. Pointers are not variables themselves they are literally pointers to variables.
An example of how and why you might want to use a pointer.
You create a variable in one function which you want to use in another function.
You could pass your variable to the new function in the function header.
This effectively COPIES the values from the original variable to a new variable local to the new function. Changes made to it in the new function only change the new variable in the new function.
But what if you wanted changes made in the new function to change the original variable where it is in the first function ?
You use a pointer.
Instead of passing the actual variable to the new function, you pass a pointer to the variable. Now changes made to the variable in the new function are reflected in the original variable in the first function.
This is why in your own example using the pointer to the array and using the actual array while in the same function has identical results. Both of them are saying "change this array".

strcpy issue with char arrays in structs in C

So I'm working on a program to take in assembly code in a text file and produce the corresponding machine code. However, I'm running into an issue when I'm trying trying to assign values to the members of the AssemblyLine struct. What happens is that when ".fill" is the opcode, arg0 is concatenated to it, and there are also issues with arg0 if I assign value to arg0 first. It is important to note that this only happens when the opcode is ".fill". For example, if the opcode is "add" the values are what I intended for them to be.
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
struct AssemblyLine {
char opcode[5];
char arg0[7];
char arg1[7];
char arg2[7];
_Bool initialized;
};
struct Label {
char name[7];
int address;
_Bool initialized;
};
main()
{
struct AssemblyLine line;
strcpy(line.opcode, ".fill");
strcpy(line.arg0, "5");
printf("%s\n", line.opcode);
return 0;
}
The output for this program is:
.fill5
My intention is that the output would just be:
.fill
I'm really confused about what would be causing this. Sorry if the answer is really obvious, this is my first time working in C, though I have programmed in C++ before. I was at first thinking that there was no null terminating character, but the string is read fine until after I use the second strcpy. Is fill used as a key word for strcpy or something? I thought maybe it had to do with the '.' but that didn't affect anything when the opcode was ".lw".
Sorry that this post is so long! Thanks for any help!
Your array isn't big enough. ".fill" is six characters include the terminating null, but you only allocate memory for five with char opcode[5]. You need to make your array bigger.
The string ".fill" is 5 characters + 1 zero character long. That makes 6 characters.
But the array 'opcode' is only 5 characters long, so the trailing zero is written to 'arg0'.
After that, your copy "5" (2 characters with zero) to 'arg0'.
Because 'printf' prints until the trailing zero occurs, it reads out of the bounds of opcode.

Resources