Passing Variables through functions C - c

Hello im just beginning to learn C and i want to know why im getting a problem here..
i wish to pass a char pointer
char *temp;
into a function ie call to function
checkIfUniqueCourseNo(temp,k);
with a prototype
int checkIfUniqueCourseNo(char checkchar[4],int);
and a function header
int checkIfUniqueCourseNo(char checkchar[4], int k)
Im sure im doing something really stupid here but im not sure how to fix it :(
thanks in advance. ps my error is that checkchar[4] outputs a P...
Example---
temp = "123A"
checkIfUniqueCourseNo(temp,k);
int checkIfUniqueCourseNo(char checkchar[4], int k){
printf("CheckifUniqueCourse\n");
printf("Check Value = %c \n", checkchar);
return 0;
}
Output = Check Value = P

temp = "123A"
checkIfUniqueCourseNo(temp,k);
int checkIfUniqueCourseNo(char checkchar[4], int k){
printf("CheckifUniqueCourse\n");
printf("Check Value = %c \n", checkchar);
^^^^^^^^^
return 0;
}
If you're trying to print out the first character of checkchar, then you need to change this line to either
printf("Check Value = %c\n", *checkchar);
or
printf("Check Value = %c\n", checkchar[0]);
In the context of a function parameter declaration, T a[N] and T a[] are equivalent to T *a; a is declared as a pointer to T, not an array of T.
When you wrote
printf("Check Value = %c\n", checkchar);
you lied to printf; you said the argument is supposed to be of type char, but you passed a char *. Hence the bogus output.
If you want to print out the entire string "1234", then you need to change that line to
printf("Check value = %s\n", checkchar);
This time we use the %s conversion specifier to tell printf that checkchar points to a 0-terminated array of char (a.k.a. a string).

This is not at all clear. Are you assigning any value to temp? If so, what?
It would make more sense to have your prototype as:
int checkIfUniqueCourseNo(char* checkchar, int);
Since it's not at all clear where you got the 4 from.

It's been a while since I've done C, but I can see a few problems here, temp = "123A" actually requires an array for 5 characters (one of which is to include the '\0' string terminating character).
Secondly, the line printf("Check Value = %c \n", checkchar); seems to be trying to print a memory pointer as a character, change it to the following: printf("Check Value = %s \n", checkchar); and it will output each character in the array until it hits the terminating character.

There are a couple of things to look at here, you need to take a good look at the data you have, how it is represented and what you want to do with it.
Your course code appears to be a four character string, you should know that traditionally, strings in C also include an extra byte at the end with the value of zero (NUL) so that the many string functions that exist know that they have reached the end of the string.
In your case, your four digit code takes up five bytes of memory. So wont fit well passing it into your function.
If I were you, I would pass in a pointer like so:-
int checkIfUniqueCourseNo(char* coursecode, int k ) {
int rv = -1;
if ( coursecode == NULL ) return rv;
//...
I have no idea what K is for, do you?
Once you have your sequence of bytes inside your function you can save yourself alot of hastle later by doing some simple bounds checking on the data like so:
//...
if ( strlen(coursecode) > 4 ){
fprintf(stderr,"course code too long\n");
return rv;
}
if ( strlen(coursecode) < 4 ){
fprintf(stderr,"course code too short\n");
return rv;
}
//...
You can be sure you have a 4 character string now..

Related

C - Print ASCII Value for Each Character in a String

I'm new to C and I'm trying to write a program that prints the ASCII value for every letter in a name that the user enters. I attempted to store the letters in an array and try to print each ASCII value and letter of the name separately but, for some reason, it only prints the value of the first letter.
For example, if I write "Anna" it just prints 65 and not the values for the other letters in the name. I think it has something to do with my sizeof(name)/sizeof(char) part of the for loop, because when I print it separately, it only prints out 1.
I can't figure out how to fix it:
#include <stdio.h>
int main(){
int e;
char name[] = "";
printf("Enter a name : \n");
scanf("%c",&name);
for(int i = 0; i < (sizeof(name)/sizeof(char)); i++){
e = name[i];
printf("The ASCII value of the letter %c is : %d \n",name[i],e);
}
int n = (sizeof(name)/sizeof(char));
printf("%d", n);
}
Here's a corrected, annotated version:
#include <stdio.h>
#include <string.h>
int main() {
int e;
char name[100] = ""; // Allow for up to 100 characters
printf("Enter a name : \n");
// scanf("%c", &name); // %c reads a single character
scanf("%99s", name); // Use %s to read a string! %99s to limit input size!
// for (int i = 0; i < (sizeof(name) / sizeof(char)); i++) { // sizeof(name) / sizeof(char) is a fixed value!
size_t len = strlen(name); // Use this library function to get string length
for (size_t i = 0; i < len; i++) { // Saves calculating each time!
e = name[i];
printf("The ASCII value of the letter %c is : %d \n", name[i], e);
}
printf("\n Name length = %zu\n", strlen(name)); // Given length!
int n = (sizeof(name) / sizeof(char)); // As noted above, this will be ...
printf("%d", n); // ... a fixed value (100, as it stands).
return 0; // ALWAYS return an integer from main!
}
But also read the comments given in your question!
This is a rather long answer, feel free to skip to the end for the code example.
First of all, by initialising a char array with unspecified length, you are making that array have length 1 (it only contains the empty string). The key issue here is that arrays in C are fixed size, so name will not grow larger.
Second, the format specifier %c causes scanf to only ever read one byte. This means that even if you had made a larger array, you would only be reading one byte to it anyway.
The parameter you're giving to scanf is erroneous, but accidentally works - you're passing a pointer to an array when it expects a pointer to char. It works because the pointer to the array points at the first element of the array. Luckily this is an easy fix, an array of a type can be passed to a function expecting a pointer to that type - it is said to "decay" to a pointer. So you could just pass name instead.
As a result of these two actions, you now have a situation where name is of length 1, and you have read exactly one byte into it. The next issue is sizeof(name)/sizeof(char) - this will always equal 1 in your program. sizeof char is defined to always equal 1, so using it as a divisor causes no effect, and we already know sizeof name is equal to 1. This means your for loop will only ever read one byte from the array. For the exact same reason n is equal to 1. This is not erroneous per se, it's just probably not what you expected.
The solution to this can be done in a couple of ways, but I'll show one. First of all, you don't want to initialize name as you do, because it always creates an array of size 1. Instead you want to manually specify a larger size for the array, for instance 100 bytes (of which the last one will be dedicated to the terminating null byte).
char name[100];
/* You might want to zero out the array too by eg. using memset. It's not
necessary in this case, but arrays are allowed to contain anything unless
and until you replace their contents.
Parameters are target, byte to fill it with, and amount of bytes to fill */
memset(name, 0, sizeof(name));
Second, you don't necessarily want to use scanf at all if you're reading just a byte string from standard input instead of a more complex formatted string. You could eg. use fgets to read an entire line from standard input, though that also includes the newline character, which we'll have to strip.
/* The parameters are target to write to, bytes to write, and file to read from.
fgets writes a null terminator automatically after the string, so we will
read at most sizeof(name) - 1 bytes.
*/
fgets(name, sizeof(name), stdin);
Now you've read the name to memory. But the size of name the array hasn't changed, so if you used the rest of the code as is you would get a lot of messages saying The ASCII value of the letter is : 0. To get the meaningful length of the string, we'll use strlen.
NOTE: strlen is generally unsafe to use on arbitrary strings that might not be properly null-terminated as it will keep reading until it finds a zero byte, but we only get a portable bounds-checked version strnlen_s in C11. In this case we also know that the string is null-terminated, because fgets deals with that.
/* size_t is a large, unsigned integer type big enough to contain the
theoretical maximum size of an object, so size functions often return
size_t.
strlen counts the amount of bytes before the first null (0) byte */
size_t n = strlen(name);
Now that we have the length of the string, we can check if the last byte is the newline character, and remove it if so.
/* Assuming every line ends with a newline, we can simply zero out the last
byte if it's '\n' */
if (name[n - 1] == '\n') {
name[n - 1] = '\0';
/* The string is now 1 byte shorter, because we removed the newline.
We don't need to calculate strlen again, we can just do it manually. */
--n;
}
The loop looks quite similar, as it was mostly fine to begin with. Mostly, we want to avoid issues that can arise from comparing a signed int and an unsigned size_t, so we'll also make i be type size_t.
for (size_t i = 0; i < n; i++) {
int e = name[i];
printf("The ASCII value of the letter %c is : %d \n", name[i], e);
}
Putting it all together, we get
#include <stdio.h>
#include <string.h>
int main() {
char name[100];
memset(name, 0, sizeof(name));
printf("Enter a name : \n");
fgets(name, sizeof(name), stdin);
size_t n = strlen(name);
if (n > 0 && name[n - 1] == '\n') {
name[n - 1] = '\0';
--n;
}
for (size_t i = 0; i < n; i++){
int e = name[i];
printf("The ASCII value of the letter %c is : %d \n", name[i], e);
}
/* To correctly print a size_t, use %zu */
printf("%zu\n", n);
/* In C99 main implicitly returns 0 if you don't add a return value
yourself, but it's a good habit to remember to return from functions. */
return 0;
}
Which should work pretty much as expected.
Additional notes:
This code should be valid C99, but I believe it's not valid C89. If you need to write to the older standard, there are several things you need to do differently. Fortunately, your compiler should warn you about those issues if you tell it which standard you want to use. C99 is probably the default these days, but older code still exists.
It's a bit inflexible to be reading strings into fixed-size buffers like this, so in a real situation you might want to have a way of dynamically increasing the size of the buffer as necessary. This will probably require you to use C's manual memory management functionality like malloc and realloc, which aren't particularly difficult but take greater care to avoid issues like memory leaks.
It's not guaranteed the strings you're reading are in any specific encoding, and C strings aren't really ideal for handling text that isn't encoded in a single-byte encoding. There is support for "wide character strings" but probably more often you'll be handling char strings containing UTF-8 where a single codepoint might be multiple bytes, and might not even represent an individual letter as such. In a more general-purpose program, you should keep this in mind.
If we need write a code to get ASCII values of all elements in a string, then we need to use "%d" instead of "%c". By doing this %d takes the corresponding ascii value of the following character.
If we need to only print the ascii value of each character in the string. Then this code will work:
#include <stdio.h>
char str[100];
int x;
int main(){
scanf("%s",str);
for(x=0;str[x]!='\0';x++){
printf("%d\n",str[x]);
}
}
To store all corresponding ASCII value of character in a new variable, we need to declare an integer variable and assign it to character. By this way the integer variable stores ascii value of character. The code is:
#include <stdio.h>
char str[100];
int x,ascii;
int main(){
scanf("%s",str);
for(x=0;str[x]!='\0';x++){
ascii=str[x];
printf("%d\n",ascii);
}
}
I hope this answer helped you.....😊

Pointers and char arrays from strings

Hi I have been reading for hours and still can't grasp the conversions between
{
char i ="adf";
char foo[];
char bar[256];
}
and adding * and & makes it more confusing
I have some code that is working.
int TX_SEND(char send[])
{
unsigned char *p_tx_buffer;
p_tx_buffer = &send[0];
strcat(send, "\r");
// Write to the port
int n = write(fd,&send[0],3);
if (n < 0) {
perror("Write failed - ");
return -1;
}
return(0);
}
code is working but I need help with 2 parts.
I want to be able to run this function like kind of like printf IE TX_SEND("AT+CGMSD=STUFF"); but I am stuck
but before hand I do this alot.
char txsend[] = "at";
TX_SEND(txsend);
Also inside my TX_WRITE() I am using write(fd,&send[0],3), but it is hardcoded to send 3 bytes from send[]. I want this to be dynamic so I can just send strings at any length (realistically they will be less than 300 ASCII chars always). I tried to do something with a pointer in there but gave up (*p_tx_buffer was my beginning attempt).
i think you want
int TX_SEND(char *send)
{
int n = write(fd,send,strlen(send));
if (n < 0) {
perror("Write failed - ");
return -1;
}
return(0);
}
you cannot tack on \n to send with strcat. I would add it in the calling function, or declare an intermediate buffer and sprintf to it
like this
int TX_SEND(char *send)
{
char buff[50]; // i dont know a good max size
snprintf(buff, sizeof(buff), "%s\n", send);
int n = write(fd,buff,strlen(buff));
if (n < 0) {
perror("Write failed - ");
return -1;
}
return(0);
}
I'm not going to go through your code line-by-line, but I urge you to focus on these facts:
chars are chars and strings are strings, and never the twain shall meet. (They're totally different.)
'x' is a character constant.
"x" is a string constant.
A string is an array of characters (terminated by '\0').
When you mention an array (including a string) in a context where you need its value, what you get is a pointer to the array's first element.
When you put a & in front of something, what you get is a pointer to that something.
When you put a * in front of a pointer, what you get is the thing that the pointer points to.
Putting this together, we could write
char str[] = "xyz";
char *p = str; /* per rule 5, this is fine, and p gets a pointer to str's first element */
char c = *p; /* per rule 7, c gets the first character of str, which is 'x' */
printf("%c\n", c);
If you're just starting with C, you may not have come across rule 5 yet. It will probably surprise you at first. Learn it well, though: you'll never understand arrays and pointers in C without it.

problems with c pointer strings

:)
I'm trying to beat string pointers in c, so I write this code but I didn't get the result that I expected.
I'm creating a string variable, and I want to pass it to a function that check if the string lenght is bigger than 10.
This is the code:
#include <stdio.h>
#include <stdlib.h>
#include <string.h>
#include <stdbool.h>
bool is_bigger_than_10(char *);
int main()
{
char *string1 = "";
int i = 0;
printf("Initial string: %s\n",&string1);
printf("Size is: %d\n",strlen(&string1));
printf("Give me one string: ");
scanf("%[^\t\n]s",&string1); //This scan allows me to enter string with spaces
printf("You write: %s\n", &string1);
printf("Size is: %d\n",strlen(&string1));
printf("String character by character:\n");
for(i = 0; i < strlen(&string1) ; i++)
{
printf("%c ",&string1[i]);
}
printf("\nNow let's check if it's bigger than 10\n");
printf("Answer is: %d",is_bigger_than_10(&string1));
return 0;
}
bool is_bigger_than_10(char *textx)
{
printf("%s --> %d > %d\n",&textx, strlen(&textx),10);
if(strlen(&textx) > 10)
{
return true;
}
else
{
return false;
}
}
The expected output should be:
Initial string:
Size is 0:
Give me one string: axel
You write: axel
String character by character:
a x e l
Now let's check if it's bigger than 10
a x e l --> 4 > 10
Answer is: 0
If yoy run that code and enter axel as the input string you will get this:
Initial string: $0#
Size is 3:
Give me one string: axel
You write: axel
String character by character: a b c d e
a x e l
Now let's check if it's bigger than 10
' --> 3 > 10
Answer is: 0
It's kind of weird, could some one help me to correct this code?
There are two things going on here:
First, your char pointer needs to point somewhere. With the line
char *string1 = "";
you create a pointer to a string literal, which you can't write to. (Obviously you can, given your output, but you just got lucky on a system that allows it.) Create a character buffer instead:
char string1[200] = "";
and ideally enforce the constant buffer limit when you read the string.
Second, you don't need all these &s. The & is not a magic marker that you have to prepend to all your arguments.
The & takes the address of a variable and passes it as a pointer. You need that when the called function needs to change the variable via the pointer. Printing doesn't need to change anything, so unless you want to print the address of a variable with %p, you shouldn't pass addresses. (In the special case of your program, you can just remove all ampersands with search and replace.)
When scanning, you need to change variables if you convert input to numbers or if you scan a char. The exception is when you scan strings with %sor %[...]: Here, you pass a char buffer (as a pointer to its first elements) and the function then fills that buffer.
The problem with scanf and printf is that the arguments after the format string are variadic, which means they will accept any arguments without type checking. The good thing is that most compilers can tell whether a format string matches the arguments and will issue warnings, it you enable them. Do yourself a favour and do that.
(Warnings will also tell you that you have type mismatches in functions where the type of the argument is known, such as your is_bigger_than_10.)

Append to C String Based on User Input

I would like to receive an integer x via user input, and return a string with length x in '#'s.
i.e.
x = 4
⇒ "####"
Is a simple solution possible, along the lines of:
printf( "%c * x = %c", hash, x, hash*x);
Currently, my online findings have me creating an iterative program:
#include <stdio.h>
#include <string.h>
//function creates xhash with width '#' characters
void append( char* xhash, char hash, int x )
{
int i = 0;
for ( i = 0; i < x; i++ ) { xhash[i] = hash; }
xhash[x] = '\0';
}
int main ( void )
{
int x = 0;
scanf( "%d", &x );
char xhash[250] = "";
char hash = "#";
append( xhash, hash, x );
printf( "%c", xhash );
return 0;
}
And this gives me a strange design: â–’
I find C strings very confusing, coming from Python where I would use
str.append(i)
or
str = "#" * x
C does not have a full-fledged string data type. "C strings" are just contiguous sequences if char values, terminated by a character with value 0 (which can be spelled '\0').
Very important to your question, though, is that (1) char is an integer data type, (2) different delimiters are used for string literals than for (single-)char literals, and (3) string literals evaluate to pointers to the first character of a C string.
Thus, this ...
char hash = "#";
... attempts to store a pointer in hash, probably resulting in the last byte of the pointer value. Instead, you want this:
char hash = '#';
Moreover, to print a C string via one of the printf()-family functions, you want to use edit descriptor %s:
printf("%s", xhash);
Descriptor %c is for outputting a single character.
A string in C is just an array of bytes followed by a zero byte. That is all that they are.
For a function that creates a string you have two options. You can have the caller pass in a pointer to an array (and the array size, if you're smart) and the function fills it in. The second option is to malloc inside your function and return the pointer to the caller.
Another thing to remember is the standard C library. Your append function is essentially memset followed by setting a zero at the end. You should just call memset instead of doing your own loop.
And I think you are getting weird output because the printf format for a string is %s not %c. The %c format is for a single character.
Finally if you are unfamiliar with C programming you should be compiling will all warnings turned on. The compiler warnings would have told you about the bad printf format string and the invalid char assignment.

What happens when using scanf("%d", &c) while c is a char?

the code is like this:
char c;
scanf("%d", &c);
inputting 3...
My guess is that when 3 is inputted, it is as type int;
and then type-demoted to char and assigned to c;
I print the value of c in specifier %d yielding 3, seems to be as expected;
but printing the value of c with specifier %c yields --a blank-- on the terminal;this is one question...(1);
to test more I furthermore declare a variable ch with type char and initialized it like this:
char ch = 1;
and the test is like this:
(i&j)? printf("yes") : printf("no");
and the result is "no"
I print out the value of i&j, and it is 0
but 1&3 should be 1? this is another question....(2);
my question is (1) and (2)
You're actually invoking undefined behavior doing that.
By using the format string %d, you're telling scanf to expect an int* as a parameter and you're passing it a pointer to a single character. Remember that scanf has no further type information on what you're passing it than what you're putting in the format string.
This will result in scanf attempting to write an int sized value to memory at an address that points to a char sized reservation, potentially (and for most architectures) writing out of bounds.
After invoking UB, all bets are off on your further calculations.
Suppose that scanf() were not a varargs-function, but a plain ordinary function taking a pointer-to-int as the 2nd argument:
int noscanf(char *format, int *ptr)
{
*ptr = 42;
return 1;
}
int main(void)
{
char ch;
int rc;
// This should *at least* give a warning ...
rc = noscanf("Haha!" , &ch);
return 0;
}
Now, scanf() is a varargs function. The only way for scanf() to determine the type of the (pointer) arguments is by inspecting the format string. And a %d means : the next argument is supposed to be a pointer to int. So scanf can happily write sizeof(int) bytes to *ptr.
I can't see a variable jthere. So i&j will be 0. And yes, if i == 1 and j == 3 then i & j == 1.
(i&j)? printf("yes") : printf("no");
statement gives the output yes,for i=1 and j=3.
And for (1) question ASCII 3 is for STX char which is not printable.

Resources