关于在C中打印字符串数组的困惑

时间:2017-06-03 20:50:13

标签: c arrays pointers

这可能是一个初学者的问题,但它让我感到困惑。我知道在c中,数组本身就是指向数组第一个元素的指针。请考虑以下示例

char *words[LENGTH];
words[0] = "zero";
words[1] = "one";
words[2] = "two";
printf("%s\n",*words);

最终打印的内容是zero。但是,我的理解是words是指向words数组的第一个元素的指针,它是一个char指针=> words是指向char的指针。因此*words将成为char的指针。因此我希望在这里打印一个内存地址而不是实际的字符串。我在这里误解了什么?

6 个答案:

答案 0 :(得分:3)

  

我理解在c中,数组本身就是指向数组第一个元素的指针。

这是不正确的 - 在大多数情况下,表达式类型为" N元素数组T"将转换为"指向T"的类型的表达式,但数组对象本身不是指针。没有为指针留出存储空间作为数组对象的一部分。

字符串文字 "zero"具有char"类型" 5元素数组,而"one"和{{1}具有"two""的类型" 4元素数组; (因为字符串以零值字符结尾,所以需要N + 1个元素来存储N字符串。)

每个字符串文字都是一个数组表达式,但由于这些表达式不是char或一元sizeof运算符的操作数,并且因为它们不用于初始化字符数组,所以每个表达式都是< em>将转换为指针表达式,每个表达式的值是数组中第一个元素的地址。

  

因此我希望在这里打印一个内存地址而不是实际的字符串。我在这里误解了什么?

&转换说明符告诉%s打印从指定地址开始的字符序列,直到看到字符串终结符 - 这就是为什么您将printf视为输出而不是地址。要打印指针值,您可以使用zero转换说明符,如下所示:

%p

答案 1 :(得分:2)

你对printf所取得的成就的理解是正确的 - 正如你所写的,*words实际上是指向char的指针。 %s格式说明符用于打印字符串,因此它假定您传递的任何指针实际上是以'\0'字符结尾的字符数组 - 格式c用于存储字符串。有了这些信息,printf知道它应该只打印数组中的所有字符,直到它找到'\0' - 这正是它在这种情况下所做的。如果你想打印那个指针的地址,那么正确的格式说明符就是(如Stargateur的回答中提到的那样)%p

答案 2 :(得分:2)

由于@Stargateur回复你需要使用%p标志并使用(void *)。 请注意,它会显示第一个字符串的起始地址(&#39;零&#39;),下一个代码将遍历所有字符串并打印其地址(将3个字符串视为2D(二维) )具有不同长度的字符串数组。

#include <stdio.h>
#define LENGTH 3

int main(void)
{
    char *words[LENGTH];
    words[0] = "zero";
    words[1] = "one";
    words[2] = "two";

    int len = 0;
    while(len<(int)LENGTH)
    {
        printf("%s\n", words[len]);
        printf("%p\n", (void *)words[len]);
        len++;
    }
    printf("\n%p\n", (void *)*words); // prints the first address only (the 'zero' address)

    return 0;
}

答案 3 :(得分:1)

你很接近你是对的,c-string是一个指针,它包含字符串第一个字符的地址。 c-string不是字节而是地址。 printf标志%s期望这些字节的地址。所以你确实给了printf()一个地址,但你要求printf()显示c-string的值。所以“零”。您唯一的错误是您没有阅读printf()手册。

如果您想要地址,请尝试:

printf("%p\n", (void *)*words);

答案 4 :(得分:1)

app.directive('upload', ['$lhttp', '$http', '$interval', '$timeout', '$q', '$location', function ($lhttp, $http, $interval, $timeout, $q, $location) { return { templateUrl: '/.src/views/upload-widget.html', controller: function($scope, $element, $attrs) { // code ... // Define upload function vm.uploadFiles = ()=>{ // code ... // Create the payload for the upload request let formdata = new FormData(); formdata.append("salt", salt); // code ... // Create the upload request let request = $http({ method: 'POST', url: "/.src/php/upload.php", data: formdata, transformRequest: angular.identity, uploadEventHandlers: { progress: function(e) { vm.progress = Math.round((e.loaded/e.total)*100) + "%"; if (vm.progress === '100%') vm.get_server_progress(salt); } }, headers: {'Content-Type': undefined} }); // Create handler functions for success and errors request.then(function successCallback (response) { vm.server_progress = "100%"; vm.actually_loading = false; $timeout(()=>{ vm.loading = false }, 600); if (response.data.error.length) { vm.fail = true; vm.error_message = response.data.error; } if (!response.data.log.length) { vm.fail = true; vm.error_message = $scope.m.text.upload_error; } }, function errorCallback (response) { // code ... }); } // code ... // Create function for checking status of server side processing of the upload vm.get_server_progress = (salt)=>{ $http.get('/.src/php/status.php?salt='+salt+'&d='+Date.now()).success((data)=>{ vm.server_progress = data+"%"; re_get_progress_if(salt); }).error(()=>{ re_get_progress_if(salt); }); } function re_get_progress_if (salt) { ////////////////////////////////////// // THIS IS THE PROBLEMATIC $TIMEOUT:// if (vm.actually_loading) $timeout(vm.get_server_progress, 100, true, salt); } }, controllerAs: 'up' }; }]); 定义了一个char *数组,即char **。 char *words[LENGTH];等于*words,表示&#34;零&#34;。

创建这样的char *数组是不安全的。例如,以下代码编译正常,但其行为未定义。

words[0]

答案 5 :(得分:1)

*(乘法中不是*)很重要的上下文, 当在declearation中使用时,如char *words[LENGTH]中的单词成为char的指针数组。

就指针而言* 地址运算符的值时,它会将值存储在特定地址,而& 是地址运算符,给出变量的地址。

printf("%s\n",*words) // prints value at address to which word points 

,而

printf("%p\n",words) // prints address to which word points